-
Notifications
You must be signed in to change notification settings - Fork 476
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 support for generic zigbee sensor #1921
base: main
Are you sure you want to change the base?
add support for generic zigbee sensor #1921
Conversation
Duplicate profile check: Passed - no duplicate profiles detected. |
Invitation URL: |
Test Results 65 files 411 suites 0s ⏱️ For more details on these failures, see this check. Results for commit 1dd4216. ♻️ This comment has been updated with latest results. |
Minimum allowed coverage is Generated by 🐒 cobertura-action against 1dd4216 |
@@ -0,0 +1,8 @@ | |||
zigbeeGeneric: | |||
- id: "ias-generic-sensor" | |||
deviceLabel: "IAS Zigbee Generic Sensor" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -0,0 +1,12 @@ | |||
name: ias-generic-button-profile |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this profile is unnecessary, please remove.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
got it
|
||
local ZIGBEE_GENERIC_SENSOR_PROFILE = "ias-generic-sensor" | ||
local ZIGBEE_GENERIC_CONTACT_SENSOR_PROFILE = "ias-generic-contact-sensor" | ||
local ZIGBEE_GENERIC_EMERGENCY_BUTTON_PROFILE = "ias-generic-emergency-button" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can remove this because there is no any implementation about button functionality in this code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
got it
local profile = ZIGBEE_GENERIC_SENSOR_PROFILE | ||
if zone_type == Contact_Switch then | ||
profile = ZIGBEE_GENERIC_CONTACT_SENSOR_PROFILE | ||
elseif zone_type == Remote_Control or zone_type == Key_Fob or zone_type == Keypad then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can remove this because there is no any implementation about button functionality in this code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay
state_change = true | ||
} | ||
|
||
log.info("---zone_status: "..zone_status.value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can remove log.info() after you have finished the test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay
local ZONETYPE = "ZoneType" | ||
local log = require "log" | ||
|
||
local Contact_Switch = 21 -- 0x0015 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use 0x0015 directly and use a capital letter when you define.
local CONTACT_SWITCH = 0x0015
local REMOTE_CONTROL = 0x010F
name: ias-generic-contact-sensor | ||
components: | ||
- id: main | ||
capabilities: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you test the battery capability for Group2 devices?
and check the configureReport set for the powerConfiguration cluster. (don't forget to add capabilities.battery in supported_capabilities of init.lua.)
Sensor should report its battery state periodically.
local ZIGBEE_GENERIC_MOTION_SENSOR_PROFILE = "ias-generic-motion-sensor" | ||
local ZIGBEE_GENERIC_WATERLEAK_SENSOR_PROFILE = "ias-generic-waterleak-sensor" | ||
|
||
-----add by dzd 20250124 start----- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these comments can be removed
end | ||
|
||
-- since we don't have button devices using IASZone, the driver here is remaining to be updated | ||
local generate_event_from_zone_status = function(driver, device, zone_status, zb_rx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of having a single function here that that branches, the standard way to handle this in drivers is with subdrivers. So if you had a subdriver that looked like:
local capabilities = require "st.capabilities"
local clusters = require "st.zigbee.zcl.clusters"
local IASZone = clusters.IASZone
local subdriver_template
local generate_event_from_zone_status = function(driver, device, zone_status, zb_rx)
if zone_status:is_alarm1_set() then
device:emit_event(capabilities.contactSensor.contact.open())
else
device:emit_event(capabilities.contactSensor.contact.closed())
end
end
local function subdriver_canhandle(opts, driver, device)
-- Create a "fields.lua" to contain this string definition and contact switch constant
return device:get_field("ZoneType") == 0x0015, subdriver_template
end
-- These functions could be moved to a common file as well.
local ias_zone_status_attr_handler = function(driver, device, zone_status, zb_rx)
generate_event_from_zone_status(driver, device, zone_status, zb_rx)
end
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
subdriver_template = {
NAME = "Zigbee Contact",
zigbee_handlers = {
attr = {
[IASZone.ID] = {
[IASZone.attributes.ZoneStatus.ID] = ias_zone_status_attr_handler
}
},
cluster = {
[IASZone.ID] = {
[IASZone.client.commands.ZoneStatusChangeNotification.ID] = ias_zone_status_change_handler
}
}
},
can_handle = subdriver_canhandle
}
return subdriver_template
There will be a bit more duplicate code, but the it allows us to separate all the different types into their own files, so if we need more complicated logic we don't end up with a big mess of a function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pInksenberg
For this, we need to check the ZoneType can be determined before the 'can_handle' triggered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this driver, we can seperate sub driver following zonetype, but this edge driver read zone type in add_handler. so this device wouldn't likely to handle some message in initial time potentially.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same problem exists whether this is a subdriver or a main driver here, until the ZONETYPE field is set on the device, we don't know what type of event we can generate, so we can't generate any event when the value changes. I still prefer the subdriver format as I think it's easier to separate the different devices, but I don't feel strongly about it, and I would be OK with this initial version, but that if any changes are made to add more complex logic that we split things out into subdrivers.
local additional_fields = { | ||
state_change = true | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should not be setting state_change = true
. That is only necessary, and should only be done for devices where they will emit the same value, but still need to be processed, like a button press.
52d5eca
to
7320dbe
Compare
capabilities: | ||
- id: contactSensor | ||
version: 1 | ||
- id: batteryLevel |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
battery level is different than battery. All other Zigbee devices use the battery capability and that's what the defaults support not batteryLevel
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@varzac @tpmanley
SRCN tried to use the battery capability but the result was untrustworthy.
So they removed the battery capabilty at the beginning, but I think If we cannot accurately display battery percentage, showing battery level (normal/warning/critical) instead would greatly benefit users.
SRCN suggested to use the zoneStatus(zone_status:is_battery_low_set()) because these devices are working based on IAS zone cluster. It is nice suggestion. Now, batteryLevel has 3 conditions.(normal/warning/critical) and we can know two battery condition with zoneStatus(1 – Low battery / 0 – Battery OK), so I think we can match the 'low battery' state to 'warning' state in batteryLevel. What do you think of this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left a somewhat similar comment here: https://github.com/SmartThingsCommunity/SmartThingsEdgeDrivers/pull/1921/files#r1956324647.
Was the BatteryPercentageRemaining
attribute found to not be trustworthy? We've found that usually works well, and the problems arise when trying to make BatteryVoltage
to a percentage as that's very hard to do, especially for coin cell batteries that have a pretty flat voltage for most of their life and then quickly decrease at the end. I would suggest using BatteryPercentageRemaining
and the battery
capability and/or ZoneStatus low battery to indicate warning
like you suggested (I don't have a strong preference whether it should be warning or critical).
7320dbe
to
6771cba
Compare
6771cba
to
7a4d856
Compare
-- test.mock_time.advance_time(50000) | ||
-- test.socket.zigbee:__set_channel_ordering("relaxed") | ||
-- test.socket.zigbee:__expect_send({ mock_device_waterleak_sensor.id, IASZone.attributes.ZoneStatus:read(mock_device_waterleak_sensor) }) | ||
-- test.wait_for_events() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, @greens @varzac
I tried to add these three pieces of code in this file.
I found that this has relationship to the capabilities in supported_capabilities
in init.lua
.
However, when I add capabilities contactSensor
, motionSensor
and waterSensor
in file init.lua
(the commented-out code), I found that only the front one can work and the others failed. Why did this happen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you clarify what the failure is. Looking at the driver, there is no code that will send a ZoneStatus read after a delay. If you are expecting the infoChanged
to happen, in the test environment that will only happen if you write test code to generate it. In addition, I don't think sending a read on the infoChanged
is correct behavior.
capabilities.refresh | ||
-- capabilities.motionSensor, | ||
-- capabilities.contactSensor, | ||
-- capabilities.waterSensor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only the motionSensor
here can work.
end | ||
|
||
-- ask device to upload its zone status, then the status of capabilities can be synchronized | ||
local ias_info_changed = function(driver, device) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function will be run every time the device is updated on the cloud side. You should not be reading an attribute here. If the intent is for this to happen at some point after the device is added, you should use the call_with_delay
to have the driver wait some period and then send the read.
event = capabilities.contactSensor.contact.closed() | ||
end | ||
elseif type == MOTION_SENSOR then | ||
if zone_status:is_alarm1_set() then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Motion sensors can use either alarm1 or alarm2 so I would suggest reporting active
if either are set
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check the newly commit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for making the changes, but can you use the or
operator instead of the extra elseif
because it's more concise/easier to read?
if zone_status:is_alarm1_set() or zone_status:is_alarm2_set() then
event = capabilities.motionSensor.motion.active()
else
event = capabilities.motionSensor.motion.inactive()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
modified
local type = device:get_field(ZONETYPE) | ||
local event | ||
if type == CONTACT_SWITCH then | ||
if zone_status:is_alarm1_set() then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ZCL spec says that contact switches can use both alarm1 and alarm2 so I think both should be checked
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check the newly commit
|
||
local battery_level_handler = function(driver, device, value, zb_rx) | ||
local voltage = value.value | ||
if voltage <= 25 then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's pretty difficult to accurately translate voltage to battery level without knowing the details of the device and battery technology. I'd either suggest using the low battery indicator in the IAS Zone Status and/or switching from batteryLevel
capability to battery
and looking at the BatteryPercentageRemaining
attribute instead of BatteryVoltage
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies, I just saw the similar comment here: #1921 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test result for BatteryPercentageRemaining:
using same type of battery
37 Meian meian water leak sensor Water Leak Sensor :100
20 EZVIZ EZVIZ T1C Smart Motion Sensor Motion sensor :90
21 Tuya Tuya Zigbee PIR Sensor Motion sensor :100
24 Tuya PIR Motion SensoR XZ-CGV2 Motion sensor :100
27 Tuya Tuya Human motion sensors Motion sensor :98
using different type of battery
38 EZVIZ EZVIZ T10C Water Leak Sensor Water Leak Sensor :98
34 Tuya Door Window Sensor Door and Window Sensor :100
33 EZVIZ EZVIZ T2C Door and Window Contact Sensor Door and Window Sensor :100
22 Tuya Tuya PIR Motion Sensor Motion sensor :100
2d38ca2
to
e8f7f2c
Compare
2d38ca2
to
d446b94
Compare
Signed-off-by: frank-huang <frank.huang@samsung.com>
d446b94
to
6b7d791
Compare
I think it would be good to also include a test of the device added behavior to verify that we read the zone type attribute and store it to the device record correctly. |
We will add that test. |
Signed-off-by: frank-huang <frank.huang@samsung.com>
2e45960
to
fa1311c
Compare
TC is updated |
) | ||
|
||
test.register_coroutine_test( | ||
"Configure should configure all necessary attributes(waterleak)", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These test names are not accurate as this isn't testing configure, this is testing added. This I think shows a potential issue. I think the cie address write will work, but since the configured attributes are set based on the defaults I don't think the ZoneStatus attribute will be configured for reporting. Are the devices properly reporting?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we will modify the name of the test. The device are not reporting Zone Status now, and we are in the process of configuring ZoneStatus for reporting.
battery_config.reportable_change = 0x10 | ||
battery_config.data_type = clusters.PowerConfiguration.attributes.BatteryVoltage.base_type | ||
|
||
local CONTACT_SWITCH = 0x0015 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use https://github.ecodesamsung.com/iot-hub/scripting-engine/blob/main/lua_libs/st/zigbee/generated/types/IasZoneType.lua instead of re-defining these here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. we will modify it.
Signed-off-by: frank-huang <frank.huang@samsung.com>
e33e9d6
to
f4cc05a
Compare
attribute = clusters.PowerConfiguration.attributes.BatteryPercentageRemaining.ID, | ||
minimum_interval = 30, | ||
maximum_interval = 21600, | ||
data_type = clusters.PowerConfiguration.attributes.BatteryVoltage.base_type, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
data_type = clusters.PowerConfiguration.attributes.BatteryVoltage.base_type, | |
data_type = clusters.PowerConfiguration.attributes.BatteryPercentageRemaining.base_type, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem
elseif type == WATER_SENSOR then | ||
if zone_status:is_alarm1_set() then | ||
event = capabilities.waterSensor.water.wet() | ||
else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
else | |
else |
nit: the linter noticed trailing whitespace here
I enabled the github workflow to run and it's showing the tests have these failures:
|
- id: firmwareUpdate | ||
version: 1 | ||
- id: refresh | ||
version: 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I expect a category is required, but if that's not the case then this is fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This profile applies when the ZoneType
of the IASZone
has not yet been identified. In this case, the profile will be updated to other profiles to reflect other categories such as contact, motion, etc.
Until the device receives the ZoneType
, we have no definitive information regarding its category; all we know is that it is a sensor.
Is there a specific device type that can solely describe a sensor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have a GenericSensor
category I believe. Not positive what the corresponding icon is, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do found that device type in OCF device type wiki.
However, we have tested the profile with GenericSenso
but noticed that there is no related icon displayed on the device card, only a default icon.
Upon investigation, we confirmed that the oic.d.sensor
, which is the OCFdtype
for GenericSensor
, does not exist in the CN production environment.
Could you please assist us in confirming whether this device type exists in the Global production environment? If it does, we would like to request our cloud team to synchronize the device type with the CN production. Thank you for your assistance in advance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be that the default icon is also what's used on the global environments. I'm not sure, though. It's not a new category, so I'd be surprised if it was different on CN.
Mainly this comment was just in case the driver packager complained about the profile not including a category. I thought it might have been a required field. If it's not a required field then you can ignore this comment. Default icon is fine for a device with undetermined functionality.
event = capabilities.motionSensor.motion.inactive() | ||
end | ||
elseif type == WATER_SENSOR then | ||
if zone_status:is_alarm1_set() then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any reason why alarm2
isn't used as a trigger here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if it should be, this function could be simplified to use a map
local event_mapping = {
CONTACT_SWITCH = {active = capabilitiles.contactSensor.contact.open(), inactive = capabilities.contactSensor.contact.closed()}
...
}
if alarm1 or alarm2 then
device:emit_event_for_endpoint(event_mapping[type].active)
else
...
something like that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We will check that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we confirmed in ZCL library, the water sensor does not support alarm2
trigger.
(Table 8-5 in ZCL library file).
Value | Zone Type | Alarm1 | Alarm2 |
---|---|---|---|
0x0000 | Standard CIE | System Alarm | - |
0x000d | Motion sensor | Intrusion indication | Presence indication |
0x0015 | Contact switch | 1st portal Open-Close | 2nd portal Open-Close |
0x0016 | Door/Window handle | See Table 8-7 | See Table 8-7 |
0x0028 | Fire sensor | Fire indication | - |
0x002a | Water sensor | Water overflow indication | - |
device:emit_event_for_endpoint( | ||
zb_rx.address_header.src_endpoint.value, | ||
event) | ||
if device:get_component_id_for_endpoint(zb_rx.address_header.src_endpoint.value) ~= "main" then | ||
device:emit_event(event) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this being done to future-proof a possible implementation for a sensor with multiple different endpoints? I get the instinct but you'd have to have all the capabilities on the main
component already in order to do this. It's probably best to just emit from the specific component rather than trying to (in the future) duplicate everything onto main as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, we will modify this one.
We will check it |
7f03dd8
to
fbb2301
Compare
fbb2301
to
1dd4216
Compare
Signed-off-by: frank-huang <frank.huang@samsung.com>
Check all that apply
Type of Change
Checklist
Description of Change
Add support for generic Zigbee sensor base on IASZone type
Summary of Completed Tests