Skip to content

Commit

Permalink
Merge pull request #1525 from SmartThingsCommunity/main
Browse files Browse the repository at this point in the history
rolling up main to beta
  • Loading branch information
ctowns authored Jul 15, 2024
2 parents e581fc1 + 58c4755 commit 7f53247
Show file tree
Hide file tree
Showing 42 changed files with 1,092 additions and 10 deletions.
6 changes: 6 additions & 0 deletions drivers/SmartThings/matter-sensor/fingerprints.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ matterManufacturer:
vendorId: 0x141E
productId: 0x0002
deviceProfileName: contact-battery
# LeTianpai
- id: "LeTianPai/Motion"
deviceLabel: LeTianPai Presence Sensor Box
vendorId: 0x142B
productId: 0x0002
deviceProfileName: motion-illuminance-temperature-humidity
matterGeneric:
- id: "matter/contact/sensor"
deviceLabel: Matter Contact Sensor
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: motion-illuminance-temperature-humidity
components:
- id: main
capabilities:
- id: motionSensor
version: 1
- id: temperatureMeasurement
version: 1
- id: relativeHumidityMeasurement
version: 1
- id: illuminanceMeasurement
version: 1
- id: firmwareUpdate
version: 1
- id: refresh
version: 1
categories:
- name: MotionSensor
preferences:
- preferenceId: tempOffset
explicit: true
- preferenceId: humidityOffset
explicit: true
5 changes: 5 additions & 0 deletions drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ local function info_changed(self, device, event, args)
end
end
end

-- resubscribe to new attributes as needed if a profile switch occured
if device.profile.id ~= args.old_st_store.profile.id then
device:subscribe()
end
end

-- Matter Handlers --
Expand Down
47 changes: 47 additions & 0 deletions drivers/SmartThings/zigbee-button/src/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ local ZigbeeDriver = require "st.zigbee"
local defaults = require "st.zigbee.defaults"
local constants = require "st.zigbee.constants"
local IASZone = (require "st.zigbee.zcl.clusters").IASZone
local TemperatureMeasurement = (require "st.zigbee.zcl.clusters").TemperatureMeasurement

local temperature_measurement_defaults = {
MIN_TEMP = "MIN_TEMP",
MAX_TEMP = "MAX_TEMP"
}

local generate_event_from_zone_status = function(driver, device, zone_status, zb_rx)
local event
Expand Down Expand Up @@ -65,10 +71,47 @@ local ias_zone_status_change_handler = function(driver, device, zb_rx)
generate_event_from_zone_status(driver, device, zb_rx.body.zcl_body.zone_status, zb_rx)
end

--- Default handler for Temperature min and max measured value on the Temperature measurement cluster
---
--- This starts initially by performing the same conversion in the temperature_measurement_attr_handler function.
--- It then sets the field of whichever measured value is defined by the @param and checks if the fields
--- correctly compare
---
--- @param minOrMax string the string that determines which attribute to set
--- @param driver Driver The current driver running containing necessary context for execution
--- @param device ZigbeeDevice The device this message was received from containing identifying information
--- @param value Int16 the value of the measured temperature
--- @param zb_rx containing the full message this report came in

local temperature_measurement_min_max_attr_handler = function(minOrMax)
return function(driver, device, value, zb_rx)
local raw_temp = value.value
local celc_temp = raw_temp / 100.0
local temp_scale = "C"

device:set_field(string.format("%s", minOrMax), celc_temp)

local min = device:get_field(temperature_measurement_defaults.MIN_TEMP)
local max = device:get_field(temperature_measurement_defaults.MAX_TEMP)

if min ~= nil and max ~= nil then
if min < max then
device:emit_event_for_endpoint(zb_rx.address_header.src_endpoint.value, capabilities.temperatureMeasurement.temperatureRange({ value = { minimum = min, maximum = max }, unit = temp_scale }))
device:set_field(temperature_measurement_defaults.MIN_TEMP, nil)
device:set_field(temperature_measurement_defaults.MAX_TEMP, nil)
else
device.log.warn_with({hub_logs = true}, string.format("Device reported a min temperature %d that is not lower than the reported max temperature %d", min, max))
end
end
end
end

local function added_handler(self, device)
device:emit_event(capabilities.button.supportedButtonValues({"pushed","held","double"}, {visibility = { displayed = false }}))
device:emit_event(capabilities.button.numberOfButtons({value = 1}, {visibility = { displayed = false }}))
device:emit_event(capabilities.button.button.pushed({state_change = false}))
device:send(TemperatureMeasurement.attributes.MaxMeasuredValue:read(device))
device:send(TemperatureMeasurement.attributes.MinMeasuredValue:read(device))
end

