Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Aqara Climate Sensor W100 #1843

Merged
merged 6 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
name: 3-button-battery-temperature-humidity
components:
- id: main
capabilities:
- id: temperatureMeasurement
version: 1
- id: relativeHumidityMeasurement
version: 1
- id: battery
version: 1
- id: firmwareUpdate
version: 1
- id: refresh
version: 1
categories:
- name: TempHumiditySensor
- id: button1
capabilities:
- id: button
version: 1
categories:
- name: RemoteController
- id: button2
capabilities:
- id: button
version: 1
categories:
- name: RemoteController
- id: button3
capabilities:
- id: button
version: 1
categories:
- name: RemoteController
preferences:
- preferenceId: tempOffset
explicit: true
- preferenceId: humidityOffset
explicit: true
deviceConfig:
dashboard:
states:
- component: main
capability: temperatureMeasurement
version: 1
group: main
composite: true
- component: main
capability: relativeHumidityMeasurement
version: 1
group: main
values:
- label: " {{humidity.value}} {{humidity.unit}}"
composite: true
actions: []
basicPlus: []
detailView:
- component: main
capability: temperatureMeasurement
version: 1
- component: main
capability: relativeHumidityMeasurement
version: 1
- component: main
capability: battery
version: 1
- component: main
capability: refresh
version: 1
- component: button1
capability: button
version: 1
- component: button2
capability: button
version: 1
- component: button3
capability: button
version: 1
automation:
conditions:
- component: main
capability: temperatureMeasurement
version: 1
- component: main
capability: relativeHumidityMeasurement
version: 1
- component: main
capability: battery
version: 1
- component: button1
capability: button
version: 1
- component: button2
capability: button
version: 1
- component: button3
capability: button
version: 1
actions: []
89 changes: 83 additions & 6 deletions drivers/SmartThings/matter-switch/src/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,10 @@ local EMULATE_HELD = "__emulate_held" -- for non-MSR (MomentarySwitchRelease) de
local SUPPORTS_MULTI_PRESS = "__multi_button" -- for MSM devices (MomentarySwitchMultiPress), create an event on receipt of MultiPressComplete
local INITIAL_PRESS_ONLY = "__initial_press_only" -- for devices that support MS (MomentarySwitch), but not MSR (MomentarySwitchRelease)

local TEMP_BOUND_RECEIVED = "__temp_bound_received"
local TEMP_MIN = "__temp_min"
local TEMP_MAX = "__temp_max"

local HUE_MANUFACTURER_ID = 0x100B
local AQARA_MANUFACTURER_ID = 0x115F

Expand Down Expand Up @@ -528,7 +532,7 @@ local function initialize_switch(driver, device)
table.sort(switch_eps)
table.sort(button_eps)

local profile_name = nil
local profile_name = ""

local component_map = {}
local component_map_used = false
Expand All @@ -539,7 +543,15 @@ local function initialize_switch(driver, device)
-- that have been implemented as server. This can be removed when we have
-- support for bindings.
local num_switch_server_eps = 0
local main_endpoint = find_default_endpoint(device)
local main_endpoint
local temperature_eps = device:get_endpoints(clusters.TemperatureMeasurement.ID)
local humidity_eps = device:get_endpoints(clusters.RelativeHumidityMeasurement.ID)
if #temperature_eps > 0 and #humidity_eps > 0 then
-- In case of Aqara Climate Sensor W100, in order to sequentially set the button name to button 1, 2, 3
main_endpoint = device.MATTER_DEFAULT_ENDPOINT
else
main_endpoint = find_default_endpoint(device)
end

