[ST Edge] Attempting to make a driver for the Zipato Micromodule Motor Controller (Z-wave)

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.

This line in your subdriver:

Needs to be calling your can handle function:

Thank you @philh30 - I realised that error soon after posting the above thread, and had already fixed it - but to no avail. Driver still not working.

Perhaps I should not have based it off of the iBlinds driver - indeed since it was using the stock Groovy DTH, my thinking was it should be based on a basic driver without any extensions, but I couldn’t find a way to do this.

Well that would have been the easy fix.

Have you tried rebooting your hub since installing your driver? Usually not necessary but could help.

What do you see in the detail view of the device in the app? Do you see individual capabilities or a single “Connected” or “Checking” line? If individual capabilities with a broken cloud, the issue is likely that capabilities haven’t been set to an initial value yet.

Is logcat producing any logs? Try swiping down on detail view to trigger a refresh command, and also try interacting with the physical device (assuming it has open/close controls on it). If no logs, I’d guess your driver is crashing.

Does the device display properly and work on the web interface at my.smartthings.com?

1 Like

I think now that the MCOHome switch devices, my biggest headache, are behind me, I guess it is time for me to tackle the remaining issues, and at the top of those is this one with the blinds.

So, first and foremost, let me try to re-include the excluded blind and see what happens and whether there has been any improvement (though, frankly, I think not).

Tried this - it did not work at the time.

I saw the device as connected, but the Open/Close/Pause buttons do not work, and there isn’t even even slider, if I recall correctly. I will have to re-include to be 100% sure.

I didn’t know how to view logging at the time, so I am not sure, will let you know after I re-include, possibly later today, possibly tomorrow.

The above is true with or without my modified driver. It is true also with the Zwave Window Treatment driver of ST.

so perhaps, instead of building a driver, I should be making my point with ST. This device worked very well with a custom DTH. I never selected a DTH for these devices, I just included them, and they worked. They were pre-calibrated from an old (previous) installation, sure, and perhaps in a couple of cases I needed to re-calibrate the device, and I did use the “Zwave Tweaker 2” to set one important parameter, but I never assigned a custom DTH for these (blind) motor controllers. Now, suddenly, I find that the fingerprint has not been included in ST’s Zwave Window Treatment Edge driver… My assumption above was that just including the fingerprint and parameters in the driver, and pushing it on my own channel - would work, but clearly that is an easy way out. What I am saying now is: Should I not be able to ask ST to fix this? To my understanding, ST have promised that anything working with a stock driver will continue to work. However, it appears that in the case of the Zipato Micromodule Motor Controller AND the Philio PAN08 In-Wall Roller Shutter Controller (same device, different branding), this is not the case.

From what I’ve found searching around regarding this device, I don’t see anything unique about the way it works. I’d expect the zwave-switch driver to work with no modifications (it should match the generic fingerprint, so it won’t join to Edge with that driver, and it would be represented as a dimmer). The zwave-window-treatment driver lacks a fingerprint to match, but also should work. Your first step should be to use logcat to confirm whether you’re getting any z-wave commands from the device, then move on to figuring out whether the driver is handling them properly.

1 Like

Thanks - will try to carry out some troubleshooting per your advice and let you know.

1 Like

I am looking for custom driver for zwave lock. The smartThings one isn’t working at all. Any idea if anyone made a customs edge for z-wave lock?