From ac36f84b8bfe4ab16cfa1c31e4ff5f13e4a48450 Mon Sep 17 00:00:00 2001 From: InovelliUSA Date: Fri, 12 Dec 2025 19:15:35 -0700 Subject: [PATCH 1/2] Inovelli - adding vzw31 red series dimmer switch --- .../SmartThings/zwave-switch/fingerprints.yml | 6 + .../profiles/inovelli-dimmer-vzw31-sn.yml | 284 ++++++++++++++++++ .../zwave-switch/src/inovelli/can_handle.lua | 3 +- .../zwave-switch/src/inovelli/sub_drivers.lua | 1 + .../src/inovelli/vzw31-sn/can_handle.lua | 19 ++ .../src/inovelli/vzw31-sn/init.lua | 67 +++++ .../zwave-switch/src/preferences.lua | 27 ++ 7 files changed, 406 insertions(+), 1 deletion(-) create mode 100644 drivers/SmartThings/zwave-switch/profiles/inovelli-dimmer-vzw31-sn.yml create mode 100644 drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/can_handle.lua create mode 100644 drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/init.lua diff --git a/drivers/SmartThings/zwave-switch/fingerprints.yml b/drivers/SmartThings/zwave-switch/fingerprints.yml index d90a0c6b76..2d5d8488db 100644 --- a/drivers/SmartThings/zwave-switch/fingerprints.yml +++ b/drivers/SmartThings/zwave-switch/fingerprints.yml @@ -56,6 +56,12 @@ zwaveManufacturer: productType: 0x0003 productId: 0x0001 deviceProfileName: inovelli-dimmer + - id: "Inovelli/VZW31-SN" + deviceLabel: Inovelli Dimmer Red Series + manufacturerId: 0x031E + productType: 0x0015 + productId: 0x0001 + deviceProfileName: inovelli-dimmer-vzw31-sn - id: "Inovelli/VZW32-SN" deviceLabel: Inovelli mmWave Dimmer Red Series manufacturerId: 0x031E diff --git a/drivers/SmartThings/zwave-switch/profiles/inovelli-dimmer-vzw31-sn.yml b/drivers/SmartThings/zwave-switch/profiles/inovelli-dimmer-vzw31-sn.yml new file mode 100644 index 0000000000..e2da4a3239 --- /dev/null +++ b/drivers/SmartThings/zwave-switch/profiles/inovelli-dimmer-vzw31-sn.yml @@ -0,0 +1,284 @@ +name: inovelli-dimmer-vzw31-sn +components: +- id: main + capabilities: + - id: switch + version: 1 + - id: switchLevel + version: 1 + - id: powerMeter + version: 1 + - id: energyMeter + version: 1 + - id: refresh + version: 1 + categories: + - name: Switch +- id: button1 + label: Down Button + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController +- id: button2 + label: Up Button + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController +- id: button3 + label: Config Button + capabilities: + - id: button + version: 1 + categories: + - name: RemoteController +preferences: + - name: "notificationChild" + title: "Add Child Device - Notification" + description: "Create Separate Child Device for Notification Control" + required: false + preferenceType: boolean + definition: + default: false + - name: "notificationType" + title: "Notification Effect" + description: "This is the notification effect used by the notification child device" + required: false + preferenceType: enumeration + definition: + options: + "255": "Clear" + "1": "Solid" + "2": "Fast Blink" + "3": "Slow Blink" + "4": "Pulse" + "5": "Chase" + "6": "Open/Close" + "7": "Small-to-Big" + "8": "Aurora" + "9": "Slow Falling" + "10": "Medium Falling" + "11": "Fast Falling" + "12": "Slow Rising" + "13": "Medium Rising" + "14": "Fast Rising" + "15": "Medium Blink" + "16": "Slow Chase" + "17": "Fast Chase" + "18": "Fast Siren" + "19": "Slow Siren" + default: 1 + - name: "parameter158" + title: "158. Switch Mode" + description: "Use as a Dimmer or an On/Off switch" + required: true + preferenceType: enumeration + definition: + options: + "0": "Dimmer (default)" + "1": "On/Off" + default: 0 + - name: "parameter52" + title: "52. Smart Bulb Mode" + description: "For use with Smart Bulbs that need constant power and are controlled via commands rather than power. Smart Bulb Mode does not work in Dumb 3-Way Switch mode." + required: true + preferenceType: enumeration + definition: + options: + "0": "Disabled (default)" + "1": "Smart Bulb Mode" + default: 0 + - name: "parameter22" + title: "22. Aux Switch Type" + description: "Set the Aux switch type. Smart Bulb Mode does not work in Dumb 3-Way Switch mode." + required: true + preferenceType: enumeration + definition: + options: + "0": "None (default)" + "1": "3-Way Dumb Switch" + "2": "3-Way Aux Switch" + "3": "Single Pole Full Sine Wave" + default: 0 + - name: "parameter1" + title: "1. Dimming Speed (Remote)" + description: "This changes the speed that the light dims up when controlled from the hub. A setting of '0' turns the light immediately on. Increasing the value slows down the transition speed. Value is multiplied by 100ms. + Default=25 (2500ms or 2.5s)" + required: false + preferenceType: number + definition: + minimum: 0 + maximum: 255 + default: 25 + - name: "parameter2" + title: "2. Dimming Speed (Local)" + description: "This changes the speed that the light dims up when controlled at the switch. A setting of '0' turns the light immediately on. Increasing the value slows down the transition speed. Value is multiplied by 100ms. + (i.e 25 = 2500ms or 2.5s) Default=255 (Sync with parameter 1)" + required: false + preferenceType: number + definition: + minimum: 0 + maximum: 255 + default: 255 + - name: "parameter3" + title: "3. Ramp Rate (Remote)" + description: "This changes the speed that the light turns on when controlled from the hub. A setting of '0' turns the light immediately on. Increasing the value slows down the transition speed. Value is multiplied by 100ms. + (i.e 25 = 2500ms or 2.5s) Default=255 (Sync with parameter 1)" + required: false + preferenceType: number + definition: + minimum: 0 + maximum: 255 + default: 255 + - name: "parameter4" + title: "4. Ramp Rate (Local)" + description: "This changes the speed that the light turns on when controlled at the switch. A setting of '0' turns the light immediately on. Increasing the value slows down the transition speed. Value is multiplied by 100ms. + (i.e 25 = 2500ms or 2.5s) Default=255 (Sync with parameter 3)" + required: false + preferenceType: number + definition: + minimum: 0 + maximum: 255 + default: 255 + - name: "parameter9" + title: "9. Minimum Level" + description: "The minimum level that the light can be dimmed. Useful when the user has a light that does not turn on or flickers at a lower level." + required: true + preferenceType: number + definition: + minimum: 1 + maximum: 99 + default: 1 + - name: "parameter10" + title: "10. Maximum Level" + description: "The maximum level that the light can be dimmed. Useful when the user wants to limit the maximum brighness." + required: true + preferenceType: number + definition: + minimum: 2 + maximum: 100 + default: 100 + - name: "parameter15" + title: "15. Level After Power Restored" + description: "The level the switch will return to when power is restored after power failure. + 0=Off + 1-100=Set Level + 101=Use previous level." + required: true + preferenceType: number + definition: + minimum: 0 + maximum: 101 + default: 101 + - name: "parameter18" + title: "18. Active Power Reports" + description: "Power level change that will result in a new power report being sent. + 0 = Disabled + 1-32767 = 0.1W-3276.7W." + required: true + preferenceType: number + definition: + minimum: 0 + maximum: 32767 + default: 100 + - name: "parameter19" + title: "19. Periodic Power & Energy Reports" + description: "Time period between consecutive power & energy reports being sent (in seconds). The timer is reset after each report is sent." + required: true + preferenceType: number + definition: + minimum: 0 + maximum: 32767 + default: 3600 + - name: "parameter20" + title: "20. Active Energy Reports" + description: "Energy level change that will result in a new energy report being sent. + 0 = Disabled + 1-32767 = 0.01kWh-327.67kWh." + required: true + preferenceType: number + definition: + minimum: 0 + maximum: 32767 + default: 100 + - name: "parameter50" + title: "50. Button Press Delay" + description: "Adjust the delay used in scene control. 0=no delay (disables multi-tap scenes), 1=100ms, 2=200ms, 3=300ms, etc." + required: true + preferenceType: enumeration + definition: + options: + "0": "0ms" + "1": "100ms" + "2": "200ms" + "3": "300ms" + "4": "400ms" + "5": "500ms (default)" + "6": "600ms" + "7": "700ms" + "8": "800ms" + "9": "900ms" + default: 5 + - name: "parameter95" + title: "95. LED Indicator Color (w/On)" + description: "Set the color of the Full LED Indicator when the load is on." + required: true + preferenceType: enumeration + definition: + options: + "0": "Red" + "7": "Orange" + "28": "Lemon" + "64": "Lime" + "85": "Green" + "106": "Teal" + "127": "Cyan" + "148": "Aqua" + "170": "Blue (default)" + "190": "Violet" + "212": "Magenta" + "234": "Pink" + "255": "White" + default: 170 + - name: "parameter96" + title: "96. LED Indicator Color (w/Off)" + description: "Set the color of the Full LED Indicator when the load is off." + required: true + preferenceType: enumeration + definition: + options: + "0": "Red" + "7": "Orange" + "28": "Lemon" + "64": "Lime" + "85": "Green" + "106": "Teal" + "127": "Cyan" + "148": "Aqua" + "170": "Blue (default)" + "190": "Violet" + "212": "Magenta" + "234": "Pink" + "255": "White" + default: 170 + - name: "parameter97" + title: "97. LED Indicator Intensity (w/On)" + description: "Set the intensity of the Full LED Indicator when the load is on." + required: true + preferenceType: number + definition: + minimum: 0 + maximum: 100 + default: 50 + - name: "parameter98" + title: "98. LED Indicator Intensity (w/Off)" + description: "Set the intensity of the Full LED Indicator when the load is off." + required: true + preferenceType: number + definition: + minimum: 0 + maximum: 100 + default: 5 \ No newline at end of file diff --git a/drivers/SmartThings/zwave-switch/src/inovelli/can_handle.lua b/drivers/SmartThings/zwave-switch/src/inovelli/can_handle.lua index 7c0f6be77b..c8ba7ac681 100644 --- a/drivers/SmartThings/zwave-switch/src/inovelli/can_handle.lua +++ b/drivers/SmartThings/zwave-switch/src/inovelli/can_handle.lua @@ -3,6 +3,7 @@ local INOVELLI_FINGERPRINTS = { { mfr = 0x031E, prod = 0x0017, model = 0x0001 }, -- Inovelli VZW32-SN + { mfr = 0x031E, prod = 0x0015, model = 0x0001 }, -- Inovelli VZW31-SN { mfr = 0x031E, prod = 0x0001, model = 0x0001 }, -- Inovelli LZW31SN { mfr = 0x031E, prod = 0x0003, model = 0x0001 }, -- Inovelli LZW31 } @@ -17,4 +18,4 @@ local function can_handle_inovelli(opts, driver, device, ...) return false end -return can_handle_inovelli +return can_handle_inovelli \ No newline at end of file diff --git a/drivers/SmartThings/zwave-switch/src/inovelli/sub_drivers.lua b/drivers/SmartThings/zwave-switch/src/inovelli/sub_drivers.lua index e182120ece..2fdea81379 100644 --- a/drivers/SmartThings/zwave-switch/src/inovelli/sub_drivers.lua +++ b/drivers/SmartThings/zwave-switch/src/inovelli/sub_drivers.lua @@ -5,5 +5,6 @@ local lazy_load = require "lazy_load_subdriver" return { lazy_load("inovelli.lzw31-sn"), + lazy_load("inovelli.vzw31-sn"), lazy_load("inovelli.vzw32-sn") } diff --git a/drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/can_handle.lua b/drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/can_handle.lua new file mode 100644 index 0000000000..2446c06dde --- /dev/null +++ b/drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/can_handle.lua @@ -0,0 +1,19 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local INOVELLI_MANUFACTURER_ID = 0x031E +local INOVELLI_VZW31_SN_PRODUCT_TYPE = 0x0015 +local INOVELLI_DIMMER_PRODUCT_ID = 0x0001 + +local function can_handle_vzw31_sn(opts, driver, device, ...) + if device:id_match( + INOVELLI_MANUFACTURER_ID, + INOVELLI_VZW31_SN_PRODUCT_TYPE, + INOVELLI_DIMMER_PRODUCT_ID + ) then + return true, require("inovelli.vzw31-sn") + end + return false +end + +return can_handle_vzw31_sn diff --git a/drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/init.lua b/drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/init.lua new file mode 100644 index 0000000000..cbd1e1ba25 --- /dev/null +++ b/drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/init.lua @@ -0,0 +1,67 @@ +-- Copyright 2025 SmartThings, Inc. +-- Licensed under the Apache License, Version 2.0 + +local capabilities = require "st.capabilities" +--- @type st.zwave.CommandClass.SwitchMultilevel +local SwitchMultilevel = (require "st.zwave.CommandClass.SwitchMultilevel")({version=4}) +--- @type st.zwave.CommandClass.Meter +local Meter = (require "st.zwave.CommandClass.Meter")({ version = 3 }) +--- @type st.zwave.CommandClass.Association +local Association = (require "st.zwave.CommandClass.Association")({ version = 1 }) +--- @type st.device +local st_device = require "st.device" + +local supported_button_values = { + ["button1"] = {"pushed","held","down_hold","pushed_2x","pushed_3x","pushed_4x","pushed_5x"}, + ["button2"] = {"pushed","held","down_hold","pushed_2x","pushed_3x","pushed_4x","pushed_5x"}, + ["button3"] = {"pushed","held","down_hold","pushed_2x","pushed_3x","pushed_4x","pushed_5x"} +} + +local function refresh_handler(driver, device) + device:send(SwitchMultilevel:Get({})) + device:send(Meter:Get({ scale = Meter.scale.electric_meter.WATTS })) + device:send(Meter:Get({ scale = Meter.scale.electric_meter.KILOWATT_HOURS })) +end + +local function device_added(driver, device) + if device.network_type ~= st_device.NETWORK_TYPE_CHILD then + device:send(Association:Set({grouping_identifier = 1, node_ids = {driver.environment_info.hub_zwave_id}})) + for _, component in pairs(device.profile.components) do + if component.id ~= "main" and component.id ~= "LEDColorConfiguration" then + device:emit_component_event( + component, + capabilities.button.supportedButtonValues( + supported_button_values[component.id], + { visibility = { displayed = false } } + ) + ) + device:emit_component_event( + component, + capabilities.button.numberOfButtons({value = 1}, { visibility = { displayed = false } }) + ) + end + end + refresh_handler(driver, device) + else + device:emit_event(capabilities.colorControl.hue(1)) + device:emit_event(capabilities.colorControl.saturation(1)) + device:emit_event(capabilities.colorTemperature.colorTemperatureRange({ value = {minimum = 2700, maximum = 6500} })) + device:emit_event(capabilities.switchLevel.level(100)) + device:emit_event(capabilities.switch.switch("off")) + end +end + +local vzw31_sn = { + NAME = "Inovelli VZW31-SN Dimmer", + lifecycle_handlers = { + added = device_added, + }, + capability_handlers = { + [capabilities.refresh.ID] = { + [capabilities.refresh.commands.refresh.NAME] = refresh_handler + } + }, + can_handle = require("inovelli.vzw31-sn.can_handle") +} + +return vzw31_sn \ No newline at end of file diff --git a/drivers/SmartThings/zwave-switch/src/preferences.lua b/drivers/SmartThings/zwave-switch/src/preferences.lua index 824e570070..375d848147 100644 --- a/drivers/SmartThings/zwave-switch/src/preferences.lua +++ b/drivers/SmartThings/zwave-switch/src/preferences.lua @@ -59,6 +59,33 @@ local devices = { switchType = {parameter_number = 22, size = 1} } }, + INOVELLI_VZW31_SN = { + MATCHING_MATRIX = { + mfrs = 0x031E, + product_types = {0x0015}, + product_ids = 0x0001 + }, + PARAMETERS = { + parameter158 = {parameter_number = 158, size = 1}, + parameter52 = {parameter_number = 52, size = 1}, + parameter1 = {parameter_number = 1, size = 1}, + parameter2 = {parameter_number = 2, size = 1}, + parameter3 = {parameter_number = 3, size = 1}, + parameter4 = {parameter_number = 4, size = 1}, + parameter9 = {parameter_number = 9, size = 1}, + parameter10 = {parameter_number = 10, size = 1}, + parameter15 = {parameter_number = 15, size = 1}, + parameter18 = {parameter_number = 18, size = 1}, + parameter19 = {parameter_number = 19, size = 2}, + parameter20 = {parameter_number = 20, size = 2}, + parameter22 = {parameter_number = 22, size = 1}, + parameter50 = {parameter_number = 50, size = 1}, + parameter95 = {parameter_number = 95, size = 1}, + parameter96 = {parameter_number = 96, size = 1}, + parameter97 = {parameter_number = 97, size = 1}, + parameter98 = {parameter_number = 98, size = 1}, + } + }, INOVELLI_VZW32_SN = { MATCHING_MATRIX = { mfrs = 0x031E, From e6f6b783628634b5f20d66f09dc260a3d187ad63 Mon Sep 17 00:00:00 2001 From: InovelliUSA Date: Sat, 20 Dec 2025 16:47:54 -0700 Subject: [PATCH 2/2] needed to add multilevel report handler to pass test suite --- .../zwave-switch/src/inovelli/vzw31-sn/init.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/init.lua b/drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/init.lua index cbd1e1ba25..ee0227c4e7 100644 --- a/drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/init.lua +++ b/drivers/SmartThings/zwave-switch/src/inovelli/vzw31-sn/init.lua @@ -10,6 +10,8 @@ local Meter = (require "st.zwave.CommandClass.Meter")({ version = 3 }) local Association = (require "st.zwave.CommandClass.Association")({ version = 1 }) --- @type st.device local st_device = require "st.device" +local cc = require "st.zwave.CommandClass" + local supported_button_values = { ["button1"] = {"pushed","held","down_hold","pushed_2x","pushed_3x","pushed_4x","pushed_5x"}, @@ -51,11 +53,22 @@ local function device_added(driver, device) end end +local function onoff_level_report_handler(driver, device, cmd) + local value = cmd.args.target_value and cmd.args.target_value or cmd.args.value + device:emit_event(value == 0 and capabilities.switch.switch.off() or capabilities.switch.switch.on()) + device:emit_event(capabilities.switchLevel.level(value)) +end + local vzw31_sn = { NAME = "Inovelli VZW31-SN Dimmer", lifecycle_handlers = { added = device_added, }, + zwave_handlers = { + [cc.SWITCH_MULTILEVEL] = { + [SwitchMultilevel.REPORT] = onoff_level_report_handler + } + }, capability_handlers = { [capabilities.refresh.ID] = { [capabilities.refresh.commands.refresh.NAME] = refresh_handler