However, as far as I understand it only allows to provide a different handling for each end point.
I basically have 2 use cases:
2 gang switch where each gang is used in different automation. While it is possible to control each gang with this approach, I’m not sure how specific end point can be controlled by Aleksa for example.
Non standard devices implementing proprietary Tuya cluster. For those devices the communication is always for standard zigbee ep=1 and the actual end point is hidden inside the proprietary message
What would be the best approach for those 2 use cases? Is there any examples for that?
Could you please clarify how supporting Tuya cluster can be possibly addressed by endpoint/component association? Tuya device will always report the same endpoint, the dispatch should be performed based on the ZCL Data, not ZCL header. I don’t think the current endpoint/component association API supports it.
Also, how integration with Aleksa will be performed? Aleksa is unaware of multi component devices. Does it mean that for each gang on multi gang switch there will be a need to create a virtual switch?
The first component must be always the “main”, which after seeing a thousand logcat, corresponds to the endpoint 1. And endpoints 2 and 3 have to be switch1 and switch2 by default.
In the ini.lua code, it assigns the endpoints by the component_id of the profile.yml file, so it is assigning the endpoint 1 two times and the third switch remains unassigned.
Solution the file of profile.yml it is necessary to change “switch1 by switch2” and “switch2 by switch3”.
On the other hand, it needs the capability refresh, also added to the file profile.yml and init.lua in the definition of capabilities of the driver_template.
Switches 2 and 3 after perform action, need to slide your finger on the device details for the status to be refreshed.
Quick controls are not individual. It is programmed and executed in all switches at the same time.
In the Automations it has the same problem of the multiple buttons, that I already put a ticket a long time ago, the actions to program appear without separation by switch.
It seems that your driver is communicating properly with your device, but is missing to push the capability event back to the platform once you send a switch command.
You can use the device:emit_event_for_endpoint to push the capability event according to the component that was updated (see reference).
@erickv,
The device installed fine, but when you turn on or off any of the 3 plugs it gives this error:
2021-09-09T22:38:59.350998848+00:00 DEBUG Zigbee Multi Switch-v1 Lidl MultiPlug device thread event handled
2021-09-09T22:39:21.021951525+00:00 TRACE Zigbee Multi Switch-v1 Received event with handler capability
2021-09-09T22:39:21.031821525+00:00 INFO Zigbee Multi Switch-v1 <ZigbeeDevice: e689144b-94c6-4871-9da5-fd98fe2e8452 [0x6A13] (Lidl MultiPlug)> received command: {"component":"main","args":[],"command":"on","capability":"switch","positional_args":[]}
2021-09-09T22:39:21.038372191+00:00 TRACE Zigbee Multi Switch-v1 Found CapabilityCommandDispatcher handler in Zigbee_Multi_Switch
2021-09-09T22:39:21.044232858+00:00 PRINT Zigbee Multi Switch-v1 component_id: main
2021-09-09T22:39:21.050194525+00:00 ERROR Zigbee Multi Switch-v1 Lidl MultiPlug thread encountered error: [string "init.lua"]:70: attempt to index
a nil value (global 'OnOff')
Driver does not send the command On or Off:
The variable OnOff is undefined.
With this modification it already updates the app status of the 3 plugs.
After several tests, this is what I see that it does not work well or as expected:
This strip has a button that activates or deactivates all 3 plugs at the same time. When you press it, app only updates the state of the main socket (1).
I am not able to capture these events from switch 2 and 3, only the event received from main is seen in the log.
The same happens with the configuration reports, they should send status every 300 sec and only the main component sends it.
If you send a “refresh” command, update the 3 plugs.
A solution that works is to program a timer every 300 sec that a refrech executes.
Automations are local if you only execute actions on the “main” socket. If you perform actions with plug 2 or 3, they are not local.
What I already commented in another post, in automation it does not show the names of the plugs. Shows all actions followed. This also happens now with multi button DTHs.
If your device is not automatically sending the respective Zigbee messages, then you can perform this state-binding directly at the driver. This way the app will have the current state of your device, e.g.:
local ENDPOINTS = {1, 2, 3}
for _, ep in pairs(ENDPOINTS) do
device:emit_event_for_endpoint(ep, attr.on())
end
And regarding the reports
I’ll keep an I on this, and as soon as I have an update, I’ll share it with you.
Also, can you please give us more details about this specific issue?
Well that has been fixed. Now automations work as local with all the combinations I have tried.
I do not know if will have related with update of the beta firmware to 39.05 that was made today.
Yesterday only the local icon appeared in the automations that only the main plug (1) was in the then part.
If you added one of the other two plugs or only 2 and / or 3, the local execution icon would disappear.
Well, Can be delete.
Where would you place this so that it only updates the status of the three plugs when the main switch is pressed?
I have a 240 sec timer that runs the refresh command and updates the status if it has changed
We can include that state-binding action at the example from above, so, when you get an on/off command from the endpoint #1 of device (i.e. “main” component), you update all the components at platform-level. For example:
local zcl_clusters = require "st.zigbee.zcl.clusters"
local OnOff = zcl_clusters.OnOff
local function on_handler(_, device, command)
-- capability reference
local attr = capabilities.switch.switch
-- parse component to endpoint
local endpoint = device:get_endpoint_for_component_id(command.component)
-- handle global on from
-- "main" main component
if endpoint == 1 then
for _, ep in pairs({1,2,3}) do
-- send Zigbee message
--
-- this will be necessary in
-- case your device doesn't
-- apply the command by itself.
device:send(OnOff.server.commands.On(device:to_endpoint(ep)))
-- send platform event
device:emit_event_for_endpoint(ep, attr.on())
end
return
end
-- send single events
device:send(OnOff.server.commands.On(device):to_endpoint(endpoint))
device:emit_event_for_endpoint(endpoint, attr.on())
end
it is better to have a single handler for both On and Off commands
to create a command only once and reuse it for each send
Therefore, I propose something like that
-- create a command to be sent, either On or Off
local cmd = (command.command == "off") and OnOff.server.commands.Off(device) or OnOff.server.commands.On(device)
for _, ep in pairs({1,2,3}) do
-- modify dest end point
cmd.address_header.dest_endpoint.value = ep
-- send command
device:send(cmd)
end
Another note, if you notify the platform right after sending the command, the platform will show the new state, even if the command was lost in the network or the device was not able to process it.
This approach is prone to get the device and platform out of sync.
I would suggest to consider notifying the platform about the new change in zigbee handler not in platform/capability handlers
Can you actually identify when the main switch has been used? If you can then I can see that @erickv is offering a workable solution. If you only know that switch 1 has turned on or off but not why then I don’t see how it helps.
However I really don’t like the idea of setting the status of a switch except in response to a report from the device itself. I think it would be better if you could do an immediate refresh to get switches 2 and 3 to report.
For Aqara switch I have the following solution.
I have a switch under “main” component and in addition “switch” component for each gang.
Something like that:
The platform handler checks whether the event is received for “main” or for the child.
If it is received from “main” component it issues send command for all children.
If it is received from specific gang, then the component is parsed to retrieve the gang number. Then the command is sent to this specific gang.
As a side note, I personally prefer to call whatever comes from platform as ‘event’, not command.
I use ‘command’ only for communication with the device.
This is basically my code, but please use it as a reference, as I have a lot of utiity functions
local function event_handler_switch_on_off(driver, device, event)
utils.log_debug(device, "event_handler_switch_on_off DNI=" .. tostring(device.device_network_id) .. " event=" .. st_utils.stringify_table(event) )
local command = (event.command == "off") and zcl_clusters.OnOff.server.commands.Off(device) or zcl_clusters.OnOff.server.commands.On(device)
if event.component == "main" then
-- Send the same command (either On or Off) to all gangs
for i = 1, utils.get_switch_count(device) do
command.address_header.dest_endpoint.value = i
device:send(command)
end
else
command.address_header.dest_endpoint.value = utils.component_name_to_ep(event.component)
device:send(command)
end
end