Skip to content

Commit 9267b81

Browse files
committed
generic_zigbee_sensor_improvement
1 parent 9379c14 commit 9267b81

33 files changed

+3187
-52
lines changed

drivers/SmartThings/zigbee-sensor/fingerprints.yml

+17-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,20 @@ 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
17+
- id: "generic-button-sensor"
18+
deviceLabel: "Zigbee Generic Button"
19+
clusters:
20+
server:
21+
- 0x0500
22+
- 0xfe00 # EZVIZ private cluster
23+
- 0xfe05 # EZVIZ private cluster
24+
deviceProfileName: generic-remote-control
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,14 @@
1+
name: generic-remote-control
2+
components:
3+
- id: main
4+
capabilities:
5+
- id: button
6+
version: 1
7+
- id: battery
8+
version: 1
9+
- id: firmwareUpdate
10+
version: 1
11+
- id: refresh
12+
version: 1
13+
categories:
14+
- name: Button
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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 clusters = require "st.zigbee.zcl.clusters"
16+
local capabilities = require "st.capabilities"
17+
18+
local IASZone = clusters.IASZone
19+
20+
local is_contact_sensor = function(opts, driver, device)
21+
if device:supports_capability(capabilities.contactSensor) then
22+
return true
23+
end
24+
end
25+
26+
local generate_event_from_zone_status = function(driver, device, zone_status, zb_rx)
27+
local event
28+
if zone_status:is_alarm1_set() or zone_status:is_alarm2_set() then
29+
event = capabilities.contactSensor.contact.open()
30+
else
31+
event = capabilities.contactSensor.contact.closed()
32+
end
33+
if event ~= nil then
34+
device:emit_event_for_endpoint(
35+
zb_rx.address_header.src_endpoint.value,
36+
event)
37+
end
38+
end
39+
40+
41+
local ias_zone_status_attr_handler = function(driver, device, zone_status, zb_rx)
42+
generate_event_from_zone_status(driver, device, zone_status, zb_rx)
43+
end
44+
45+
local ias_zone_status_change_handler = function(driver, device, zb_rx)
46+
generate_event_from_zone_status(driver, device, zb_rx.body.zcl_body.zone_status, zb_rx)
47+
end
48+
49+
50+
local generic_contact_sensor = {
51+
NAME = "Generic Contact Sensor",
52+
zigbee_handlers = {
53+
attr = {
54+
[IASZone.ID] = {
55+
[IASZone.attributes.ZoneStatus.ID] = ias_zone_status_attr_handler
56+
}
57+
},
58+
cluster = {
59+
[IASZone.ID] = {
60+
[IASZone.client.commands.ZoneStatusChangeNotification.ID] = ias_zone_status_change_handler
61+
}
62+
}
63+
},
64+
can_handle = is_contact_sensor
65+
}
66+
67+
return generic_contact_sensor
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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 capabilities = require "st.capabilities"
16+
local defaults = require "st.zigbee.defaults"
17+
18+
local EZVIZ_PRIVATE_CLUSTER = 0xFE05
19+
local EZVIZ_PRIVATE_ATTRIBUTE = 0x0000
20+
21+
local EZVIZ_MFR = "EZVIZ"
22+
23+
local is_ezviz_button = function(opts, driver, device)
24+
if device:supports_capability(capabilities.button) and device:get_manufacturer() == EZVIZ_MFR then
25+
return true
26+
end
27+
end
28+
29+
-- We need an empty added here to override the added in root init.lua, because we already knows its profile
30+
local device_added = function(self, device)
31+
end
32+
33+
local ezviz_private_cluster_button_handler = function(driver, device, zb_rx)
34+
local event
35+
local additional_fields = {
36+
state_change = true
37+
}
38+
if zb_rx.value == 0x01 then
39+
event = capabilities.button.button.pushed(additional_fields)
40+
elseif zb_rx.value == 0x02 then
41+
event = capabilities.button.button.double(additional_fields)
42+
elseif zb_rx.value == 0x03 then
43+
event = capabilities.button.button.held(additional_fields)
44+
end
45+
if event ~= nil then
46+
device:emit_event(event)
47+
end
48+
end
49+
50+
local ezviz_button_handler = {
51+
NAME = "Ezviz Button",
52+
supported_capabilities = {
53+
capabilities.battery,
54+
capabilities.button,
55+
capabilities.refresh
56+
},
57+
zigbee_handlers = {
58+
attr = {
59+
[EZVIZ_PRIVATE_CLUSTER] = {
60+
[EZVIZ_PRIVATE_ATTRIBUTE] = ezviz_private_cluster_button_handler
61+
}
62+
}
63+
},
64+
lifecycle_handlers = {
65+
added = device_added
66+
},
67+
can_handle = is_ezviz_button
68+
}
69+
defaults.register_for_default_handlers(ezviz_button_handler, ezviz_button_handler.supported_capabilities)
70+
return ezviz_button_handler

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

+21-48
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,14 @@ local device_management = require "st.zigbee.device_management"
2323
local CONTACT_SWITCH = IasZoneType.CONTACT_SWITCH
2424
local MOTION_SENSOR = IasZoneType.MOTION_SENSOR
2525
local WATER_SENSOR = IasZoneType.WATER_SENSOR
26+
local REMOTE_CONTROL = IasZoneType.REMOTE_CONTROL
2627

2728
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"
33+
local ZIGBEE_GENERIC_REMOTE_CONTROL_PROFILE = "generic-remote-control"
3134

3235
local ZONETYPE = "ZoneType"
3336
local IASZone = clusters.IASZone
@@ -55,12 +58,18 @@ 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
61+
elseif zone_type == REMOTE_CONTROL then
62+
profile = ZIGBEE_GENERIC_REMOTE_CONTROL_PROFILE
6063
elseif zone_type == WATER_SENSOR then
6164
profile = ZIGBEE_GENERIC_WATERLEAK_SENSOR_PROFILE
65+
elseif zone_type == MOTION_SENSOR then
66+
profile = ZIGBEE_GENERIC_MOTION_SENSOR_PROFILE
67+
for _, ep in ipairs(device.zigbee_endpoints) do
68+
if device:supports_server_cluster(clusters.IlluminanceMeasurement.ID, ep.id) then
69+
profile = ZIGBEE_GENERIC_MOTION_ILLUMINANCE_PROFILE
70+
end
71+
end
6272
end
63-
6473
device:try_update_metadata({profile = profile})
6574
end
6675

@@ -70,44 +79,6 @@ local ias_zone_type_attr_handler = function (driver, device, attr_val)
7079
update_profile(device, attr_val.value)
7180
end
7281

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-
11182
local zigbee_generic_sensor_template = {
11283
supported_capabilities = {
11384
capabilities.battery,
@@ -117,13 +88,7 @@ local zigbee_generic_sensor_template = {
11788
zigbee_handlers = {
11889
attr = {
11990
[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
91+
[IASZone.attributes.ZoneType.ID] = ias_zone_type_attr_handler
12792
}
12893
}
12994
},
@@ -132,6 +97,14 @@ local zigbee_generic_sensor_template = {
13297
doConfigure = do_configure,
13398
infoChanged = info_changed
13499
},
100+
sub_drivers = {
101+
require("contact"),
102+
require("motion"),
103+
require("waterleak"),
104+
require("motion-illuminance"),
105+
require("meian"),
106+
require("ezviz")
107+
},
135108
ias_zone_configuration_method = constants.IAS_ZONE_CONFIGURE_TYPE.AUTO_ENROLL_RESPONSE
136109
}
137110

0 commit comments

Comments
 (0)