Skip to content

Commit a59d461

Browse files
committed
generic_zigbee_sensor_improvement
1 parent 9379c14 commit a59d461

File tree

8 files changed

+424
-54
lines changed

8 files changed

+424
-54
lines changed

drivers/SmartThings/zigbee-sensor/fingerprints.yml

+9-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,12 @@ zigbeeGeneric:
55
server:
66
- 0x0500
77
deviceProfileName: generic-sensor
8-
8+
- id: "generic-battery-sensor"
9+
deviceLabel: "Zigbee Generic Sensor"
10+
deviceIdentifiers:
11+
- 0x0402
12+
clusters:
13+
server:
14+
- 0x0500
15+
- 0x0001
16+
deviceProfileName: generic-sensor
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: generic-motion-illuminance
2+
components:
3+
- id: main
4+
capabilities:
5+
- id: motionSensor
6+
version: 1
7+
- id: illuminanceMeasurement
8+
version: 1
9+
config:
10+
values:
11+
- key: "illuminance.value"
12+
range: [0, 32000]
13+
- id: battery
14+
version: 1
15+
- id: firmwareUpdate
16+
version: 1
17+
- id: refresh
18+
version: 1
19+
categories:
20+
- name: MotionSensor
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
-- Copyright 2025 SmartThings
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- http://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
local defaults = require "st.zigbee.defaults"
16+
local capabilities = require "st.capabilities"
17+
18+
local is_contact_sensor = function(opts, driver, device)
19+
if device:supports_capability(capabilities.contactSensor) then
20+
return true
21+
end
22+
end
23+
24+
local generic_contact_sensor = {
25+
NAME = "Generic Contact Sensor",
26+
supported_capabilities = {
27+
capabilities.contactSensor
28+
},
29+
can_handle = is_contact_sensor
30+
}
31+
defaults.register_for_default_handlers(generic_contact_sensor, generic_contact_sensor.supported_capabilities)
32+
return generic_contact_sensor

drivers/SmartThings/zigbee-sensor/src/init.lua

+17-48
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ local capabilities = require "st.capabilities"
1919
local constants = require "st.zigbee.constants"
2020
local IasZoneType = require "st.zigbee.generated.types.IasZoneType"
2121
local device_management = require "st.zigbee.device_management"
22+
local PowerConfiguration = clusters.PowerConfiguration
2223

2324
local CONTACT_SWITCH = IasZoneType.CONTACT_SWITCH
2425
local MOTION_SENSOR = IasZoneType.MOTION_SENSOR
@@ -28,6 +29,7 @@ local ZIGBEE_GENERIC_SENSOR_PROFILE = "generic-sensor"
2829
local ZIGBEE_GENERIC_CONTACT_SENSOR_PROFILE = "generic-contact-sensor"
2930
local ZIGBEE_GENERIC_MOTION_SENSOR_PROFILE = "generic-motion-sensor"
3031
local ZIGBEE_GENERIC_WATERLEAK_SENSOR_PROFILE = "generic-waterleak-sensor"
32+
local ZIGBEE_GENERIC_MOTION_ILLUMINANCE_PROFILE = "generic-motion-illuminance"
3133

3234
local ZONETYPE = "ZoneType"
3335
local IASZone = clusters.IASZone
@@ -42,6 +44,7 @@ local do_configure = function(self, device)
4244
device:configure()
4345
device:send(device_management.build_bind_request(device, IASZone.ID, self.environment_info.hub_zigbee_eui))
4446
device:send(IASZone.attributes.ZoneStatus:configure_reporting(device, 30, 300, 1))
47+
device:send(PowerConfiguration.attributes.BatteryPercentageRemaining:read(device))
4548
end
4649

4750
local function info_changed(driver, device, event, args)
@@ -55,12 +58,16 @@ local function update_profile(device, zone_type)
5558
local profile = ZIGBEE_GENERIC_SENSOR_PROFILE
5659
if zone_type == CONTACT_SWITCH then
5760
profile = ZIGBEE_GENERIC_CONTACT_SENSOR_PROFILE
58-
elseif zone_type == MOTION_SENSOR then
59-
profile = ZIGBEE_GENERIC_MOTION_SENSOR_PROFILE
6061
elseif zone_type == WATER_SENSOR then
6162
profile = ZIGBEE_GENERIC_WATERLEAK_SENSOR_PROFILE
63+
elseif zone_type == MOTION_SENSOR then
64+
profile = ZIGBEE_GENERIC_MOTION_SENSOR_PROFILE
65+
for _, ep in ipairs(device.zigbee_endpoints) do
66+
if device:supports_server_cluster(clusters.IlluminanceMeasurement.ID, ep.id) then
67+
profile = ZIGBEE_GENERIC_MOTION_ILLUMINANCE_PROFILE
68+
end
69+
end
6270
end
63-
6471
device:try_update_metadata({profile = profile})
6572
end
6673