local zigbee_button_driver_template = {
Expand All @@ -81,6 +124,10 @@ local zigbee_button_driver_template = {
attr = {
[IASZone.ID] = {
[IASZone.attributes.ZoneStatus.ID] = ias_zone_status_attr_handler
},
[TemperatureMeasurement.ID] = {
[TemperatureMeasurement.attributes.MinMeasuredValue.ID] = temperature_measurement_min_max_attr_handler(temperature_measurement_defaults.MIN_TEMP),
[TemperatureMeasurement.attributes.MaxMeasuredValue.ID] = temperature_measurement_min_max_attr_handler(temperature_measurement_defaults.MAX_TEMP),
}
},
cluster = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ local zigbee_test_utils = require "integration_test.zigbee_test_utils"

local OnOff = clusters.OnOff
local PowerConfiguration = clusters.PowerConfiguration
local TemperatureMeasurement = clusters.TemperatureMeasurement

local button = capabilities.button

Expand Down Expand Up @@ -64,6 +65,14 @@ test.register_coroutine_test(
test.socket.capability:__expect_send(
mock_device:generate_test_message("main", button.button.pushed({ state_change = false }))
)
test.socket.zigbee:__expect_send({
mock_device.id,
TemperatureMeasurement.attributes.MaxMeasuredValue:read(mock_device)
})
test.socket.zigbee:__expect_send({
mock_device.id,
TemperatureMeasurement.attributes.MinMeasuredValue:read(mock_device)
})
end
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ test.register_coroutine_test(
attribute_id = "button", state = { value = "pushed" }
}
})
test.socket.zigbee:__expect_send({
mock_device.id,
TemperatureMeasurement.attributes.MaxMeasuredValue:read(mock_device)
})
test.socket.zigbee:__expect_send({
mock_device.id,
TemperatureMeasurement.attributes.MinMeasuredValue:read(mock_device)
})
-- test.socket.zigbee:__expect_send({
-- mock_device.id,
-- PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ local test = require "integration_test"
local clusters = require "st.zigbee.zcl.clusters"
local IASZone = clusters.IASZone
local PowerConfiguration = clusters.PowerConfiguration
local TemperatureMeasurement = clusters.TemperatureMeasurement
local capabilities = require "st.capabilities"
local zigbee_test_utils = require "integration_test.zigbee_test_utils"
local IasEnrollResponseCode = require "st.zigbee.generated.zcl_clusters.IASZone.types.EnrollResponseCode"
Expand All @@ -26,7 +27,7 @@ local ZoneStatusAttribute = IASZone.attributes.ZoneStatus
local button_attr = capabilities.button.button

local mock_device = test.mock_device.build_test_zigbee_device(
{ profile = t_utils.get_profile_definition("button-profile.yml") }
{ profile = t_utils.get_profile_definition("one-button-temp-battery.yml") }
)
zigbee_test_utils.prepare_zigbee_env_info()
local function test_init()
Expand Down Expand Up @@ -159,6 +160,46 @@ test.register_message_test(
}
)

test.register_message_test(
"Temperature report should be handled (C)",
{
{
channel = "zigbee",
direction = "receive",
message = { mock_device.id, TemperatureMeasurement.attributes.MeasuredValue:build_test_attr_report(mock_device, 2500)
}
},
{
channel = "capability",
direction = "send",
message = mock_device:generate_test_message("main", capabilities.temperatureMeasurement.temperature({ value = 25.0, unit = "C"}))
}
}
)

test.register_message_test(
"Minimum & Maximum Temperature report should be handled (C)",
{
{
channel = "zigbee",
direction = "receive",
message = { mock_device.id, TemperatureMeasurement.attributes.MinMeasuredValue:build_test_attr_report(mock_device, 2000)
}
},
{
channel = "zigbee",
direction = "receive",
message = { mock_device.id, TemperatureMeasurement.attributes.MaxMeasuredValue:build_test_attr_report(mock_device, 3000)
}
},
{
channel = "capability",
direction = "send",
message = mock_device:generate_test_message("main", capabilities.temperatureMeasurement.temperatureRange({ value = { minimum = 20.00, maximum = 30.00 }, unit = "C" }))
}
}
)

test.register_coroutine_test(
"Health check should check all relevant attributes",
function()
Expand All @@ -182,6 +223,14 @@ test.register_coroutine_test(
attribute_id = "button", state = { value = "pushed" }
}
})
test.socket.zigbee:__expect_send({
mock_device.id,
TemperatureMeasurement.attributes.MaxMeasuredValue:read(mock_device)
})
test.socket.zigbee:__expect_send({
mock_device.id,
TemperatureMeasurement.attributes.MinMeasuredValue:read(mock_device)
})
test.wait_for_events()

test.mock_time.advance_time(50000) -- Battery has a max reporting interval of 21600
Expand All @@ -192,6 +241,10 @@ test.register_coroutine_test(
PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device)
}
)
test.socket.zigbee:__expect_send({
mock_device.id,
TemperatureMeasurement.attributes.MeasuredValue:read(mock_device)
})
end,
{
test_init = function()
Expand All @@ -218,6 +271,12 @@ test.register_coroutine_test(
IASZone.attributes.ZoneStatus:read(mock_device)
}
)
test.socket.zigbee:__expect_send(
{
mock_device.id,
TemperatureMeasurement.attributes.MeasuredValue:read(mock_device)
}
)
end
)

