From 8ce98f7ea1aaa86017f625327f4bd76a6832ce47 Mon Sep 17 00:00:00 2001 From: Corey Stup Date: Sun, 28 Aug 2022 17:53:30 -0400 Subject: [PATCH 1/2] - Added support for switchLevel. Previous DTH supported it, needed for better Alexa support. - Added preferences/settings for leviton 4 speed fan. --- .../SmartThings/zwave-fan/fingerprints.yml | 2 +- .../zwave-fan/profiles/fan-3speed.yml | 2 + .../zwave-fan/profiles/fan-4speed.yml | 2 + .../zwave-fan/profiles/leviton-fan-4speed.yml | 74 +++++++++++++++++++ drivers/SmartThings/zwave-fan/src/init.lua | 32 ++++++++ .../SmartThings/zwave-fan/src/preferences.lua | 54 ++++++++++++++ .../zwave-fan/src/zwave_fan_helpers.lua | 9 +++ 7 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 drivers/SmartThings/zwave-fan/profiles/leviton-fan-4speed.yml create mode 100644 drivers/SmartThings/zwave-fan/src/preferences.lua diff --git a/drivers/SmartThings/zwave-fan/fingerprints.yml b/drivers/SmartThings/zwave-fan/fingerprints.yml index 440fcd6e52..0b842dfb79 100644 --- a/drivers/SmartThings/zwave-fan/fingerprints.yml +++ b/drivers/SmartThings/zwave-fan/fingerprints.yml @@ -28,4 +28,4 @@ zwaveManufacturer: manufacturerId: 0x001D productType: 0x0038 productId: 0x0002 - deviceProfileName: fan-4speed \ No newline at end of file + deviceProfileName: leviton-fan-4speed \ No newline at end of file diff --git a/drivers/SmartThings/zwave-fan/profiles/fan-3speed.yml b/drivers/SmartThings/zwave-fan/profiles/fan-3speed.yml index f49120604a..e6667b7178 100644 --- a/drivers/SmartThings/zwave-fan/profiles/fan-3speed.yml +++ b/drivers/SmartThings/zwave-fan/profiles/fan-3speed.yml @@ -6,6 +6,8 @@ components: version: 1 - id: switch version: 1 + - id: switchLevel + version: 1 - id: refresh version: 1 categories: diff --git a/drivers/SmartThings/zwave-fan/profiles/fan-4speed.yml b/drivers/SmartThings/zwave-fan/profiles/fan-4speed.yml index 978b6d2dce..fe8465dbbf 100644 --- a/drivers/SmartThings/zwave-fan/profiles/fan-4speed.yml +++ b/drivers/SmartThings/zwave-fan/profiles/fan-4speed.yml @@ -6,6 +6,8 @@ components: version: 1 - id: switch version: 1 + - id: switchLevel + version: 1 - id: refresh version: 1 categories: diff --git a/drivers/SmartThings/zwave-fan/profiles/leviton-fan-4speed.yml b/drivers/SmartThings/zwave-fan/profiles/leviton-fan-4speed.yml new file mode 100644 index 0000000000..786351a5b1 --- /dev/null +++ b/drivers/SmartThings/zwave-fan/profiles/leviton-fan-4speed.yml @@ -0,0 +1,74 @@ +name: leviton-fan-4speed +components: +- id: main + capabilities: + - id: fanSpeed + version: 1 + - id: switch + version: 1 + - id: switchLevel + version: 1 + - id: refresh + version: 1 + categories: + - name: Fan +preferences: +- name: "ledLevelIndicatorTimeout" + title: "Level Indicator" + description: "0 = Level Indicator always off; 1-254 = Level indicator on time in seconds; 255 = Level Indicator always on" + required: true + preferenceType: integer + definition: + minimum: 0 + maximum: 255 + default: 3 +- name: "statusLEDConfiguration" + title: "Status LED" + preferenceType: enumeration + required: true + definition: + options: + 254: "Status LED On when the fan is On" + 255: "Status LED On when the fan is Off" + 0: "Status LED is always Off" + default: 255 +- name: "minimumFanSpeedLevel" + title: "Minimum Fan Speed Level" + description: "The lowest speed can be increased for larger fans which may struggle to turn on at the lowest level" + preferenceType: enumeration + required: true + definition: + options: + 25: "Low" + 50: "Medium" + 75: "High" + 99: "Max" + default: 25 +- name: "maximumFanSpeedLevel" + title: "Maximum Fan Speed Level" + description: "The maximum speed can be set lower than the fastest speed to prevent wobbling" + preferenceType: enumeration + required: true + definition: + options: + 25: "Low" + 50: "Medium" + 75: "High" + 99: "Max" + default: 99 +- name: "presetFanSpeedLevel" + title: "Turn On Speed" + description: "Fan Speed Level when the fan is turned on" + preferenceType: enumeration + required: true + definition: + options: + 0: "Return to the last speed" + 25: "Low" + 50: "Medium" + 75: "High" + 99: "Max" + default: 0 +metadata: + mnmn: SmartThingsEdge + vid: generic-fan-4-speed \ No newline at end of file diff --git a/drivers/SmartThings/zwave-fan/src/init.lua b/drivers/SmartThings/zwave-fan/src/init.lua index acdb34ae76..e0cbd429e7 100644 --- a/drivers/SmartThings/zwave-fan/src/init.lua +++ b/drivers/SmartThings/zwave-fan/src/init.lua @@ -18,6 +18,34 @@ 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" + +--- 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]) + --2's complement value if needed + --fix for Configuration:Set() not yet packing unsigned bytes > 127 correctly + if preferences[id].size == 1 and new_parameter_value > 127 then + new_parameter_value = new_parameter_value - 256 + end + 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 -------------------------------------------------------------------------------------------- @@ -26,6 +54,10 @@ local driver_template = { supported_capabilities = { capabilities.switch, capabilities.fanSpeed, + capabilities.switchLevel, + }, + lifecycle_handlers = { + infoChanged = info_changed }, sub_drivers = { require("zwave-fan-3-speed"), diff --git a/drivers/SmartThings/zwave-fan/src/preferences.lua b/drivers/SmartThings/zwave-fan/src/preferences.lua new file mode 100644 index 0000000000..43221d7d1a --- /dev/null +++ b/drivers/SmartThings/zwave-fan/src/preferences.lua @@ -0,0 +1,54 @@ +-- Copyright 2022 SmartThings +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. + +local devices = { + LEVITON = { + MATCHING_MATRIX = { -- Zwave 4 speed fan controller model ZW4SF + mfrs = 0x001D, + product_types = 0x0038, + product_ids = 0x0002, + }, + PARAMETERS = { + minimumFanSpeedLevel = {parameter_number = 3, size = 1}, -- P3: Minimum fan speed level + maximumFanSpeedLevel = {parameter_number = 4, size = 1}, -- P4: Maximum fan speed level + presetFanSpeedLevel = {parameter_number = 5, size = 1}, -- P5: Preset fan speed level + ledLevelIndicatorTimeout = {parameter_number = 6, size = 1}, -- P6: LED level indicator timeout + statusLEDConfiguration = {parameter_number = 7, size = 1}, -- P7: Status LED configuration + }, + }, + } + + 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 diff --git a/drivers/SmartThings/zwave-fan/src/zwave_fan_helpers.lua b/drivers/SmartThings/zwave-fan/src/zwave_fan_helpers.lua index e166ec8c3f..62d7425787 100644 --- a/drivers/SmartThings/zwave-fan/src/zwave_fan_helpers.lua +++ b/drivers/SmartThings/zwave-fan/src/zwave_fan_helpers.lua @@ -62,6 +62,15 @@ function zwave_handlers.fan_multilevel_report(driver, device, cmd, map_switch_le device:emit_event(capabilities.fanSpeed.fanSpeed(map_switch_level_to_fan_speed(level))) device:emit_event(level > 0 and capabilities.switch.switch.on() or capabilities.switch.switch.off()) + + if device:supports_capability_by_id(capabilities.switchLevel.ID) then + if level == 99 or level == 0xFF then + -- Directly map 99 to 100 to avoid rounding issues remapping 0-99 to 0-100 + -- 0xFF is a (deprecated) reserved value that the spec requires be mapped to 100 + level = 100 + end + device:emit_event_for_endpoint(cmd.src_channel, capabilities.switchLevel.level(level)) + end end end From 497d0f45b1f7c7b3f613e80b63ce15a1aeea0b55 Mon Sep 17 00:00:00 2001 From: Corey Stup Date: Mon, 29 Aug 2022 11:46:26 -0400 Subject: [PATCH 2/2] Updated preference text for Status LED Updated "Status LED" preference text to fit better on app. --- .../SmartThings/zwave-fan/profiles/leviton-fan-4speed.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/SmartThings/zwave-fan/profiles/leviton-fan-4speed.yml b/drivers/SmartThings/zwave-fan/profiles/leviton-fan-4speed.yml index 786351a5b1..7d7fbc80da 100644 --- a/drivers/SmartThings/zwave-fan/profiles/leviton-fan-4speed.yml +++ b/drivers/SmartThings/zwave-fan/profiles/leviton-fan-4speed.yml @@ -24,13 +24,14 @@ preferences: default: 3 - name: "statusLEDConfiguration" title: "Status LED" + description: "Status LED On when" preferenceType: enumeration required: true definition: options: - 254: "Status LED On when the fan is On" - 255: "Status LED On when the fan is Off" - 0: "Status LED is always Off" + 254: "Fan is On" + 255: "Fan is Off" + 0: "Always Off" default: 255 - name: "minimumFanSpeedLevel" title: "Minimum Fan Speed Level"