@@ -70,44 +77,6 @@ local ias_zone_type_attr_handler = function (driver, device, attr_val)
7077
update_profile(device, attr_val.value)
7178
end
7279

73-
-- since we don't have button devices using IASZone, the driver here is remaining to be updated
74-
local generate_event_from_zone_status = function(driver, device, zone_status, zb_rx)
75-
local type = device:get_field(ZONETYPE)
76-
local event
77-
if type == CONTACT_SWITCH then
78-
if zone_status:is_alarm1_set() or zone_status:is_alarm2_set() then
79-
event = capabilities.contactSensor.contact.open()
80-
else
81-
event = capabilities.contactSensor.contact.closed()
82-
end
83-
elseif type == MOTION_SENSOR then
84-
if zone_status:is_alarm1_set() or zone_status:is_alarm2_set() then
85-
event = capabilities.motionSensor.motion.active()
86-
else
87-
event = capabilities.motionSensor.motion.inactive()
88-
end
89-
elseif type == WATER_SENSOR then
90-
if zone_status:is_alarm1_set() then
91-
event = capabilities.waterSensor.water.wet()
92-
else
93-
event = capabilities.waterSensor.water.dry()
94-
end
95-
end
96-
if event ~= nil then
97-
device:emit_event_for_endpoint(
98-
zb_rx.address_header.src_endpoint.value,
99-
event)
100-
end
101-
end
102-
103-
local ias_zone_status_attr_handler = function(driver, device, zone_status, zb_rx)
104-
generate_event_from_zone_status(driver, device, zone_status, zb_rx)
105-
end
106-
107-
local ias_zone_status_change_handler = function(driver, device, zb_rx)
108-
generate_event_from_zone_status(driver, device, zb_rx.body.zcl_body.zone_status, zb_rx)
109-
end
110-
11180
local zigbee_generic_sensor_template = {
11281
supported_capabilities = {
11382
capabilities.battery,
@@ -117,13 +86,7 @@ local zigbee_generic_sensor_template = {
11786
zigbee_handlers = {
11887
attr = {
11988
[IASZone.ID] = {
120-
[IASZone.attributes.ZoneType.ID] = ias_zone_type_attr_handler,
121-
[IASZone.attributes.ZoneStatus.ID] = ias_zone_status_attr_handler
122-
}
123-
},
124-
cluster = {
125-
[IASZone.ID] = {
126-
[IASZone.client.commands.ZoneStatusChangeNotification.ID] = ias_zone_status_change_handler
89+
[IASZone.attributes.ZoneType.ID] = ias_zone_type_attr_handler
12790
}
12891
}
12992
},
@@ -132,6 +95,12 @@ local zigbee_generic_sensor_template = {
13295
doConfigure = do_configure,
13396
infoChanged = info_changed
13497
},
98+
sub_drivers = {
99+
require("contact"),
100+
require("motion"),
101+
require("waterleak"),
102+
require("motion-illuminance")
103+
},
135104
ias_zone_configuration_method = constants.IAS_ZONE_CONFIGURE_TYPE.AUTO_ENROLL_RESPONSE
136105
}
137106

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
-- Copyright 2025 SmartThings
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- http://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
local defaults = require "st.zigbee.defaults"
16+
local capabilities = require "st.capabilities"
17+
18+
local is_motion_illuminance = function(opts, driver, device)
19+
if device:supports_capability(capabilities.motionSensor) and device:supports_capability(capabilities.illuminanceMeasurement) then
20+
return true
21+
end
22+
end
23+
24+
local generic_motion_illuminance = {
25+
NAME = "Generic Motion illuminance",
26+
supported_capabilities = {
27+
capabilities.illuminanceMeasurement,
28+
capabilities.motionSensor
29+
},
30+
can_handle = is_motion_illuminance
31+
}
32+
defaults.register_for_default_handlers(generic_motion_illuminance, generic_motion_illuminance.supported_capabilities)
33+
return generic_motion_illuminance
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
-- Copyright 2025 SmartThings
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- http://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
local defaults = require "st.zigbee.defaults"
16+
local capabilities = require "st.capabilities"
17+
18+
local is_motion_sensor = function(opts, driver, device)
19+
if device:supports_capability(capabilities.motionSensor) and not device:supports_capability(capabilities.illuminanceMeasurement) then
20+
return true
21+
end
22+
end
23+
24+
local generic_motion_sensor = {
25+
NAME = "Generic Motion Sensor",
26+
supported_capabilities = {
27+
capabilities.motionSensor
28+
},
29+
can_handle = is_motion_sensor
30+
}
31+
defaults.register_for_default_handlers(generic_motion_sensor, generic_motion_sensor.supported_capabilities)
32+
return generic_motion_sensor

0 commit comments

Comments
 (0)