Expand All @@ -237,6 +296,14 @@ test.register_coroutine_test(
1)
}
)
test.socket.zigbee:__expect_send({
mock_device.id,
TemperatureMeasurement.attributes.MeasuredValue:configure_reporting(mock_device,
30,
600,
100)
}
)
test.socket.zigbee:__expect_send(
{
mock_device.id,
Expand All @@ -245,6 +312,14 @@ test.register_coroutine_test(
PowerConfiguration.ID)
}
)
test.socket.zigbee:__expect_send(
{
mock_device.id,
zigbee_test_utils.build_bind_request(mock_device,
zigbee_test_utils.mock_hub_eui,
TemperatureMeasurement.ID)
}
)
test.socket.zigbee:__expect_send(
{
mock_device.id,
Expand All @@ -263,6 +338,12 @@ test.register_coroutine_test(
PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device)
}
)
test.socket.zigbee:__expect_send(
{
mock_device.id,
TemperatureMeasurement.attributes.MeasuredValue:read(mock_device)
}
)
test.socket.zigbee:__expect_send(
{
mock_device.id,
Expand Down
57 changes: 56 additions & 1 deletion drivers/SmartThings/zigbee-contact/src/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,50 @@ local capabilities = require "st.capabilities"
local ZigbeeDriver = require "st.zigbee"
local constants = require "st.zigbee.constants"
local defaults = require "st.zigbee.defaults"
local TemperatureMeasurement = (require "st.zigbee.zcl.clusters").TemperatureMeasurement
local configurationMap = require "configurations"
local SMARTSENSE_MULTI_SENSOR_CUSTOM_PROFILE = 0xFC01

local temperature_measurement_defaults = {
MIN_TEMP = "MIN_TEMP",
MAX_TEMP = "MAX_TEMP"
}

--- Default handler for Temperature min and max measured value on the Temperature measurement cluster
---
--- This starts initially by performing the same conversion in the temperature_measurement_attr_handler function.
--- It then sets the field of whichever measured value is defined by the @param and checks if the fields
--- correctly compare
---
--- @param minOrMax string the string that determines which attribute to set
--- @param driver Driver The current driver running containing necessary context for execution
--- @param device ZigbeeDevice The device this message was received from containing identifying information
--- @param value Int16 the value of the measured temperature
--- @param zb_rx containing the full message this report came in

local temperature_measurement_min_max_attr_handler = function(minOrMax)
return function(driver, device, value, zb_rx)
local raw_temp = value.value
local celc_temp = raw_temp / 100.0
local temp_scale = "C"

device:set_field(string.format("%s", minOrMax), celc_temp)

local min = device:get_field(temperature_measurement_defaults.MIN_TEMP)
local max = device:get_field(temperature_measurement_defaults.MAX_TEMP)

if min ~= nil and max ~= nil then
if min < max then
device:emit_event_for_endpoint(zb_rx.address_header.src_endpoint.value, capabilities.temperatureMeasurement.temperatureRange({ value = { minimum = min, maximum = max }, unit = temp_scale }))
device:set_field(temperature_measurement_defaults.MIN_TEMP, nil)
device:set_field(temperature_measurement_defaults.MAX_TEMP, nil)
else
device.log.warn_with({hub_logs = true}, string.format("Device reported a min temperature %d that is not lower than the reported max temperature %d", min, max))
end
end
end
end

local function device_init(driver, device)
local configuration = configurationMap.get_device_configuration(device)
if configuration ~= nil then
Expand All @@ -29,6 +70,11 @@ local function device_init(driver, device)
end
end

local function added_handler(driver, device)
device:send(TemperatureMeasurement.attributes.MaxMeasuredValue:read(device))
device:send(TemperatureMeasurement.attributes.MinMeasuredValue:read(device))
end

local zigbee_contact_driver_template = {
supported_capabilities = {
capabilities.contactSensor,
Expand All @@ -37,11 +83,20 @@ local zigbee_contact_driver_template = {
capabilities.threeAxis,
capabilities.accelerationSensor
},
zigbee_handlers = {
attr = {
[TemperatureMeasurement.ID] = {
[TemperatureMeasurement.attributes.MinMeasuredValue.ID] = temperature_measurement_min_max_attr_handler(temperature_measurement_defaults.MIN_TEMP),
[TemperatureMeasurement.attributes.MaxMeasuredValue.ID] = temperature_measurement_min_max_attr_handler(temperature_measurement_defaults.MAX_TEMP),
}
}
},
additional_zcl_profiles = {
[SMARTSENSE_MULTI_SENSOR_CUSTOM_PROFILE] = true
},
lifecycle_handlers = {
init = device_init
init = device_init,
added = added_handler,
},
sub_drivers = {
require("aqara"),
Expand Down
Loading

0 comments on commit 7f53247

Please sign in to comment.