From 97b0d52000421b6991f6151329d2cc821c4251ab Mon Sep 17 00:00:00 2001 From: Carter Swedal Date: Wed, 6 Mar 2024 08:19:10 -0700 Subject: [PATCH 1/6] fixup! allow specified port lunchbox (#1257) --- drivers/SmartThings/jbl/src/lunchbox/rest.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/SmartThings/jbl/src/lunchbox/rest.lua b/drivers/SmartThings/jbl/src/lunchbox/rest.lua index 340b73e114..3d682718b7 100644 --- a/drivers/SmartThings/jbl/src/lunchbox/rest.lua +++ b/drivers/SmartThings/jbl/src/lunchbox/rest.lua @@ -30,7 +30,8 @@ local function connect(client) port = 443 use_ssl = true end - + + local port = client.base_url.port or default_port local sock, err = client.socket_builder(client.base_url.host, port, use_ssl) if sock == nil then From 7221665bd14c0d367cc726b75435f25a9244a1b4 Mon Sep 17 00:00:00 2001 From: Hongming6 <150672162+Hongming6@users.noreply.github.com> Date: Thu, 7 Mar 2024 04:56:21 +0800 Subject: [PATCH 2/6] Aqara LED Light Bulb T1 (Tunable White) (#1116) * Aqara LED Light Bulb T1 (Tunable White) * modification time * Fixed the intermediate level reported during device dimming --- .../zigbee-switch/fingerprints.yml | 5 + .../zigbee-switch/profiles/aqara-led-bulb.yml | 27 +++ .../zigbee-switch/src/aqara-light/init.lua | 16 +- .../zigbee-switch/src/preferences.lua | 9 + .../src/test/test_aqara_led_bulb.lua | 159 ++++++++++++++++++ 5 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 drivers/SmartThings/zigbee-switch/profiles/aqara-led-bulb.yml create mode 100644 drivers/SmartThings/zigbee-switch/src/test/test_aqara_led_bulb.lua diff --git a/drivers/SmartThings/zigbee-switch/fingerprints.yml b/drivers/SmartThings/zigbee-switch/fingerprints.yml index e1d212be01..9fe0d2e184 100644 --- a/drivers/SmartThings/zigbee-switch/fingerprints.yml +++ b/drivers/SmartThings/zigbee-switch/fingerprints.yml @@ -111,6 +111,11 @@ zigbeeManufacturer: manufacturer: LUMI model: lumi.light.acn004 deviceProfileName: aqara-light + - id: "Aqara/lumi.light.acn014" + deviceLabel: Aqara LED Light Bulb T1 (Tunable White) + manufacturer: Aqara + model: lumi.light.acn014 + deviceProfileName: aqara-led-bulb # VIMAR - id: "Vimar/xx592-2-way-smart-switch" deviceLabel: Vimar 2-way Smart Switch diff --git a/drivers/SmartThings/zigbee-switch/profiles/aqara-led-bulb.yml b/drivers/SmartThings/zigbee-switch/profiles/aqara-led-bulb.yml new file mode 100644 index 0000000000..65ee11beb0 --- /dev/null +++ b/drivers/SmartThings/zigbee-switch/profiles/aqara-led-bulb.yml @@ -0,0 +1,27 @@ +name: aqara-led-bulb +components: + - id: main + capabilities: + - id: switch + version: 1 + - id: switchLevel + version: 1 + config: + values: + - key: "level.value" + range: [1, 100] + - id: colorTemperature + version: 1 + config: + values: + - key: "colorTemperature.value" + range: [2700, 6500] + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 + categories: + - name: Light +preferences: + - preferenceId: stse.restorePowerState + explicit: true diff --git a/drivers/SmartThings/zigbee-switch/src/aqara-light/init.lua b/drivers/SmartThings/zigbee-switch/src/aqara-light/init.lua index 64b3a31649..528902864f 100644 --- a/drivers/SmartThings/zigbee-switch/src/aqara-light/init.lua +++ b/drivers/SmartThings/zigbee-switch/src/aqara-light/init.lua @@ -1,6 +1,7 @@ local clusters = require "st.zigbee.zcl.clusters" local cluster_base = require "st.zigbee.cluster_base" local data_types = require "st.zigbee.data_types" +local capabilities = require "st.capabilities" local OnOff = clusters.OnOff local Level = clusters.Level @@ -11,7 +12,8 @@ local PRIVATE_ATTRIBUTE_ID = 0x0009 local MFG_CODE = 0x115F local FINGERPRINTS = { - { mfr = "LUMI", model = "lumi.light.acn004" } + { mfr = "LUMI", model = "lumi.light.acn004" }, + { mfr = "Aqara", model = "lumi.light.acn014" } } local function is_aqara_products(opts, driver, device) @@ -43,12 +45,24 @@ local function device_added(driver, device, event) device:send(Level.attributes.OffTransitionTime:write(device, 0)) end +local function set_level_handler(driver, device, cmd) + local level = math.floor(cmd.args.level / 100.0 * 254) + local dimming_rate = 0x0000 + + device:send(Level.commands.MoveToLevelWithOnOff(device, level, dimming_rate)) +end + local aqara_light_handler = { NAME = "Aqara Light Handler", lifecycle_handlers = { added = device_added, doConfigure = do_configure }, + capability_handlers = { + [capabilities.switchLevel.ID] = { + [capabilities.switchLevel.commands.setLevel.NAME] = set_level_handler + } + }, can_handle = is_aqara_products } diff --git a/drivers/SmartThings/zigbee-switch/src/preferences.lua b/drivers/SmartThings/zigbee-switch/src/preferences.lua index 20900d5a52..64c003eb56 100644 --- a/drivers/SmartThings/zigbee-switch/src/preferences.lua +++ b/drivers/SmartThings/zigbee-switch/src/preferences.lua @@ -37,6 +37,15 @@ local devices = { return clusters.Level.attributes.OffTransitionTime:write(device, raw_value) end } + }, + AQARA_LIGHT_BULB = { + MATCHING_MATRIX = { mfr = "Aqara", model = "lumi.light.acn014" }, + PARAMETERS = { + ["stse.restorePowerState"] = function(device, value) + return cluster_base.write_manufacturer_specific_attribute(device, 0xFCC0, + 0x0201, 0x115F, data_types.Boolean, value) + end + } } } local preferences = {} diff --git a/drivers/SmartThings/zigbee-switch/src/test/test_aqara_led_bulb.lua b/drivers/SmartThings/zigbee-switch/src/test/test_aqara_led_bulb.lua new file mode 100644 index 0000000000..86c8d63058 --- /dev/null +++ b/drivers/SmartThings/zigbee-switch/src/test/test_aqara_led_bulb.lua @@ -0,0 +1,159 @@ +-- Copyright 2023 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 test = require "integration_test" +local t_utils = require "integration_test.utils" +local clusters = require "st.zigbee.zcl.clusters" +local cluster_base = require "st.zigbee.cluster_base" +local data_types = require "st.zigbee.data_types" +local zigbee_test_utils = require "integration_test.zigbee_test_utils" + +local OnOff = clusters.OnOff +local Level = clusters.Level +local ColorControl = clusters.ColorControl + +local PRIVATE_CLUSTER_ID = 0xFCC0 +local PRIVATE_ATTRIBUTE_ID = 0x0009 +local MFG_CODE = 0x115F + +local RESTORE_POWER_STATE_ATTRIBUTE_ID = 0x0201 + +local mock_device = test.mock_device.build_test_zigbee_device( + { + profile = t_utils.get_profile_definition("aqara-led-bulb.yml"), + fingerprinted_endpoint_id = 0x01, + zigbee_endpoints = { + [1] = { + id = 1, + manufacturer = "Aqara", + model = "lumi.light.acn014", + server_clusters = { 0x0006, 0x0008, 0x0300 } + } + } + } +) + +zigbee_test_utils.prepare_zigbee_env_info() + +local function test_init() + test.mock_device.add_test_device(mock_device) +end + +test.set_test_init_function(test_init) + +test.register_coroutine_test( + "Handle added lifecycle", + function() + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" }) + + test.socket.zigbee:__expect_send( + { + mock_device.id, + cluster_base.write_manufacturer_specific_attribute(mock_device, PRIVATE_CLUSTER_ID, PRIVATE_ATTRIBUTE_ID + , MFG_CODE, data_types.Uint8, 1) + } + ) + test.socket.zigbee:__expect_send({ mock_device.id, Level.attributes.OnTransitionTime:write(mock_device, 0) }) + test.socket.zigbee:__expect_send({ mock_device.id, Level.attributes.OffTransitionTime:write(mock_device, 0) }) + end +) + +test.register_coroutine_test( + "Configure should configure all necessary attributes and refresh device", + function() + test.socket.device_lifecycle:__queue_receive({ mock_device.id, "doConfigure" }) + test.socket.zigbee:__set_channel_ordering("relaxed") + + test.socket.zigbee:__expect_send( + { + mock_device.id, + ColorControl.commands.MoveToColorTemperature(mock_device, 200, 0) + } + ) + + test.socket.zigbee:__expect_send({ + mock_device.id, + zigbee_test_utils.build_bind_request(mock_device, zigbee_test_utils.mock_hub_eui, Level.ID) + }) + test.socket.zigbee:__expect_send( + { + mock_device.id, + Level.attributes.CurrentLevel:configure_reporting(mock_device, 1, 3600, 1) + } + ) + test.socket.zigbee:__expect_send({ + mock_device.id, + zigbee_test_utils.build_bind_request(mock_device, zigbee_test_utils.mock_hub_eui, ColorControl.ID) + }) + test.socket.zigbee:__expect_send( + { + mock_device.id, + ColorControl.attributes.ColorTemperatureMireds:configure_reporting(mock_device, 1, 3600, 16) + } + ) + test.socket.zigbee:__expect_send({ + mock_device.id, + zigbee_test_utils.build_bind_request(mock_device, zigbee_test_utils.mock_hub_eui, OnOff.ID) + }) + test.socket.zigbee:__expect_send( + { + mock_device.id, + OnOff.attributes.OnOff:configure_reporting(mock_device, 0, 300, 1) + } + ) + + test.socket.zigbee:__expect_send({ mock_device.id, OnOff.attributes.OnOff:read(mock_device) }) + test.socket.zigbee:__expect_send({ mock_device.id, Level.attributes.CurrentLevel:read(mock_device) }) + test.socket.zigbee:__expect_send({ mock_device.id, ColorControl.attributes.ColorTemperatureMireds:read(mock_device) }) + + mock_device:expect_metadata_update({ provisioning_state = "PROVISIONED" }) + end +) + +test.register_coroutine_test( + "Set Color Temperature command test", + function() + test.timer.__create_and_queue_test_time_advance_timer(1, "oneshot") + test.socket.capability:__queue_receive({ mock_device.id, + { capability = "colorTemperature", component = "main", command = "setColorTemperature", args = { 200 } } }) + + local temp_in_mired = math.floor(1000000 / 200) + test.socket.zigbee:__expect_send( + { + mock_device.id, + OnOff.commands.On(mock_device) + } + ) + test.socket.zigbee:__expect_send( + { + mock_device.id, + ColorControl.commands.MoveToColorTemperature(mock_device, temp_in_mired, 0x0000) + } + ) + end +) + +test.register_coroutine_test( + "Handle restorePowerState in infochanged", + function() + test.socket.device_lifecycle:__queue_receive(mock_device:generate_info_changed({ + preferences = { ["stse.restorePowerState"] = true } + })) + test.socket.zigbee:__expect_send({ mock_device.id, + cluster_base.write_manufacturer_specific_attribute(mock_device, PRIVATE_CLUSTER_ID, + RESTORE_POWER_STATE_ATTRIBUTE_ID, MFG_CODE, data_types.Boolean, true) }) + end +) + +test.run_registered_tests() From 4b6a5a27e9bc1c0224ba044710f518655c0d7be3 Mon Sep 17 00:00:00 2001 From: Douglas Stephen Date: Wed, 6 Mar 2024 20:54:27 -0600 Subject: [PATCH 3/6] Update Zigbee tests for next Lua Libs release (#1156) The next Lua Libs release has a few changes on timing and tolerance for some clusters to ease battery drain, so these test updates will need to be merged in at that time. Co-authored-by: cjswedes --- .../SmartThings/zigbee-button/src/test/test_samjin_button.lua | 2 +- .../zigbee-contact/src/test/test_centralite_multi_sensor.lua | 2 +- .../zigbee-contact/src/test/test_samjin_multi_sensor.lua | 2 +- .../zigbee-contact/src/test/test_smartthings_multi_sensor.lua | 2 +- .../zigbee-contact/src/test/test_zigbee_contact.lua | 4 ++-- .../src/test/test_centralite_sensor.lua | 2 +- .../zigbee-humidity-sensor/src/test/test_heiman_sensor.lua | 2 +- .../src/test/test_humidity_temperature.lua | 2 +- .../src/test/test_humidity_temperature_sensor.lua | 2 +- .../src/test/test_all_capabilities_zigbee_motion.lua | 2 +- .../zigbee-motion-sensor/src/test/test_compacta_motion.lua | 2 +- .../zigbee-motion-sensor/src/test/test_frient_sensor.lua | 2 +- .../zigbee-motion-sensor/src/test/test_samjin_sensor.lua | 2 +- .../zigbee-sound-sensor/src/test/test_zigbee_sound_sensor.lua | 2 +- .../src/test/test_centralite_water_leak_sensor.lua | 2 +- .../src/test/test_frient_water_leak_sensor.lua | 2 +- .../src/test/test_samjin_water_leak_sensor.lua | 2 +- .../src/test/test_sinope_zigbee_water.lua | 4 ++-- .../src/test/test_smartthings_water_leak_sensor.lua | 2 +- .../zigbee-water-leak-sensor/src/test/test_zigbee_water.lua | 4 ++-- .../src/test/test_zigbee_water_freeze.lua | 4 ++-- 21 files changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/SmartThings/zigbee-button/src/test/test_samjin_button.lua b/drivers/SmartThings/zigbee-button/src/test/test_samjin_button.lua index 7a59312850..9e986f097f 100644 --- a/drivers/SmartThings/zigbee-button/src/test/test_samjin_button.lua +++ b/drivers/SmartThings/zigbee-button/src/test/test_samjin_button.lua @@ -89,7 +89,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send({ mock_device.id, TemperatureMeasurement.attributes.MeasuredValue:configure_reporting( - mock_device, 30, 300, 16 + mock_device, 30, 600, 100 ) }) test.socket.zigbee:__expect_send({ diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_centralite_multi_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_centralite_multi_sensor.lua index 2b93291472..e3628f6ec7 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_centralite_multi_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_centralite_multi_sensor.lua @@ -240,7 +240,7 @@ test.register_coroutine_test( }) test.socket.zigbee:__expect_send({ mock_device.id, - TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 16) + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) }) test.socket.zigbee:__expect_send({ mock_device.id, diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_samjin_multi_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_samjin_multi_sensor.lua index a1b72c1344..d8a23f4af5 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_samjin_multi_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_samjin_multi_sensor.lua @@ -147,7 +147,7 @@ test.register_coroutine_test( }) test.socket.zigbee:__expect_send({ mock_device.id, - TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 16) + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) }) test.socket.zigbee:__expect_send({ mock_device.id, diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_smartthings_multi_sensor.lua b/drivers/SmartThings/zigbee-contact/src/test/test_smartthings_multi_sensor.lua index 0953858c0d..05e5fdd0d4 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_smartthings_multi_sensor.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_smartthings_multi_sensor.lua @@ -294,7 +294,7 @@ test.register_coroutine_test( }) test.socket.zigbee:__expect_send({ mock_device.id, - TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 16) + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) }) test.socket.zigbee:__expect_send({ mock_device.id, diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_zigbee_contact.lua b/drivers/SmartThings/zigbee-contact/src/test/test_zigbee_contact.lua index 1f5be76ca2..0c89cbb6aa 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_zigbee_contact.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_zigbee_contact.lua @@ -190,8 +190,8 @@ test.register_coroutine_test( mock_device.id, TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, - 300, - 0x10) + 600, + 100) } ) test.socket.zigbee:__expect_send( diff --git a/drivers/SmartThings/zigbee-humidity-sensor/src/test/test_centralite_sensor.lua b/drivers/SmartThings/zigbee-humidity-sensor/src/test/test_centralite_sensor.lua index 96ddd665e0..626d704f2a 100644 --- a/drivers/SmartThings/zigbee-humidity-sensor/src/test/test_centralite_sensor.lua +++ b/drivers/SmartThings/zigbee-humidity-sensor/src/test/test_centralite_sensor.lua @@ -141,7 +141,7 @@ test.register_coroutine_test( }) test.socket.zigbee:__expect_send({ mock_device.id, - TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 16) + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) }) test.socket.zigbee:__expect_send({ mock_device.id, diff --git a/drivers/SmartThings/zigbee-humidity-sensor/src/test/test_heiman_sensor.lua b/drivers/SmartThings/zigbee-humidity-sensor/src/test/test_heiman_sensor.lua index 45795d7faa..3dd7f5c719 100644 --- a/drivers/SmartThings/zigbee-humidity-sensor/src/test/test_heiman_sensor.lua +++ b/drivers/SmartThings/zigbee-humidity-sensor/src/test/test_heiman_sensor.lua @@ -127,7 +127,7 @@ test.register_coroutine_test( }) test.socket.zigbee:__expect_send({ mock_device.id, - TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 16) + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) }) test.socket.zigbee:__expect_send({ mock_device.id, RelativeHumidity.attributes.MeasuredValue:read(mock_device):to_endpoint(0x02) }) test.socket.zigbee:__expect_send({ mock_device.id, TemperatureMeasurement.attributes.MeasuredValue:read(mock_device) }) diff --git a/drivers/SmartThings/zigbee-humidity-sensor/src/test/test_humidity_temperature.lua b/drivers/SmartThings/zigbee-humidity-sensor/src/test/test_humidity_temperature.lua index cf22600ec1..3fa1b5719b 100644 --- a/drivers/SmartThings/zigbee-humidity-sensor/src/test/test_humidity_temperature.lua +++ b/drivers/SmartThings/zigbee-humidity-sensor/src/test/test_humidity_temperature.lua @@ -94,7 +94,7 @@ test.register_coroutine_test( }) test.socket.zigbee:__expect_send({ mock_device.id, - TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 0x10) + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) }) test.socket.zigbee:__expect_send({ mock_device.id, diff --git a/drivers/SmartThings/zigbee-humidity-sensor/src/test/test_humidity_temperature_sensor.lua b/drivers/SmartThings/zigbee-humidity-sensor/src/test/test_humidity_temperature_sensor.lua index 9114c04bc8..1defdb1b71 100644 --- a/drivers/SmartThings/zigbee-humidity-sensor/src/test/test_humidity_temperature_sensor.lua +++ b/drivers/SmartThings/zigbee-humidity-sensor/src/test/test_humidity_temperature_sensor.lua @@ -101,7 +101,7 @@ test.register_coroutine_test( }) test.socket.zigbee:__expect_send({ mock_device.id, - TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 0x10) + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) }) test.socket.zigbee:__expect_send({ mock_device.id, diff --git a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_all_capabilities_zigbee_motion.lua b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_all_capabilities_zigbee_motion.lua index 4f348b727f..c68eb33ef9 100644 --- a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_all_capabilities_zigbee_motion.lua +++ b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_all_capabilities_zigbee_motion.lua @@ -194,7 +194,7 @@ test.register_coroutine_test( }) test.socket.zigbee:__expect_send({ mock_device.id, - TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 0x10) + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) }) test.socket.zigbee:__expect_send({ mock_device.id, diff --git a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_compacta_motion.lua b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_compacta_motion.lua index 4b558cc36e..a5264683e5 100644 --- a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_compacta_motion.lua +++ b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_compacta_motion.lua @@ -60,7 +60,7 @@ test.register_coroutine_test( }) test.socket.zigbee:__expect_send({ mock_device.id, - TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 16) + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) }) test.socket.zigbee:__expect_send({ mock_device.id, diff --git a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_frient_sensor.lua b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_frient_sensor.lua index bf4d309272..c2eb704ccc 100644 --- a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_frient_sensor.lua +++ b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_frient_sensor.lua @@ -62,7 +62,7 @@ test.register_coroutine_test( }) test.socket.zigbee:__expect_send({ mock_device.id, - TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 16) + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) }) test.socket.zigbee:__expect_send({ mock_device.id, diff --git a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_samjin_sensor.lua b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_samjin_sensor.lua index 637b2346f8..a645c46c75 100644 --- a/drivers/SmartThings/zigbee-motion-sensor/src/test/test_samjin_sensor.lua +++ b/drivers/SmartThings/zigbee-motion-sensor/src/test/test_samjin_sensor.lua @@ -70,7 +70,7 @@ test.register_coroutine_test( }) test.socket.zigbee:__expect_send({ mock_device.id, - TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 16) + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) }) test.socket.zigbee:__expect_send({ mock_device.id, diff --git a/drivers/SmartThings/zigbee-sound-sensor/src/test/test_zigbee_sound_sensor.lua b/drivers/SmartThings/zigbee-sound-sensor/src/test/test_zigbee_sound_sensor.lua index 85901991b6..90249669ba 100644 --- a/drivers/SmartThings/zigbee-sound-sensor/src/test/test_zigbee_sound_sensor.lua +++ b/drivers/SmartThings/zigbee-sound-sensor/src/test/test_zigbee_sound_sensor.lua @@ -84,7 +84,7 @@ test.register_coroutine_test( }) test.socket.zigbee:__expect_send({ mock_device.id, - TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 0x10) + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) }) test.socket.zigbee:__expect_send({ mock_device.id, diff --git a/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_centralite_water_leak_sensor.lua b/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_centralite_water_leak_sensor.lua index 1ecf651e16..30258012d4 100644 --- a/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_centralite_water_leak_sensor.lua +++ b/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_centralite_water_leak_sensor.lua @@ -96,7 +96,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send( { mock_device.id, - TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 16) + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) } ) diff --git a/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_frient_water_leak_sensor.lua b/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_frient_water_leak_sensor.lua index 5412b94afa..4cae9883ca 100644 --- a/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_frient_water_leak_sensor.lua +++ b/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_frient_water_leak_sensor.lua @@ -96,7 +96,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send( { mock_device.id, - TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 16) + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) } ) test.socket.zigbee:__expect_send( diff --git a/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_samjin_water_leak_sensor.lua b/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_samjin_water_leak_sensor.lua index 5afaa68f4b..352841bdd4 100644 --- a/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_samjin_water_leak_sensor.lua +++ b/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_samjin_water_leak_sensor.lua @@ -96,7 +96,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send( { mock_device.id, - TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 16) + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) } ) diff --git a/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_sinope_zigbee_water.lua b/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_sinope_zigbee_water.lua index 3306fbb336..33f6c28f24 100644 --- a/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_sinope_zigbee_water.lua +++ b/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_sinope_zigbee_water.lua @@ -215,8 +215,8 @@ test.register_coroutine_test( TemperatureMeasurement.attributes.MeasuredValue:configure_reporting( mock_device, 30, - 300, - 0x10 + 600, + 100 ) }) test.socket.zigbee:__expect_send({ diff --git a/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_smartthings_water_leak_sensor.lua b/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_smartthings_water_leak_sensor.lua index 390e505bcd..5cf7801637 100644 --- a/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_smartthings_water_leak_sensor.lua +++ b/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_smartthings_water_leak_sensor.lua @@ -96,7 +96,7 @@ test.register_coroutine_test( test.socket.zigbee:__expect_send( { mock_device.id, - TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 300, 16) + TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device, 30, 600, 100) } ) diff --git a/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_zigbee_water.lua b/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_zigbee_water.lua index c6c712063d..b202dd450c 100644 --- a/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_zigbee_water.lua +++ b/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_zigbee_water.lua @@ -189,8 +189,8 @@ test.register_coroutine_test( TemperatureMeasurement.attributes.MeasuredValue:configure_reporting( mock_device, 30, - 300, - 0x10 + 600, + 100 ) }) test.socket.zigbee:__expect_send({ diff --git a/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_zigbee_water_freeze.lua b/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_zigbee_water_freeze.lua index c6ea0e7760..ed03d10974 100644 --- a/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_zigbee_water_freeze.lua +++ b/drivers/SmartThings/zigbee-water-leak-sensor/src/test/test_zigbee_water_freeze.lua @@ -111,8 +111,8 @@ test.register_coroutine_test( TemperatureMeasurement.attributes.MeasuredValue:configure_reporting( mock_device, 30, - 300, - 0x10 + 600, + 100 ) }) test.socket.zigbee:__expect_send({ From e7ba1e7e2ad6d43259e04ecd2cde650f75450986 Mon Sep 17 00:00:00 2001 From: Carter Swedal Date: Wed, 6 Mar 2024 21:20:31 -0700 Subject: [PATCH 4/6] fixup! jbl variable sccope (#1258) --- drivers/SmartThings/jbl/src/lunchbox/rest.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/SmartThings/jbl/src/lunchbox/rest.lua b/drivers/SmartThings/jbl/src/lunchbox/rest.lua index 3d682718b7..1128dd7f96 100644 --- a/drivers/SmartThings/jbl/src/lunchbox/rest.lua +++ b/drivers/SmartThings/jbl/src/lunchbox/rest.lua @@ -31,7 +31,7 @@ local function connect(client) use_ssl = true end - local port = client.base_url.port or default_port + if client.base_url.port ~= port then port = client.base_url.port end local sock, err = client.socket_builder(client.base_url.host, port, use_ssl) if sock == nil then @@ -268,7 +268,7 @@ RestClient.__index = RestClient function RestClient.one_shot_get(full_url, additional_headers, socket_builder) local url_table = lb_utils.force_url_table(full_url) - local client = RestClient.new(url_table.scheme .. "://" .. url_table.host, socket_builder) + local client = RestClient.new(url_table.scheme .. "://" .. url_table.authority, socket_builder) local ret, err = client:get(url_table.path, additional_headers) client:shutdown() return ret, err @@ -276,7 +276,7 @@ end function RestClient.one_shot_post(full_url, body, additional_headers, socket_builder) local url_table = lb_utils.force_url_table(full_url) - local client = RestClient.new(url_table.scheme .. "://" .. url_table.host, socket_builder) + local client = RestClient.new(url_table.scheme .. "://" .. url_table.authority, socket_builder) local ret, err = client:post(url_table.path, body, additional_headers) client:shutdown() return ret, err From 6b54273281bac6da44088590a6d79adb4f7bf701 Mon Sep 17 00:00:00 2001 From: YongSung Lee Date: Thu, 7 Mar 2024 21:09:58 +0900 Subject: [PATCH 5/6] add Resideo Korea DT300ST-M0000 Thermostat (#1119) * add Resideo Korea DT300ST-M0000 Thermostat Resideo Korea Thermostat for WWST * add unittest for child devices --- .../zigbee-thermostat/fingerprints.yml | 5 + .../thermostat-resideo-dt300st-m000.yml | 34 + .../zigbee-thermostat/src/init.lua | 3 +- .../src/resideo_korea/init.lua | 186 +++++ .../src/test/test_resideo_dt300st_m000.lua | 719 ++++++++++++++++++ 5 files changed, 946 insertions(+), 1 deletion(-) create mode 100644 drivers/SmartThings/zigbee-thermostat/profiles/thermostat-resideo-dt300st-m000.yml create mode 100644 drivers/SmartThings/zigbee-thermostat/src/resideo_korea/init.lua create mode 100644 drivers/SmartThings/zigbee-thermostat/src/test/test_resideo_dt300st_m000.lua diff --git a/drivers/SmartThings/zigbee-thermostat/fingerprints.yml b/drivers/SmartThings/zigbee-thermostat/fingerprints.yml index 1dd3137f16..b8793b0043 100644 --- a/drivers/SmartThings/zigbee-thermostat/fingerprints.yml +++ b/drivers/SmartThings/zigbee-thermostat/fingerprints.yml @@ -119,6 +119,11 @@ zigbeeManufacturer: manufacturer: Centralite model: 3156105 deviceProfileName: base-thermostat-no-operating-state + - id: "Resideo/DT300ST-M000" + deviceLabel: Main Thermostat + manufacturer: Resideo Korea + model: DT300ST-M000 + deviceProfileName: thermostat-resideo-dt300st-m000 zigbeeGeneric: - id: "genericThermostat" deviceLabel: Zigbee Thermostat diff --git a/drivers/SmartThings/zigbee-thermostat/profiles/thermostat-resideo-dt300st-m000.yml b/drivers/SmartThings/zigbee-thermostat/profiles/thermostat-resideo-dt300st-m000.yml new file mode 100644 index 0000000000..a31234eb90 --- /dev/null +++ b/drivers/SmartThings/zigbee-thermostat/profiles/thermostat-resideo-dt300st-m000.yml @@ -0,0 +1,34 @@ +name: thermostat-resideo-dt300st-m000 +components: +- id: main + capabilities: + - id: temperatureMeasurement + version: 1 + - id: thermostatHeatingSetpoint + version: 1 + config: + values: + - key: "heatingSetpoint.value" + range: [ 5, 35 ] + - id: thermostatMode + version: 1 + config: + values: + - key: "thermostatMode.value" + enabledValues: + - heating + - idle + - id: thermostatOperatingState + version: 1 + config: + values: + - key: "thermostatOperatingState.value" + enabledValues: + - heating + - idle + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 + categories: + - name: Thermostat diff --git a/drivers/SmartThings/zigbee-thermostat/src/init.lua b/drivers/SmartThings/zigbee-thermostat/src/init.lua index 0f35ada2d5..6602c1c3db 100644 --- a/drivers/SmartThings/zigbee-thermostat/src/init.lua +++ b/drivers/SmartThings/zigbee-thermostat/src/init.lua @@ -294,7 +294,8 @@ local zigbee_thermostat_driver = { require("leviton"), require("danfoss"), require("popp"), - require("vimar") + require("vimar"), + require("resideo_korea") }, } diff --git a/drivers/SmartThings/zigbee-thermostat/src/resideo_korea/init.lua b/drivers/SmartThings/zigbee-thermostat/src/resideo_korea/init.lua new file mode 100644 index 0000000000..a1e68ef02a --- /dev/null +++ b/drivers/SmartThings/zigbee-thermostat/src/resideo_korea/init.lua @@ -0,0 +1,186 @@ +-- Copyright 2023 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 device_lib = require "st.device" +local device_management = require "st.zigbee.device_management" + +-- Zigbee Spec Utils +local clusters = require "st.zigbee.zcl.clusters" +local Thermostat = clusters.Thermostat +local ThermostatSystemMode = Thermostat.attributes.SystemMode + +local capabilities = require "st.capabilities" +local ThermostatMode = capabilities.thermostatMode +local ThermostatOperatingState = capabilities.thermostatOperatingState + +local do_refresh = function(self, device) + local attributes = {Thermostat.attributes.OccupiedHeatingSetpoint, Thermostat.attributes.LocalTemperature, + Thermostat.attributes.ControlSequenceOfOperation, Thermostat.attributes.ThermostatRunningState, + Thermostat.attributes.SystemMode} + for _, attribute in pairs(attributes) do + if device.network_type == device_lib.NETWORK_TYPE_ZIGBEE then + -- SmartThings Hub has a issue with setting parent endpoint + device:send(attribute:read(device):to_endpoint(0x01)) + else + device:send(attribute:read(device)) + end + end +end + +local do_configure = function(self, device) + if device.network_type == device_lib.NETWORK_TYPE_ZIGBEE then + for endpoint = 1, 6 do + device:send(device_management.build_bind_request(device, Thermostat.ID, self.environment_info.hub_zigbee_eui, + endpoint)) + end + end + device:send(Thermostat.attributes.OccupiedHeatingSetpoint:configure_reporting(device, 20, 300, 100)) + device:send(Thermostat.attributes.LocalTemperature:configure_reporting(device, 20, 300, 100)) + device:send(Thermostat.attributes.ThermostatRunningState:configure_reporting(device, 20, 300)) + device:send(Thermostat.attributes.SystemMode:configure_reporting(device, 20, 300)) + + do_refresh(self, device) +end + +local SUPPORTED_THERMOSTAT_MODES = {ThermostatMode.thermostatMode.away.NAME, ThermostatMode.thermostatMode.heat.NAME} + +local supported_thermostat_modes_handler = function(driver, device, supported_modes, zb_rx) + device:emit_event_for_endpoint(zb_rx.address_header.src_endpoint.value, + ThermostatMode.supportedThermostatModes(SUPPORTED_THERMOSTAT_MODES, { + visibility = { + displayed = false + } + })) +end + +local thermostat_operating_state_handler = function(driver, device, operating_state, zb_rx) + if (operating_state:is_heat_second_stage_on_set() or operating_state:is_heat_on_set()) then + device:emit_event_for_endpoint(zb_rx.address_header.src_endpoint.value, + ThermostatOperatingState.thermostatOperatingState.heating()) + elseif (operating_state:is_cool_second_stage_on_set() or operating_state:is_cool_on_set()) then + device:emit_event_for_endpoint(zb_rx.address_header.src_endpoint.value, + ThermostatOperatingState.thermostatOperatingState.cooling()) + elseif (operating_state:is_fan_on_set()) then + device:emit_event_for_endpoint(zb_rx.address_header.src_endpoint.value, + ThermostatOperatingState.thermostatOperatingState.fan_only()) + else + device:emit_event_for_endpoint(zb_rx.address_header.src_endpoint.value, + ThermostatOperatingState.thermostatOperatingState.idle()) + end +end + +local function thermostat_occupied_heating_setpoint_handler(driver, device, value, zb_rx) + device:emit_event_for_endpoint(zb_rx.address_header.src_endpoint.value, + capabilities.thermostatHeatingSetpoint.heatingSetpoint({ + value = value.value / 100.0, + unit = "C" + })) +end + +local set_thermostat_mode = function(driver, device, command) + if command.args.mode == ThermostatMode.thermostatMode.off.NAME or command.args.mode == + ThermostatMode.thermostatMode.away.NAME then + device:send_to_component(command.component, Thermostat.attributes.SystemMode:write(device, ThermostatSystemMode.OFF)) + device.thread:call_with_delay(1, function(d) + device:send_to_component(command.component, Thermostat.attributes.SystemMode:read(device)) + end) + elseif command.args.mode == ThermostatMode.thermostatMode.auto.NAME or command.args.mode == + ThermostatMode.thermostatMode.heat.NAME then + device:send_to_component(command.component, + Thermostat.attributes.SystemMode:write(device, ThermostatSystemMode.HEAT)) + device.thread:call_with_delay(1, function(d) + device:send_to_component(command.component, Thermostat.attributes.SystemMode:read(device)) + end) + end +end + +local thermostat_mode_setter = function(mode_name) + return function(driver, device, command) + return set_thermostat_mode(driver, device, { + component = command.component, + args = { + mode = mode_name + } + }) + end +end + +local thermostat_mode_handler = function(driver, device, thermostat_mode, zb_rx) + if thermostat_mode.value == ThermostatSystemMode.OFF then + device:emit_event_for_endpoint(zb_rx.address_header.src_endpoint.value, ThermostatMode.thermostatMode.away()) + else + device:emit_event_for_endpoint(zb_rx.address_header.src_endpoint.value, ThermostatMode.thermostatMode.heat()) + end +end + +local function added(driver, device, event) + if device.network_type == device_lib.NETWORK_TYPE_ZIGBEE then + for i = 2, 6, 1 do + local name = string.format("Room %d", i - 1) + local metadata = { + type = "EDGE_CHILD", + label = name, + profile = "thermostat-resideo-dt300st-m000", + parent_device_id = device.id, + parent_assigned_child_key = string.format("%02X", i), + vendor_provided_label = name + } + driver:try_create_device(metadata) + end + end +end + +local function find_child(parent, ep_id) + return parent:get_child_by_parent_assigned_key(string.format("%02X", ep_id)) +end + +local function init(driver, device, event) + if device.network_type == device_lib.NETWORK_TYPE_ZIGBEE then + device:set_find_child(find_child) + end +end + +local resideo_thermostat = { + NAME = "Resideo Thermostat Handler", + lifecycle_handlers = { + init = init, + added = added, + doConfigure = do_configure + }, + zigbee_handlers = { + attr = { + [Thermostat.ID] = { + [Thermostat.attributes.ControlSequenceOfOperation.ID] = supported_thermostat_modes_handler, + [Thermostat.attributes.ThermostatRunningState.ID] = thermostat_operating_state_handler, + [Thermostat.attributes.SystemMode.ID] = thermostat_mode_handler, + [Thermostat.attributes.OccupiedHeatingSetpoint.ID] = thermostat_occupied_heating_setpoint_handler + } + } + }, + capability_handlers = { + [ThermostatMode.ID] = { + [ThermostatMode.commands.setThermostatMode.NAME] = set_thermostat_mode, + [ThermostatMode.commands.auto.NAME] = thermostat_mode_setter(ThermostatMode.thermostatMode.heat.NAME), + [ThermostatMode.commands.off.NAME] = thermostat_mode_setter(ThermostatMode.thermostatMode.off.NAME), + [ThermostatMode.commands.heat.NAME] = thermostat_mode_setter(ThermostatMode.thermostatMode.heat.NAME) + }, + [capabilities.refresh.ID] = { + [capabilities.refresh.commands.refresh.NAME] = do_refresh + } + }, + can_handle = function(opts, driver, device, ...) + return device:get_manufacturer() == "Resideo Korea" and device:get_model() == "DT300ST-M000" + end +} + +return resideo_thermostat diff --git a/drivers/SmartThings/zigbee-thermostat/src/test/test_resideo_dt300st_m000.lua b/drivers/SmartThings/zigbee-thermostat/src/test/test_resideo_dt300st_m000.lua new file mode 100644 index 0000000000..2a3348e3d0 --- /dev/null +++ b/drivers/SmartThings/zigbee-thermostat/src/test/test_resideo_dt300st_m000.lua @@ -0,0 +1,719 @@ +-- Copyright 2023 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 test = require "integration_test" +local t_utils = require "integration_test.utils" +local zigbee_test_utils = require "integration_test.zigbee_test_utils" +local clusters = require "st.zigbee.zcl.clusters" + +local Thermostat = clusters.Thermostat +local capabilities = require "st.capabilities" + +local mock_device = test.mock_device.build_test_zigbee_device({ + profile = t_utils.get_profile_definition("thermostat-resideo-dt300st-m000.yml"), + zigbee_endpoints = { + [1] = { + id = 1, + manufacturer = "Resideo Korea", + model = "DT300ST-M000", + server_clusters = {0x0201, 0x0402} + } + } +}) + +-- Room 1 (2nd Thermostat) +local mock_first_child = test.mock_device.build_test_child_device({ + profile = t_utils.get_profile_definition("thermostat-resideo-dt300st-m000.yml"), + device_network_id = string.format("%04X:%02X", mock_device:get_short_address(), 2), + parent_device_id = mock_device.id, + parent_assigned_child_key = string.format("%02X", 2) +}) + +-- Room 2 (3rd Thermostat) +local mock_second_child = test.mock_device.build_test_child_device({ + profile = t_utils.get_profile_definition("thermostat-resideo-dt300st-m000.yml"), + device_network_id = string.format("%04X:%02X", mock_device:get_short_address(), 3), + parent_device_id = mock_device.id, + parent_assigned_child_key = string.format("%02X", 3) +}) + +-- Room 3 (4th Thermostat) +local mock_third_child = test.mock_device.build_test_child_device({ + profile = t_utils.get_profile_definition("thermostat-resideo-dt300st-m000.yml"), + device_network_id = string.format("%04X:%02X", mock_device:get_short_address(), 4), + parent_device_id = mock_device.id, + parent_assigned_child_key = string.format("%02X", 4) +}) + +-- Room 4 (5th Thermostat) +local mock_forth_child = test.mock_device.build_test_child_device({ + profile = t_utils.get_profile_definition("thermostat-resideo-dt300st-m000.yml"), + device_network_id = string.format("%04X:%02X", mock_device:get_short_address(), 5), + parent_device_id = mock_device.id, + parent_assigned_child_key = string.format("%02X", 5) +}) + +-- Room 5 (6th Thermostat) +local mock_fifth_child = test.mock_device.build_test_child_device({ + profile = t_utils.get_profile_definition("thermostat-resideo-dt300st-m000.yml"), + device_network_id = string.format("%04X:%02X", mock_device:get_short_address(), 6), + parent_device_id = mock_device.id, + parent_assigned_child_key = string.format("%02X", 6) +}) + +zigbee_test_utils.prepare_zigbee_env_info() +local function test_init() + test.mock_device.add_test_device(mock_device) + test.mock_device.add_test_device(mock_first_child) + test.mock_device.add_test_device(mock_second_child) + test.mock_device.add_test_device(mock_third_child) + test.mock_device.add_test_device(mock_forth_child) + test.mock_device.add_test_device(mock_fifth_child) + zigbee_test_utils.init_noop_health_check_timer() +end + +test.set_test_init_function(test_init) + +test.register_coroutine_test("Configure should configure all necessary attributes", function() + test.socket.zigbee:__set_channel_ordering("relaxed") + test.socket.device_lifecycle:__queue_receive({mock_device.id, "doConfigure"}) + for endpoint = 1, 6 do + test.socket.zigbee:__expect_send({mock_device.id, + zigbee_test_utils.build_bind_request(mock_device, zigbee_test_utils.mock_hub_eui, + Thermostat.ID, endpoint)}) + end + + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.OccupiedHeatingSetpoint:configure_reporting(mock_device, 20, + 300, 100)}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.LocalTemperature:configure_reporting(mock_device, 20, 300, 100)}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.ThermostatRunningState:configure_reporting(mock_device, 20, + 300)}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.SystemMode:configure_reporting(mock_device, 20, 300)}) + + local attributes = {Thermostat.attributes.OccupiedHeatingSetpoint, Thermostat.attributes.LocalTemperature, + Thermostat.attributes.ControlSequenceOfOperation, Thermostat.attributes.ThermostatRunningState, + Thermostat.attributes.SystemMode} + for _, attribute in pairs(attributes) do + test.socket.zigbee:__expect_send({mock_device.id, attribute:read(mock_device)}) + end + mock_device:expect_metadata_update({ + provisioning_state = "PROVISIONED" + }) +end) + +-------------------------------------------------------------------------------- +-- Parent thermostat device + +test.register_coroutine_test("Refresh should read all necessary attributes", function() + test.socket.zigbee:__set_channel_ordering("relaxed") + test.socket.capability:__queue_receive({mock_device.id, { + capability = "refresh", + component = "main", + command = "refresh", + args = {} + }}) + local attributes = {Thermostat.attributes.OccupiedHeatingSetpoint, Thermostat.attributes.LocalTemperature, + Thermostat.attributes.ControlSequenceOfOperation, Thermostat.attributes.ThermostatRunningState, + Thermostat.attributes.SystemMode} + for _, attribute in pairs(attributes) do + test.socket.zigbee:__expect_send({mock_device.id, attribute:read(mock_device)}) + end +end) + +test.register_coroutine_test("Temperature reporting should create the appropriate events", function() + test.socket.zigbee:__queue_receive({mock_device.id, + Thermostat.attributes.LocalTemperature:build_test_attr_report(mock_device, 2100)}) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.temperatureMeasurement.temperature({ + value = 21.0, + unit = "C" + }))) +end) + +test.register_coroutine_test("Thermostat mode reporting should create the appropriate events", function() + test.socket.zigbee:__queue_receive({mock_device.id, + Thermostat.attributes.SystemMode:build_test_attr_report(mock_device, + Thermostat.attributes.SystemMode.OFF)}) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.thermostatMode + .thermostatMode.away())) + test.socket.zigbee:__queue_receive({mock_device.id, + Thermostat.attributes.SystemMode:build_test_attr_report(mock_device, + Thermostat.attributes.SystemMode.HEAT)}) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.thermostatMode + .thermostatMode.heat())) +end) + +test.register_coroutine_test("ControlSequenceOfOperation reporting should create the appropriate events", function() + test.socket.zigbee:__queue_receive({mock_device.id, + Thermostat.attributes.ControlSequenceOfOperation:build_test_attr_report( + mock_device, 0x02)}) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.thermostatMode.supportedThermostatModes({"away", "heat"}, { + visibility = { + displayed = false + } + }))) +end) + +test.register_coroutine_test("OccupiedHeatingSetpoint reporting shoulb create the appropriate events", function() + test.socket.zigbee:__queue_receive({mock_device.id, + Thermostat.attributes.OccupiedHeatingSetpoint:build_test_attr_report(mock_device, + 2100)}) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", + capabilities.thermostatHeatingSetpoint.heatingSetpoint({ + value = 21.0, + unit = "C" + }))) +end) + +test.register_coroutine_test("Setting the heating setpoint should generate the appropriate messages", function() + test.socket.capability:__queue_receive({mock_device.id, { + component = "main", + capability = capabilities.thermostatHeatingSetpoint.ID, + command = "setHeatingSetpoint", + args = {21} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.OccupiedHeatingSetpoint:write(mock_device, 2100)}) +end) + +test.register_coroutine_test("Setting the thermostat mode to away should generate the appropriate messages", function() + test.socket.capability:__queue_receive({mock_device.id, { + component = "main", + capability = capabilities.thermostatMode.ID, + command = "setThermostatMode", + args = {"away"} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.SystemMode:write(mock_device, + Thermostat.attributes.SystemMode.OFF)}) +end) + +test.register_coroutine_test("Setting the thermostat mode to heat should generate the appropriate messages", function() + test.socket.capability:__queue_receive({mock_device.id, { + component = "main", + capability = capabilities.thermostatMode.ID, + command = "heat", + args = {} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.SystemMode:write(mock_device, + Thermostat.attributes.SystemMode.HEAT)}) +end) + +-------------------------------------------------------------------------------- +-- First child thermostat device + +test.register_coroutine_test("Refresh should read all necessary attributes with first child device", function() + test.socket.zigbee:__set_channel_ordering("relaxed") + test.socket.capability:__queue_receive({mock_first_child.id, { + capability = "refresh", + component = "main", + command = "refresh", + args = {} + }}) + local attributes = {Thermostat.attributes.OccupiedHeatingSetpoint, Thermostat.attributes.LocalTemperature, + Thermostat.attributes.ControlSequenceOfOperation, Thermostat.attributes.ThermostatRunningState, + Thermostat.attributes.SystemMode} + for _, attribute in pairs(attributes) do + test.socket.zigbee:__expect_send({mock_device.id, attribute:read(mock_first_child)}) + end +end) + +test.register_coroutine_test("Temperature reporting should create the appropriate events with first child device", function() + test.socket.zigbee:__queue_receive({mock_first_child.id, + Thermostat.attributes.LocalTemperature:build_test_attr_report(mock_first_child, 2100)}) + test.socket.capability:__expect_send(mock_first_child:generate_test_message("main", + capabilities.temperatureMeasurement.temperature({ + value = 21.0, + unit = "C" + }))) +end) + +test.register_coroutine_test("Thermostat mode reporting should create the appropriate events with first child device", function() + test.socket.zigbee:__queue_receive({mock_first_child.id, + Thermostat.attributes.SystemMode:build_test_attr_report(mock_first_child, + Thermostat.attributes.SystemMode.OFF)}) + test.socket.capability:__expect_send(mock_first_child:generate_test_message("main", capabilities.thermostatMode + .thermostatMode.away())) + test.socket.zigbee:__queue_receive({mock_first_child.id, + Thermostat.attributes.SystemMode:build_test_attr_report(mock_first_child, + Thermostat.attributes.SystemMode.HEAT)}) + test.socket.capability:__expect_send(mock_first_child:generate_test_message("main", capabilities.thermostatMode + .thermostatMode.heat())) +end) + +test.register_coroutine_test("ControlSequenceOfOperation reporting should create the appropriate events with first child device", function() + test.socket.zigbee:__queue_receive({mock_first_child.id, + Thermostat.attributes.ControlSequenceOfOperation:build_test_attr_report( + mock_first_child, 0x02)}) + test.socket.capability:__expect_send(mock_first_child:generate_test_message("main", + capabilities.thermostatMode.supportedThermostatModes({"away", "heat"}, { + visibility = { + displayed = false + } + }))) +end) + +test.register_coroutine_test("OccupiedHeatingSetpoint reporting shoulb create the appropriate events with first child device", function() + test.socket.zigbee:__queue_receive({mock_first_child.id, + Thermostat.attributes.OccupiedHeatingSetpoint:build_test_attr_report(mock_first_child, + 2100)}) + test.socket.capability:__expect_send(mock_first_child:generate_test_message("main", + capabilities.thermostatHeatingSetpoint.heatingSetpoint({ + value = 21.0, + unit = "C" + }))) +end) + +test.register_coroutine_test("Setting the heating setpoint should generate the appropriate messages with first child device", function() + test.socket.capability:__queue_receive({mock_first_child.id, { + component = "main", + capability = capabilities.thermostatHeatingSetpoint.ID, + command = "setHeatingSetpoint", + args = {21} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.OccupiedHeatingSetpoint:write(mock_first_child, 2100)}) +end) + +test.register_coroutine_test("Setting the thermostat mode to away should generate the appropriate messages with first child device", function() + test.socket.capability:__queue_receive({mock_first_child.id, { + component = "main", + capability = capabilities.thermostatMode.ID, + command = "setThermostatMode", + args = {"away"} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.SystemMode:write(mock_first_child, + Thermostat.attributes.SystemMode.OFF)}) +end) + +test.register_coroutine_test("Setting the thermostat mode to heat should generate the appropriate messages with first child device", function() + test.socket.capability:__queue_receive({mock_first_child.id, { + component = "main", + capability = capabilities.thermostatMode.ID, + command = "heat", + args = {} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.SystemMode:write(mock_first_child, + Thermostat.attributes.SystemMode.HEAT)}) +end) + +-------------------------------------------------------------------------------- +-- Second child thermostat device + +test.register_coroutine_test("Refresh should read all necessary attributes with second child device", function() + test.socket.zigbee:__set_channel_ordering("relaxed") + test.socket.capability:__queue_receive({mock_second_child.id, { + capability = "refresh", + component = "main", + command = "refresh", + args = {} + }}) + local attributes = {Thermostat.attributes.OccupiedHeatingSetpoint, Thermostat.attributes.LocalTemperature, + Thermostat.attributes.ControlSequenceOfOperation, Thermostat.attributes.ThermostatRunningState, + Thermostat.attributes.SystemMode} + for _, attribute in pairs(attributes) do + test.socket.zigbee:__expect_send({mock_device.id, attribute:read(mock_second_child)}) + end +end) + +test.register_coroutine_test("Temperature reporting should create the appropriate events with second child device", function() + test.socket.zigbee:__queue_receive({mock_second_child.id, + Thermostat.attributes.LocalTemperature:build_test_attr_report(mock_second_child, 2100)}) + test.socket.capability:__expect_send(mock_second_child:generate_test_message("main", + capabilities.temperatureMeasurement.temperature({ + value = 21.0, + unit = "C" + }))) +end) + +test.register_coroutine_test("Thermostat mode reporting should create the appropriate events with second child device", function() + test.socket.zigbee:__queue_receive({mock_second_child.id, + Thermostat.attributes.SystemMode:build_test_attr_report(mock_second_child, + Thermostat.attributes.SystemMode.OFF)}) + test.socket.capability:__expect_send(mock_second_child:generate_test_message("main", capabilities.thermostatMode + .thermostatMode.away())) + test.socket.zigbee:__queue_receive({mock_second_child.id, + Thermostat.attributes.SystemMode:build_test_attr_report(mock_second_child, + Thermostat.attributes.SystemMode.HEAT)}) + test.socket.capability:__expect_send(mock_second_child:generate_test_message("main", capabilities.thermostatMode + .thermostatMode.heat())) +end) + +test.register_coroutine_test("ControlSequenceOfOperation reporting should create the appropriate events with second child device", function() + test.socket.zigbee:__queue_receive({mock_second_child.id, + Thermostat.attributes.ControlSequenceOfOperation:build_test_attr_report( + mock_second_child, 0x02)}) + test.socket.capability:__expect_send(mock_second_child:generate_test_message("main", + capabilities.thermostatMode.supportedThermostatModes({"away", "heat"}, { + visibility = { + displayed = false + } + }))) +end) + +test.register_coroutine_test("OccupiedHeatingSetpoint reporting shoulb create the appropriate events with second child device", function() + test.socket.zigbee:__queue_receive({mock_second_child.id, + Thermostat.attributes.OccupiedHeatingSetpoint:build_test_attr_report(mock_second_child, + 2100)}) + test.socket.capability:__expect_send(mock_second_child:generate_test_message("main", + capabilities.thermostatHeatingSetpoint.heatingSetpoint({ + value = 21.0, + unit = "C" + }))) +end) + +test.register_coroutine_test("Setting the heating setpoint should generate the appropriate messages with second child device", function() + test.socket.capability:__queue_receive({mock_second_child.id, { + component = "main", + capability = capabilities.thermostatHeatingSetpoint.ID, + command = "setHeatingSetpoint", + args = {21} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.OccupiedHeatingSetpoint:write(mock_second_child, 2100)}) +end) + +test.register_coroutine_test("Setting the thermostat mode to away should generate the appropriate messages with second child device", function() + test.socket.capability:__queue_receive({mock_second_child.id, { + component = "main", + capability = capabilities.thermostatMode.ID, + command = "setThermostatMode", + args = {"away"} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.SystemMode:write(mock_second_child, + Thermostat.attributes.SystemMode.OFF)}) +end) + +test.register_coroutine_test("Setting the thermostat mode to heat should generate the appropriate messages with second child device", function() + test.socket.capability:__queue_receive({mock_second_child.id, { + component = "main", + capability = capabilities.thermostatMode.ID, + command = "heat", + args = {} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.SystemMode:write(mock_second_child, + Thermostat.attributes.SystemMode.HEAT)}) +end) + +-------------------------------------------------------------------------------- +-- Third child thermostat device + +test.register_coroutine_test("Refresh should read all necessary attributes with third child device", function() + test.socket.zigbee:__set_channel_ordering("relaxed") + test.socket.capability:__queue_receive({mock_third_child.id, { + capability = "refresh", + component = "main", + command = "refresh", + args = {} + }}) + local attributes = {Thermostat.attributes.OccupiedHeatingSetpoint, Thermostat.attributes.LocalTemperature, + Thermostat.attributes.ControlSequenceOfOperation, Thermostat.attributes.ThermostatRunningState, + Thermostat.attributes.SystemMode} + for _, attribute in pairs(attributes) do + test.socket.zigbee:__expect_send({mock_device.id, attribute:read(mock_third_child)}) + end +end) + +test.register_coroutine_test("Temperature reporting should create the appropriate events with third child device", function() + test.socket.zigbee:__queue_receive({mock_third_child.id, + Thermostat.attributes.LocalTemperature:build_test_attr_report(mock_third_child, 2100)}) + test.socket.capability:__expect_send(mock_third_child:generate_test_message("main", + capabilities.temperatureMeasurement.temperature({ + value = 21.0, + unit = "C" + }))) +end) + +test.register_coroutine_test("Thermostat mode reporting should create the appropriate events with third child device", function() + test.socket.zigbee:__queue_receive({mock_third_child.id, + Thermostat.attributes.SystemMode:build_test_attr_report(mock_third_child, + Thermostat.attributes.SystemMode.OFF)}) + test.socket.capability:__expect_send(mock_third_child:generate_test_message("main", capabilities.thermostatMode + .thermostatMode.away())) + test.socket.zigbee:__queue_receive({mock_third_child.id, + Thermostat.attributes.SystemMode:build_test_attr_report(mock_third_child, + Thermostat.attributes.SystemMode.HEAT)}) + test.socket.capability:__expect_send(mock_third_child:generate_test_message("main", capabilities.thermostatMode + .thermostatMode.heat())) +end) + +test.register_coroutine_test("ControlSequenceOfOperation reporting should create the appropriate events with third child device", function() + test.socket.zigbee:__queue_receive({mock_third_child.id, + Thermostat.attributes.ControlSequenceOfOperation:build_test_attr_report( + mock_third_child, 0x02)}) + test.socket.capability:__expect_send(mock_third_child:generate_test_message("main", + capabilities.thermostatMode.supportedThermostatModes({"away", "heat"}, { + visibility = { + displayed = false + } + }))) +end) + +test.register_coroutine_test("OccupiedHeatingSetpoint reporting shoulb create the appropriate events with third child device", function() + test.socket.zigbee:__queue_receive({mock_third_child.id, + Thermostat.attributes.OccupiedHeatingSetpoint:build_test_attr_report(mock_third_child, + 2100)}) + test.socket.capability:__expect_send(mock_third_child:generate_test_message("main", + capabilities.thermostatHeatingSetpoint.heatingSetpoint({ + value = 21.0, + unit = "C" + }))) +end) + +test.register_coroutine_test("Setting the heating setpoint should generate the appropriate messages with third child device", function() + test.socket.capability:__queue_receive({mock_third_child.id, { + component = "main", + capability = capabilities.thermostatHeatingSetpoint.ID, + command = "setHeatingSetpoint", + args = {21} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.OccupiedHeatingSetpoint:write(mock_third_child, 2100)}) +end) + +test.register_coroutine_test("Setting the thermostat mode to away should generate the appropriate messages with third child device", function() + test.socket.capability:__queue_receive({mock_third_child.id, { + component = "main", + capability = capabilities.thermostatMode.ID, + command = "setThermostatMode", + args = {"away"} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.SystemMode:write(mock_third_child, + Thermostat.attributes.SystemMode.OFF)}) +end) + +test.register_coroutine_test("Setting the thermostat mode to heat should generate the appropriate messages with third child device", function() + test.socket.capability:__queue_receive({mock_third_child.id, { + component = "main", + capability = capabilities.thermostatMode.ID, + command = "heat", + args = {} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.SystemMode:write(mock_third_child, + Thermostat.attributes.SystemMode.HEAT)}) +end) + +-------------------------------------------------------------------------------- +-- Forth child thermostat device + +test.register_coroutine_test("Refresh should read all necessary attributes with forth child device", function() + test.socket.zigbee:__set_channel_ordering("relaxed") + test.socket.capability:__queue_receive({mock_forth_child.id, { + capability = "refresh", + component = "main", + command = "refresh", + args = {} + }}) + local attributes = {Thermostat.attributes.OccupiedHeatingSetpoint, Thermostat.attributes.LocalTemperature, + Thermostat.attributes.ControlSequenceOfOperation, Thermostat.attributes.ThermostatRunningState, + Thermostat.attributes.SystemMode} + for _, attribute in pairs(attributes) do + test.socket.zigbee:__expect_send({mock_device.id, attribute:read(mock_forth_child)}) + end +end) + +test.register_coroutine_test("Temperature reporting should create the appropriate events with forth child device", function() + test.socket.zigbee:__queue_receive({mock_forth_child.id, + Thermostat.attributes.LocalTemperature:build_test_attr_report(mock_forth_child, 2100)}) + test.socket.capability:__expect_send(mock_forth_child:generate_test_message("main", + capabilities.temperatureMeasurement.temperature({ + value = 21.0, + unit = "C" + }))) +end) + +test.register_coroutine_test("Thermostat mode reporting should create the appropriate events with forth child device", function() + test.socket.zigbee:__queue_receive({mock_forth_child.id, + Thermostat.attributes.SystemMode:build_test_attr_report(mock_forth_child, + Thermostat.attributes.SystemMode.OFF)}) + test.socket.capability:__expect_send(mock_forth_child:generate_test_message("main", capabilities.thermostatMode + .thermostatMode.away())) + test.socket.zigbee:__queue_receive({mock_forth_child.id, + Thermostat.attributes.SystemMode:build_test_attr_report(mock_forth_child, + Thermostat.attributes.SystemMode.HEAT)}) + test.socket.capability:__expect_send(mock_forth_child:generate_test_message("main", capabilities.thermostatMode + .thermostatMode.heat())) +end) + +test.register_coroutine_test("ControlSequenceOfOperation reporting should create the appropriate events with forth child device", function() + test.socket.zigbee:__queue_receive({mock_forth_child.id, + Thermostat.attributes.ControlSequenceOfOperation:build_test_attr_report( + mock_forth_child, 0x02)}) + test.socket.capability:__expect_send(mock_forth_child:generate_test_message("main", + capabilities.thermostatMode.supportedThermostatModes({"away", "heat"}, { + visibility = { + displayed = false + } + }))) +end) + +test.register_coroutine_test("OccupiedHeatingSetpoint reporting shoulb create the appropriate events with forth child device", function() + test.socket.zigbee:__queue_receive({mock_forth_child.id, + Thermostat.attributes.OccupiedHeatingSetpoint:build_test_attr_report(mock_forth_child, + 2100)}) + test.socket.capability:__expect_send(mock_forth_child:generate_test_message("main", + capabilities.thermostatHeatingSetpoint.heatingSetpoint({ + value = 21.0, + unit = "C" + }))) +end) + +test.register_coroutine_test("Setting the heating setpoint should generate the appropriate messages with forth child device", function() + test.socket.capability:__queue_receive({mock_forth_child.id, { + component = "main", + capability = capabilities.thermostatHeatingSetpoint.ID, + command = "setHeatingSetpoint", + args = {21} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.OccupiedHeatingSetpoint:write(mock_forth_child, 2100)}) +end) + +test.register_coroutine_test("Setting the thermostat mode to away should generate the appropriate messages with forth child device", function() + test.socket.capability:__queue_receive({mock_forth_child.id, { + component = "main", + capability = capabilities.thermostatMode.ID, + command = "setThermostatMode", + args = {"away"} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.SystemMode:write(mock_forth_child, + Thermostat.attributes.SystemMode.OFF)}) +end) + +test.register_coroutine_test("Setting the thermostat mode to heat should generate the appropriate messages with forth child device", function() + test.socket.capability:__queue_receive({mock_forth_child.id, { + component = "main", + capability = capabilities.thermostatMode.ID, + command = "heat", + args = {} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.SystemMode:write(mock_forth_child, + Thermostat.attributes.SystemMode.HEAT)}) +end) + +-------------------------------------------------------------------------------- +-- Fifth child thermostat device + +test.register_coroutine_test("Refresh should read all necessary attributes with fifth child device", function() + test.socket.zigbee:__set_channel_ordering("relaxed") + test.socket.capability:__queue_receive({mock_fifth_child.id, { + capability = "refresh", + component = "main", + command = "refresh", + args = {} + }}) + local attributes = {Thermostat.attributes.OccupiedHeatingSetpoint, Thermostat.attributes.LocalTemperature, + Thermostat.attributes.ControlSequenceOfOperation, Thermostat.attributes.ThermostatRunningState, + Thermostat.attributes.SystemMode} + for _, attribute in pairs(attributes) do + test.socket.zigbee:__expect_send({mock_device.id, attribute:read(mock_fifth_child)}) + end +end) + +test.register_coroutine_test("Temperature reporting should create the appropriate events with fifth child device", function() + test.socket.zigbee:__queue_receive({mock_fifth_child.id, + Thermostat.attributes.LocalTemperature:build_test_attr_report(mock_fifth_child, 2100)}) + test.socket.capability:__expect_send(mock_fifth_child:generate_test_message("main", + capabilities.temperatureMeasurement.temperature({ + value = 21.0, + unit = "C" + }))) +end) + +test.register_coroutine_test("Thermostat mode reporting should create the appropriate events with fifth child device", function() + test.socket.zigbee:__queue_receive({mock_fifth_child.id, + Thermostat.attributes.SystemMode:build_test_attr_report(mock_fifth_child, + Thermostat.attributes.SystemMode.OFF)}) + test.socket.capability:__expect_send(mock_fifth_child:generate_test_message("main", capabilities.thermostatMode + .thermostatMode.away())) + test.socket.zigbee:__queue_receive({mock_fifth_child.id, + Thermostat.attributes.SystemMode:build_test_attr_report(mock_fifth_child, + Thermostat.attributes.SystemMode.HEAT)}) + test.socket.capability:__expect_send(mock_fifth_child:generate_test_message("main", capabilities.thermostatMode + .thermostatMode.heat())) +end) + +test.register_coroutine_test("ControlSequenceOfOperation reporting should create the appropriate events with fifth child device", function() + test.socket.zigbee:__queue_receive({mock_fifth_child.id, + Thermostat.attributes.ControlSequenceOfOperation:build_test_attr_report( + mock_fifth_child, 0x02)}) + test.socket.capability:__expect_send(mock_fifth_child:generate_test_message("main", + capabilities.thermostatMode.supportedThermostatModes({"away", "heat"}, { + visibility = { + displayed = false + } + }))) +end) + +test.register_coroutine_test("OccupiedHeatingSetpoint reporting shoulb create the appropriate events with fifth child device", function() + test.socket.zigbee:__queue_receive({mock_fifth_child.id, + Thermostat.attributes.OccupiedHeatingSetpoint:build_test_attr_report(mock_fifth_child, + 2100)}) + test.socket.capability:__expect_send(mock_fifth_child:generate_test_message("main", + capabilities.thermostatHeatingSetpoint.heatingSetpoint({ + value = 21.0, + unit = "C" + }))) +end) + +test.register_coroutine_test("Setting the heating setpoint should generate the appropriate messages with fifth child device", function() + test.socket.capability:__queue_receive({mock_fifth_child.id, { + component = "main", + capability = capabilities.thermostatHeatingSetpoint.ID, + command = "setHeatingSetpoint", + args = {21} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.OccupiedHeatingSetpoint:write(mock_fifth_child, 2100)}) +end) + +test.register_coroutine_test("Setting the thermostat mode to away should generate the appropriate messages with fifth child device", function() + test.socket.capability:__queue_receive({mock_fifth_child.id, { + component = "main", + capability = capabilities.thermostatMode.ID, + command = "setThermostatMode", + args = {"away"} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.SystemMode:write(mock_fifth_child, + Thermostat.attributes.SystemMode.OFF)}) +end) + +test.register_coroutine_test("Setting the thermostat mode to heat should generate the appropriate messages with fifth child device", function() + test.socket.capability:__queue_receive({mock_fifth_child.id, { + component = "main", + capability = capabilities.thermostatMode.ID, + command = "heat", + args = {} + }}) + test.socket.zigbee:__expect_send({mock_device.id, + Thermostat.attributes.SystemMode:write(mock_fifth_child, + Thermostat.attributes.SystemMode.HEAT)}) +end) + + +test.run_registered_tests() From 0b18e67da35aa8b002ff3e204b77e2191554aa60 Mon Sep 17 00:00:00 2001 From: kdbang Date: Fri, 8 Mar 2024 00:07:45 +0900 Subject: [PATCH 6/6] Cannot onboading JBL 300 (#1261) Signed-off-by: Keuckdo Bang --- drivers/SmartThings/jbl/src/lunchbox/rest.lua | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/SmartThings/jbl/src/lunchbox/rest.lua b/drivers/SmartThings/jbl/src/lunchbox/rest.lua index 1128dd7f96..f3db77745b 100644 --- a/drivers/SmartThings/jbl/src/lunchbox/rest.lua +++ b/drivers/SmartThings/jbl/src/lunchbox/rest.lua @@ -144,6 +144,38 @@ local function parse_chunked_response(original_response, sock) return full_response end +local function recv_additional_response(original_response, sock) + local full_response = Response.new(original_response.status, nil) + local headers = original_response:get_headers() + local content_length_str = headers:get_one("Content-Length") + local content_length = nil + local bytes_read = 0 + if content_length_str then + content_length = math.tointeger(content_length_str) + end + + local next_recv, next_err, partial + + repeat + next_recv, next_err, partial = sock:receive(content_length - bytes_read) + + if next_recv ~= nil and #next_recv >= 1 then + full_response:append_body(next_recv) + bytes_read = bytes_read + #next_recv + end + + if partial ~= nil and #partial >= 1 then + full_response:append_body(partial) + bytes_read = bytes_read + #partial + end + until next_err == "closed" or bytes_read >= content_length + + full_response._received_body = true + full_response._parsed_headers = true + + return full_response +end + local function handle_response(sock) if api_version >= 9 then local response, err = Response.tcp_source(sock) @@ -158,7 +190,9 @@ local function handle_response(sock) if initial_recv ~= nil then local headers = initial_recv:get_headers() - if headers and headers:get_one("Transfer-Encoding") == "chunked" then + if headers:get_one("Content-Length") then + full_response = recv_additional_response(initial_recv, sock) + elseif headers and headers:get_one("Transfer-Encoding") == "chunked" then local response, err = parse_chunked_response(initial_recv, sock) if err ~= nil then return nil, err