Hi everyone. Sorry about this post, however I’m not really a developer, and this is my first rodeo with Edge. I’ve been working on creating a driver for the Zipato Micromodule Motor Controller, effectively a clone of the iBlinds Window Treatment driver. I managed to connect the device with Edge, however the code isn’t working.
Said code is this:
local capabilities = require "st.capabilities"
--- @type st.zwave.CommandClass
local cc = require "st.zwave.CommandClass"
--- @type st.zwave.CommandClass.SwitchMultilevel
local SwitchMultilevel = (require "st.zwave.CommandClass.SwitchMultilevel")({ version=3 })
local ZIPATO_MICROMODULE_MOTOR_CONTROLLER_FINGERPRINTS = {
{mfr = 0x013C, prod = 0x0001, model = 0x0015}, -- Zipato Window Treatment
}
--- Determine whether the passed device is iblinds window treatment v3
---
--- @param driver st.zwave.Driver
--- @param device st.zwave.Device
--- @return boolean true if the device is iblinds window treatment, else false
local function can_handle_iblinds_window_treatment_v3(opts, driver, device, ...)
for _, fingerprint in ipairs(ZIPATO_MICROMODULE_MOTOR_CONTROLLER_FINGERPRINTS) do
if device:id_match(fingerprint.mfr, fingerprint.prod, fingerprint.model) then
return true
end
end
return false
end
local capability_handlers = {}
function capability_handlers.close(driver, device)
device:emit_event(capabilities.windowShade.windowShade.closed())
device:emit_event(capabilities.windowShadeLevel.shadeLevel(0))
device:send(SwitchMultilevel:Set({value = 0}))
end
local function set_shade_level_helper(driver, device, value)
local value = math.max(math.min(value, 99), 0)
if value == 0 or value == 99 then
device:emit_event(capabilities.windowShade.windowShade.closed())
elseif value == (device.preferences.defaultOnValue or 50) then
device:emit_event(capabilities.windowShade.windowShade.open())
else
device:emit_event(capabilities.windowShade.windowShade.partially_open())
end
device:emit_event(capabilities.windowShadeLevel.shadeLevel(value))
device:send(SwitchMultilevel:Set({value = value}))
end
function capability_handlers.set_shade_level(driver, device, command)
set_shade_level_helper(driver, device, command.args.shadeLevel)
end
function capability_handlers.preset_position(driver, device)
set_shade_level_helper(driver, device, device.preferences.defaultOnValue or 50)
end
local zipato_micromodule_motor_controller = {
capability_handlers = {
[capabilities.windowShade.ID] = {
[capabilities.windowShade.commands.close.NAME] = capability_handlers.close
},
[capabilities.windowShadeLevel.ID] = {
[capabilities.windowShadeLevel.commands.setShadeLevel.NAME] = capability_handlers.set_shade_level
},
[capabilities.windowShadePreset.ID] = {
[capabilities.windowShadePreset.commands.presetPosition.NAME] = capability_handlers.preset_position
}
},
NAME = "Zipato Micromodule Motor Controller",
can_handle = can_handle_zipato_micromodule_motor_controller
}
return zipato_micromodule_motor_controller
Along with this, I have also made a fingerprints.yml
file, being this:
zwaveManufacturer:
- id: "zipato/micromodulemotorcontroller"
deviceLabel: Zipato Micromodule Motor Controller
manufacturerId: 0x013C
productType: 0x0001
productId: 0x0015
deviceProfileName: zipato-micromodule-motor-controller
In the src
folder, my preferences.lua
look this this:
local devices = {
ZIPATO_WINDOW_TREATMENT = {
MATCHING_MATRIX = {
mfrs = {0x013C},
product_types = {0x0001},
product_ids = 0x0015
},
PARAMETERS = {
wattMeterReportPeriod = {parameter_number = 1, size = 2}
kwhMeterReportPeriod = {parameter_number = 2, size = 2}
thresholdOfCurrentForLoadCaution = {parameter_number = 3, size = 2}
thresholdOfKwhForLoadCaution = {parameter_number = 4, size = 2}
externalSwitchType = {parameter_number = 5, size = 1}
levelReportMode = {parameter_number = 6, size = 1}
}
}
}
local preferences = {}
preferences.get_device_parameters = function(zw_device)
for _, device in pairs(devices) do
if zw_device:id_match(
device.MATCHING_MATRIX.mfrs,
device.MATCHING_MATRIX.product_types,
device.MATCHING_MATRIX.product_ids) then
return device.PARAMETERS
end
end
return nil
end
preferences.to_numeric_value = function(new_value)
local numeric = tonumber(new_value)
if numeric == nil then -- in case the value is boolean
numeric = new_value and 1 or 0
end
return numeric
end
return preferences
And my init.lua
looks like this:
local capabilities = require "st.capabilities"
--- @type st.zwave.defaults
local defaults = require "st.zwave.defaults"
--- @type st.zwave.Driver
local ZwaveDriver = require "st.zwave.driver"
--- @type st.zwave.CommandClass.Configuration
local Configuration = (require "st.zwave.CommandClass.Configuration")({ version=4 })
local preferencesMap = require "preferences"
local function added_handler(self, device)
device:emit_event(capabilities.windowShade.supportedWindowShadeCommands({"open", "close", "pause"}))
end
--- Handle preference changes
---
--- @param driver st.zwave.Driver
--- @param device st.zwave.Device
--- @param event table
--- @param args
local function info_changed(driver, device, event, args)
local preferences = preferencesMap.get_device_parameters(device)
if preferences then
for id, value in pairs(device.preferences) do
if preferences[id] and args.old_st_store.preferences[id] ~= value then
local new_parameter_value = preferencesMap.to_numeric_value(device.preferences[id])
device:send(Configuration:Set({parameter_number = preferences[id].parameter_number, size = preferences[id].size, configuration_value = new_parameter_value}))
end
end
end
end
--------------------------------------------------------------------------------------------
-- Register message handlers and run driver
--------------------------------------------------------------------------------------------
local driver_template = {
supported_capabilities = {
capabilities.windowShade,
capabilities.windowShadeLevel,
capabilities.windowShadePreset,
capabilities.statelessCurtainPowerButton,
capabilities.battery
},
lifecycle_handlers = {
added = added_handler,
infoChanged = info_changed
},
sub_drivers = {
require("zipato-micromodule-motor-controller")
}
}
defaults.register_for_default_handlers(driver_template, driver_template.supported_capabilities)
--- @type st.zwave.Driver
local window_treatment = ZwaveDriver("zwave_window_treatment", driver_template)
window_treatment:run()
Lastly, I have this profile, which shows in the app, but doesn’t really change anything:
name: zipato-micromodule-motor-controller
components:
- id: main
capabilities:
- id: windowShade
version: 1
- id: windowShadeLevel
version: 1
- id: windowShadePreset
version: 1
- id: refresh
version: 1
categories:
- name: Blind
preferences:
- name: "wattMeterReportPeriod"
title: "Watt Meter Report Period"
description: "If the setting is configured for 1 hour (set value =720), the Micromodule will report its instant power consumption every 1 hour to the node of corresponding Group."
required: true
preferenceType: integer
definition:
minimum: 1
maximum: 32767
default: 720
- name: "kwhMeterReportPeriod"
title: "KWH Meter Report Period"
description: "If the setting is configured for 1 hour (set value =6), the Micromodule will report its Accumulated Power Consumption (KW/h) every 1 hour to the node of corresponding Group."
required: true
preferenceType: integer
definition:
minimum: 1
maximum: 32767
default: 6
- name: "thresholdOfCurrent"
title: "Threshold of curr. for Load Caution"
description: "This is a warning when the wattage of load exceeds the preset threshold value, If the setting value is 500, when the load current over this value, Micromodule will send current meter report command to the node of corresponding Group."
required: true
preferenceType: integer
definition:
minimum: 10
maximum: 500
default: 500
- name: "thresholdOfKwh"
title: "Threshold of KWH for Load Caution"
description: "This is a warning when the KWh is over the preset threshold value, If the setting value is 10000, when the Accumulated Power Consumption of Relay1/2 is over this value, Micromodule will send KWh Meter Report command to the node of corresponding Group, min. value is 1 and def. value is 10000."
required: true
preferenceType: integer
definition:
minimum: 1
maximum: 10000
default: 10000
- name: "externalSwitchType"
title: "External switch type"
description: "One Push Button: When the configuration setting is One Push Button, only S1 input will be valid. Two Push Button: If this setting is configured as Two Push Button, S1 and S2 input will be valid, but will not accept pressing S1 and S2 at the same time."
required: true
preferenceType: enumeration
definition:
options:
0: "One Push button"
1: "Two Push button"
default: 1
- name: "levelReportMode"
title: "Level report mode"
description: "Mode 1: In 5 secs period after controlled by a moving command, it will report the destination level when received command, otherwise it will report the actual level of the shutter when received command. Mode 2: Whenever the shutter moves past a 10 percent level, it will auto report the level."
required: true
preferenceType: enumeration
definition:
options:
0: "Report destination level in 5s"
1: "Report 10% level while running"
default: 1
For the sake of completion, I can say that the device binds well with the driver automatically during scanning for a new device. My parameter show in settings. However, the device remains with status “Checking…” and I never get to see the level of the blind. Moreover, Open and Close (and obviously Pause) buttons do not work.
I assumed that using one of the Lua drivers I found ready-made would make sense, since these types of Blind Controllers worked perfectly well using the old stock DTH for Z-Wave Window Shade. If anyone could help me out here that would be great. Thank you for your continued help and assistance.