-
Notifications
You must be signed in to change notification settings - Fork 514
WWSTCERT-8423/8426 [Aqara] Wireless Remote Switch T1(Single/Double) #2458
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| name: aqara-double-buttons | ||
| components: | ||
| - id: main | ||
| capabilities: | ||
| - id: button | ||
| version: 1 | ||
| - id: batteryLevel | ||
| version: 1 | ||
| - id: refresh | ||
| version: 1 | ||
| categories: | ||
| - name: RemoteController | ||
| - id: button1 | ||
| capabilities: | ||
| - id: button | ||
| version: 1 | ||
| categories: | ||
| - name: RemoteController | ||
| - id: button2 | ||
| capabilities: | ||
| - id: button | ||
| version: 1 | ||
| categories: | ||
| - name: RemoteController | ||
| - id: all | ||
| capabilities: | ||
| - id: button | ||
| version: 1 | ||
| categories: | ||
| - name: RemoteController |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| name: one-button-batteryLevel | ||
| components: | ||
| - id: main | ||
| capabilities: | ||
| - id: button | ||
| version: 1 | ||
| - id: batteryLevel | ||
| version: 1 | ||
| - id: firmwareUpdate | ||
| version: 1 | ||
| - id: refresh | ||
| version: 1 | ||
| categories: | ||
| - name: Button |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,74 +29,113 @@ local MFG_CODE = 0x115F | |
| local MULTISTATE_INPUT_CLUSTER_ID = 0x0012 | ||
| local PRESENT_ATTRIBUTE_ID = 0x0055 | ||
|
|
||
| local COMP_LIST = { "button1", "button2", "all" } | ||
| local FINGERPRINTS = { | ||
| { mfr = "LUMI", model = "lumi.remote.b1acn02" }, | ||
| { mfr = "LUMI", model = "lumi.remote.acn003" } | ||
| ["lumi.remote.b1acn02"] = { mfr = "LUMI", btn_cnt = 1 }, | ||
| ["lumi.remote.acn003"] = { mfr = "LUMI", btn_cnt = 1 }, | ||
| ["lumi.remote.b186acn03"] = { mfr = "LUMI", btn_cnt = 1 }, | ||
| ["lumi.remote.b286acn03"] = { mfr = "LUMI", btn_cnt = 3 } | ||
| } | ||
|
|
||
| local configuration = { | ||
| { | ||
| cluster = MULTISTATE_INPUT_CLUSTER_ID, | ||
| attribute = PRESENT_ATTRIBUTE_ID, | ||
| minimum_interval = 3, | ||
| maximum_interval = 7200, | ||
| data_type = data_types.Uint16, | ||
| reportable_change = 1 | ||
| }, | ||
| { | ||
| cluster = PowerConfiguration.ID, | ||
| attribute = PowerConfiguration.attributes.BatteryVoltage.ID, | ||
| minimum_interval = 30, | ||
| maximum_interval = 3600, | ||
| data_type = PowerConfiguration.attributes.BatteryVoltage.base_type, | ||
| reportable_change = 1 | ||
| } | ||
| { | ||
| cluster = MULTISTATE_INPUT_CLUSTER_ID, | ||
| attribute = PRESENT_ATTRIBUTE_ID, | ||
| minimum_interval = 3, | ||
| maximum_interval = 7200, | ||
| data_type = data_types.Uint16, | ||
| reportable_change = 1 | ||
| }, | ||
| { | ||
| cluster = PowerConfiguration.ID, | ||
| attribute = PowerConfiguration.attributes.BatteryVoltage.ID, | ||
| minimum_interval = 30, | ||
| maximum_interval = 3600, | ||
| data_type = PowerConfiguration.attributes.BatteryVoltage.base_type, | ||
| reportable_change = 1 | ||
| } | ||
| } | ||
|
|
||
| local function present_value_attr_handler(driver, device, value, zb_rx) | ||
| if value.value == 1 then | ||
| device:emit_event(capabilities.button.button.pushed({state_change = true})) | ||
| elseif value.value == 2 then | ||
| device:emit_event(capabilities.button.button.double({state_change = true})) | ||
| elseif value.value == 0 then | ||
| device:emit_event(capabilities.button.button.held({state_change = true})) | ||
| end | ||
| local end_point = zb_rx.address_header.src_endpoint.value | ||
| local btn_evt_cnt = FINGERPRINTS[device:get_model()].btn_cnt or 1 | ||
| local evt = capabilities.button.button.held({ state_change = true }) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we be explicit about this only being the case when the value is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't anticipate any issues, as it should work the same way with values of 2 or higher |
||
| if value.value == 1 then | ||
| evt = capabilities.button.button.pushed({ state_change = true }) | ||
| elseif value.value == 2 then | ||
| evt = capabilities.button.button.double({ state_change = true }) | ||
| end | ||
| device:emit_event(evt) | ||
| if btn_evt_cnt > 1 then | ||
| device:emit_component_event(device.profile.components[COMP_LIST[end_point]], evt) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems like button events will only be emitted from the In the past we've used the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To monitor all button events on the card, they are set to be emitted from the main component. Endpoint 3 triggers an event when both button 1 and button 2 are pressed simultaneously, so the all component is used to indicate that both buttons must be pressed together. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @greens This device appears to have two physical buttons, but it actually functions like a 3-button device. When both buttons are pressed simultaneously, it triggers the button event for the all component, but not for button1 or button2. However, when naming it button3, it would be difficult for users to associate it with pressing simultaneously, so it was suggested to create it as an all component. If you have better idea about |
||
| end | ||
| end | ||
| local function battery_level_handler(driver, device, value, zb_rx) | ||
| local voltage = value.value | ||
| local batteryLevel = "normal" | ||
| if voltage <= 25 then | ||
| batteryLevel = "critical" | ||
| elseif voltage < 28 then | ||
| batteryLevel = "warning" | ||
| end | ||
| device:emit_event(capabilities.batteryLevel.battery(batteryLevel)) | ||
| end | ||
|
|
||
| local is_aqara_products = function(opts, driver, device) | ||
| for _, fingerprint in ipairs(FINGERPRINTS) do | ||
| if device:get_manufacturer() == fingerprint.mfr and device:get_model() == fingerprint.model then | ||
| return true | ||
| end | ||
| end | ||
| return false | ||
| local isAqaraProducts = false | ||
| if FINGERPRINTS[device:get_model()] and FINGERPRINTS[device:get_model()].mfr == device:get_manufacturer() then | ||
| isAqaraProducts = true | ||
| end | ||
| return isAqaraProducts | ||
| end | ||
|
|
||
| local function device_init(driver, device) | ||
| battery_defaults.build_linear_voltage_init(2.6, 3.0)(driver, device) | ||
| if configuration ~= nil then | ||
| for _, attribute in ipairs(configuration) do | ||
| device:add_configured_attribute(attribute) | ||
| end | ||
| battery_defaults.build_linear_voltage_init(2.6, 3.0)(driver, device) | ||
| if configuration ~= nil then | ||
| for _, attribute in ipairs(configuration) do | ||
| device:add_configured_attribute(attribute) | ||
| 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})) | ||
| button_utils.emit_event_if_latest_state_missing(device, "main", capabilities.button, capabilities.button.button.NAME, capabilities.button.button.pushed({state_change = false})) | ||
| device:emit_event(capabilities.battery.battery(100)) | ||
| local btn_evt_cnt = FINGERPRINTS[device:get_model()].btn_cnt or 1 | ||
|
|
||
| device:emit_event(capabilities.button.supportedButtonValues({ "pushed", "held", "double" }, | ||
| { visibility = { displayed = false } })) | ||
| device:emit_event(capabilities.button.numberOfButtons({ value = 1 })) | ||
| button_utils.emit_event_if_latest_state_missing(device, "main", capabilities.button, capabilities.button.button.NAME, | ||
| capabilities.button.button.pushed({ state_change = false })) | ||
| device:emit_event(capabilities.batteryLevel.battery.normal()) | ||
| device:emit_event(capabilities.batteryLevel.type("CR2032")) | ||
| device:emit_event(capabilities.batteryLevel.quantity(1)) | ||
|
|
||
| if btn_evt_cnt > 1 then | ||
| for i = 1, btn_evt_cnt do | ||
| device:emit_component_event(device.profile.components[COMP_LIST[i]], | ||
| capabilities.button.supportedButtonValues({ "pushed", "held", "double" }, | ||
| { visibility = { displayed = false } })) | ||
| device:emit_component_event(device.profile.components[COMP_LIST[i]], | ||
| capabilities.button.numberOfButtons({ value = 1 })) | ||
| device:emit_component_event(device.profile.components[COMP_LIST[i]], | ||
| capabilities.button.button.pushed({ state_change = false })) | ||
| button_utils.emit_event_if_latest_state_missing(device, COMP_LIST[i], capabilities.button, | ||
| capabilities.button.button.NAME, capabilities.button.button.pushed({ state_change = false })) | ||
| end | ||
| end | ||
| end | ||
|
|
||
| local function do_configure(driver, device) | ||
| local ATTR_ID = PRIVATE_ATTRIBUTE_ID_T1 | ||
| local cmd_value = 1 | ||
|
|
||
| device:configure() | ||
| if device:get_model() == "lumi.remote.b1acn02" then | ||
| device:send(cluster_base.write_manufacturer_specific_attribute(device, | ||
| PRIVATE_CLUSTER_ID, PRIVATE_ATTRIBUTE_ID_T1, MFG_CODE, data_types.Uint8, 1)) | ||
| elseif device:get_model() == "lumi.remote.acn003" then | ||
| device:send(cluster_base.write_manufacturer_specific_attribute(device, | ||
| PRIVATE_CLUSTER_ID, PRIVATE_ATTRIBUTE_ID_E1, MFG_CODE, data_types.Uint8, 2)) | ||
| if device:get_model() == "lumi.remote.acn003" then | ||
| ATTR_ID = PRIVATE_ATTRIBUTE_ID_E1 | ||
| cmd_value = 2 | ||
| end | ||
| device:send(cluster_base.write_manufacturer_specific_attribute(device, | ||
| PRIVATE_CLUSTER_ID, ATTR_ID, MFG_CODE, data_types.Uint8, cmd_value)) | ||
| -- when the wireless switch T1 accesses the network, the gateway sends | ||
| -- private attribute 0009 to make the device no longer distinguish | ||
| -- between the standard gateway and the aqara gateway. | ||
|
|
@@ -105,20 +144,23 @@ local function do_configure(driver, device) | |
| end | ||
|
|
||
| local aqara_wireless_switch_handler = { | ||
| NAME = "Aqara Wireless Switch Handler", | ||
| lifecycle_handlers = { | ||
| init = device_init, | ||
| added = added_handler, | ||
| doConfigure = do_configure | ||
| }, | ||
| zigbee_handlers = { | ||
| attr = { | ||
| [MULTISTATE_INPUT_CLUSTER_ID] = { | ||
| [PRESENT_ATTRIBUTE_ID] = present_value_attr_handler | ||
| } | ||
| NAME = "Aqara Wireless Switch Handler", | ||
| lifecycle_handlers = { | ||
| init = device_init, | ||
| added = added_handler, | ||
| doConfigure = do_configure | ||
| }, | ||
| zigbee_handlers = { | ||
| attr = { | ||
| [MULTISTATE_INPUT_CLUSTER_ID] = { | ||
| [PRESENT_ATTRIBUTE_ID] = present_value_attr_handler | ||
| }, | ||
| [PowerConfiguration.ID] = { | ||
| [PowerConfiguration.attributes.BatteryVoltage.ID] = battery_level_handler | ||
| } | ||
| }, | ||
| can_handle = is_aqara_products | ||
| } | ||
| }, | ||
| can_handle = is_aqara_products | ||
| } | ||
|
|
||
| return aqara_wireless_switch_handler | ||
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.
rename to
one-button-batteryLeveland include thefirmwareUpdatecapability.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 have updated.