-- If a switch endpoint is present, it will be the main endpoint and therefore the
-- main component. If button endpoints are present, they will be added as
Expand Down Expand Up @@ -613,17 +625,21 @@ local function initialize_switch(driver, device)
battery_support = true
end
if #button_eps > 1 and tbl_contains(STATIC_BUTTON_PROFILE_SUPPORTED, #button_eps) then
if #temperature_eps > 0 and #humidity_eps > 0 then
device.log.debug("So far, it means Aqara Climate Sensor W100.")
profile_name = "-temperature-humidity"
end
if battery_support then
profile_name = string.format("%d-button-battery", #button_eps)
profile_name = string.format("%d-button-battery", #button_eps) .. profile_name
else
profile_name = string.format("%d-button", #button_eps)
profile_name = string.format("%d-button", #button_eps) .. profile_name
end
elseif not battery_support then
-- a battery-less button/remote
profile_name = "button"
end

if profile_name then
if profile_name ~= "" then
device:try_update_metadata({profile = profile_name})
device:set_field(DEFERRED_CONFIGURE, true)
device:set_field(BUTTON_DEVICE_PROFILED, true)
Expand Down Expand Up @@ -1199,6 +1215,49 @@ local function device_added(driver, device)
device_init(driver, device)
end

local function temperature_attr_handler(driver, device, ib, response)
local measured_value = ib.data.value
if measured_value ~= nil then
local temp = measured_value / 100.0
local unit = "C"
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.temperatureMeasurement.temperature({value = temp, unit = unit}))
end
end

local temp_attr_handler_factory = function(minOrMax)
return function(driver, device, ib, response)
if ib.data.value == nil then
return
end
local temp = ib.data.value / 100.0
local unit = "C"
set_field_for_endpoint(device, TEMP_BOUND_RECEIVED..minOrMax, ib.endpoint_id, temp)
local min = get_field_for_endpoint(device, TEMP_BOUND_RECEIVED..TEMP_MIN, ib.endpoint_id)
local max = get_field_for_endpoint(device, TEMP_BOUND_RECEIVED..TEMP_MAX, ib.endpoint_id)
if min ~= nil and max ~= nil then
if min < max then
-- Only emit the capability for RPC version >= 5 (unit conversion for
-- temperature range capability is only supported for RPC >= 5)
if version.rpc >= 5 then
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.temperatureMeasurement.temperatureRange({ value = { minimum = min, maximum = max }, unit = unit }))
end
set_field_for_endpoint(device, TEMP_BOUND_RECEIVED..TEMP_MIN, ib.endpoint_id, nil)
set_field_for_endpoint(device, TEMP_BOUND_RECEIVED..TEMP_MAX, ib.endpoint_id, 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 humidity_attr_handler(driver, device, ib, response)
local measured_value = ib.data.value
if measured_value ~= nil then
local humidity = utils.round(measured_value / 100.0)
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.relativeHumidityMeasurement.humidity(humidity))
end
end

local matter_driver_template = {
lifecycle_handlers = {
init = device_init,
Expand Down Expand Up @@ -1249,6 +1308,14 @@ local matter_driver_template = {
},
[clusters.Switch.ID] = {
[clusters.Switch.attributes.MultiPressMax.ID] = max_press_handler
},
[clusters.RelativeHumidityMeasurement.ID] = {
[clusters.RelativeHumidityMeasurement.attributes.MeasuredValue.ID] = humidity_attr_handler
},
[clusters.TemperatureMeasurement.ID] = {
[clusters.TemperatureMeasurement.attributes.MeasuredValue.ID] = temperature_attr_handler,
[clusters.TemperatureMeasurement.attributes.MinMeasuredValue.ID] = temp_attr_handler_factory(TEMP_MIN),
[clusters.TemperatureMeasurement.attributes.MaxMeasuredValue.ID] = temp_attr_handler_factory(TEMP_MAX),
}
},
event = {
Expand Down Expand Up @@ -1302,6 +1369,14 @@ local matter_driver_template = {
},
[capabilities.powerMeter.ID] = {
clusters.ElectricalPowerMeasurement.attributes.ActivePower
},
[capabilities.relativeHumidityMeasurement.ID] = {
clusters.RelativeHumidityMeasurement.attributes.MeasuredValue
},
[capabilities.temperatureMeasurement.ID] = {
clusters.TemperatureMeasurement.attributes.MeasuredValue,
clusters.TemperatureMeasurement.attributes.MinMeasuredValue,
clusters.TemperatureMeasurement.attributes.MaxMeasuredValue
}
},
subscribed_events = {
Expand Down Expand Up @@ -1352,7 +1427,9 @@ local matter_driver_template = {
capabilities.powerConsumptionReport,
capabilities.valve,
capabilities.button,
capabilities.battery
capabilities.battery,
capabilities.temperatureMeasurement,
capabilities.relativeHumidityMeasurement
},
sub_drivers = {
require("eve-energy"),
Expand Down
Loading
Loading