openhab-addons
openhab-addons copied to clipboard
[boschshc] Add support for Light/Shutter Control II
Description
This PR adds support for another Bosch Smart Home device, namely Light/Shutter Control II. The device can either be configured as shutter control or as light control with two light switch circuits.
Testing
Hi @GerdZanker, @jlaur and @lsiepel, I would like to discuss the thing/channel modeling approach for this device with you.
We have the following situation: Bosch provides a device that can be configured either as a shutter control or a light switch with two light switch circuits. The shutter control configuration is straight-forward (one device, one thing type, corresponding channels).
However, when configured as two light switches, we see a parent device (it provides basic services such as communication quality and power metering) and two child devices, that represent the light switch circuits.
In my current implementation I have modeled it in the same way in openHAB. I introduced two different thing types, and the user sees three things. Here is an overview of the things and channels:
- Light Control II (parent device)
- system channel
signal-strength
indicating communication quality - channels
power-consumption
andenergy-consumption
for combined power metering
- system channel
- Light Switch 1 (this is a logical child device of the parent device)
- system channel
power-switch
to control the light circuit - channel
child-protection
to control child protection (for each light switch circuit separately)
- system channel
- Light Switch 2 (this is a logical child device of the parent device)
- system channel
power-switch
to control the light circuit - channel
child-protection
to control child protection (for each light switch circuit separately)
- system channel
Currently the user sees three independent things in openHAB, but they belong to one single physical device. From a technical perspective, this is the most straight-forward mapping, but I'm aware that this might not be the most user-friendly one, since users might expect one thing per physical device. Indeed, @mike-bike who was so kind to test my code already mentioned that this might be counter-intuitive for users (see https://github.com/openhab/openhab-addons/issues/14562#issuecomment-1938346719).
However, my rationale for separating the things was that the channel names are always the same this way. If we combined all these channels into one thing then we would need to "number" certain channels like this:
- Light Control II (parent device)
- system channel
signal-strength
indicating communication quality - channels
power-consumption
andenergy-consumption
for combined power metering - system channel
power-switch-1
to control light circuit 1 - system channel
power-switch-2
to control light circuit 2 - channel
child-protection-1
to control child protection for light circuit 1 - channel
child-protection-2
to control child protection for light circuit 2
- system channel
The problem is that this does not scale well. For example, if devices are released in the future that allow more switch circuits or even more complex / mixed configurations (like shutter controls, dimmers, relays, light switches freely configurable) then the channels would have to be configured in a dynamic way. If we keep the thing separation, we can use "thing composition" to model the configuration.
What would be your preferred way to model this device and possible future devices in terms of the openHAB model? Are dynamic channel configurations possible and would you prefer it in this case?
Also: the Light Control II device has the bridge as parent device. Is it possible to model deeper parent-child relations, such as the Light Switch being a child of Light Control II (and therefore a grandchild of the bridge)?
Also: the Light Control II device has the bridge as parent device. Is it possible to model deeper parent-child relations, such as the Light Switch being a child of Light Control II (and therefore a grandchild of the bridge)?
Yes, that is possible, and I would actually suggest to go with your first proposition of separate things, but make the parent Light Control II a bridge. The Netatmo binding is one example of having multiple levels:
- account (logical bridge to reuse Netatmo cloud account across different weather stations)
- weather station (physical device connected to Wi-Fi)
- additional indoor module (physical battery-powered device with proprietary wireless connection to the weather station)
- outdoor module
- etc.
- weather station (physical device connected to Wi-Fi)
I do not think, that Netatmo actually fits to the Bosch device. Netatmo (and Weather Service providers etc) support user defined multiple βdevicesβ e.g. weather channels or weather stations etc. There the "root" thing acting as bridge makes sense. The Bosch device Light Control II is a well defined closed devise. It has 2 separate switches build into a fixed device. Even in future, if Bosch would provide more complex devices, they will have defined finite characteristics pending on the configuration. Having the Bosch root device act as bridge seems to me overkill.
Defined as Roller Shutter II it has:
- actual Power (W)
- cumulated Energy (Wh)
- Signal Strength
- Up
- Down
- Opening %
- Child protection
- plus addtl configuration items which may not be relevant for openHAB
Defined as Light Switch II it has:
- actual Power consumption (W)
- cumulated Energy (Wh)
- Signal Strength
- On/Off 1
- Child Protection 1
- automatic Timeout 1
- On/Off 2
- Child Protection 2
- automatic Timeout 2
Though, I do not have any idea about the implementation complexity to define dynamic channels, but to me it would make logical sense to have it as one thing.
Anyway, current setup works for me as well. I am happy about the support!
Thanks guys
Take care, Michael
I must say that this is no simple choice. If you model it as the suggested parent/child, i must agree with @mike-bike it feels a bit overcomplicated. From code perspective (re-use / composition) it suits good to have a parent child setup. From user perspective; i bought one device and when i add it in openHAB it is represented as three Things. That's somewhat strange. That is also where it differs to the netatmo binding as those child Things are actual different hardware devices.
About the scalability: don't know if you expect future devices with 3+ circuits, but i would not make this (not yet existing) problem a big issue. And if a device with many more circuits is introduced, it can allways be modeled as a parent/child device.
Anyway, not making it easier here, but i would sugggest a more 'flat' structure of the Thing with numbered channels. Similar to how the z-wave binding handles a two button switch.
Thank you very much for your input @jlaur, @lsiepel and @mike-bike.
After having experimented with the parent/child model with two bridges, I am not really satisfied with the user experience. The Light Shutter Control II seems much harder to configure than the other devices although it's not really such a different device.
Bosch exposes it as parent device with two child devices on the technical level, but this does not mean that the user (or the user interface) has to be aware of this technical representation.
Maybe we can clarify the following before we proceed:
- @mike-bike, can you tell us a bit about how this device is presented on the Bosch user interface (in the app)? Does it feel like one device or more like two devices? Does the user see anything related to the parent/child separation or does it rather feel like a single device that is configured?
- Thanks for the hint with the two-button switch in the Z-Wave binding, @lsiepel. I will take a look at the thing type definition and the handler code once I find some time in order to find out whether this model is more suitable in our case.
After that we might have more context information to make a decision. Thank you all for your input and support :+1:
That's a good question. Interestingly it is shown as two devices in the Bosch App, there is no parent. Both devices do have the power consumption and energy as attributes. They both show the same consolidated values, but if a device is switched off, it shows power consumption 0 even though the other may consume power. If it is on, it shows the one consolidated value. The signal strengths is not visible in any of the Light Switch devices. It will only become an option if the device is configured as Roller Shutter. That is an interesting alternative option (always a new way to look at things): two separate devices if configured as light switch and one device if configured as a roller shutter.
Please note, that I only can describe the visualization in the Bosch App and not the underlying software model. Similar view could be achieved in OpenHAB UI (e.g. by grouping) independent of the number of things.
(Edit: inline images removed. Happy to share via PM as needed)
@lsiepel I just tried to find the two-button z-wave switch, but I got lost because there are tons of thing definitions π Could you please direct me to a relevant thing definition and the corresponding handler implementation?
t tried to find the two-button z-wave switch, but
I'm not familiair with the z-wave code. My suggestions was purely from functional perspective. It is one device, that has 2-buttons. They are modelled exactly as @mike-bike suggested, so i would suggest to create something like: actual Power consumption (W) cumulated Energy (Wh) Signal Strength On/Off 1 Child Protection 1 automatic Timeout 1 On/Off 2 Child Protection 2 automatic Timeout 2
How to construct those channels in code from the Bosch devices is beyond my knowledge about this device. But i don't think it would be that difficult for you.
After having thought about the different possibilities for some time I'm now also in favor of this model (one thing type, numbered channels). I will provide an implementation as soon as possible :+1:
@jlaur, I hope that you are also OK with this approach since it's different from what you suggested previously.
@jlaur, I hope that you are also OK with this approach since it's different from what you suggested previously.
Definitely, it sounds like the best solution now when I have seen all arguments. π My proposal was made when not knowing all details, and was mostly to confirm that multiple layers of bridges is possible and sometimes useful. I agree on the more flat structure for this particular case confined by specific hardware with exactly two switches.
I just finished an implementation with a single thing type and re-uploaded the JAR :+1:
@mike-bike could you please download and test again? Note that it's important to delete all things and channels belonging to the old implementation, otherwise you might run into persistence / configuration issues. So the order should be
- delete all things and channels that have anything to do with Light Control II
- download and install JAR
- create a new Light Control II thing (in the best case the discovery will propose it, otherwise manually)
- test all channels
Done. Old channels and things deleted and new one identified as new thing activated. Items relinked. It seems to be working ok. One thing with all channels. Switch changes reflected immediately in Bosch App and vice versa. Update to power consumption a bit delayed in openHAB due to update latency. Will test a more tomorrow, but for now all is working fine.
Great work! Amazing, considering that you do not have that physical device available for testing!
Regards, Michael
Thanks for testing again and for your feedback β€οΈ That's really amazing considering the amount of code that was changed in the mean time :wink: I guess it does pay off to work with unit tests π
I'm working on code cleanups, some refactorings that are required now, maximizing unit test coverage and documentation. Will push some code soon. Stay tuned π
I pushed my changes and the PR is open for code reviews again π
Note for the reviewers @lsiepel @jlaur and @GerdZanker: it might be easier to compare against main
as opposed to the last commit that you reviewed, because commit 6 makes large parts of the code up to commit 5 obsolete.
@mike-bike I propose to wait until after the code reviews before the next (and hopefully last) test iteration. You need to test once more that all my refactorings worked and we might change the labels/identifiers (e.g. childId1
, childId2
) in the configuration. Nevertheless, I updated the JAR again in case you want to do intermediate tests anyways.
@mike-bike I propose to wait until after the code reviews before the next (and hopefully last) test iteration. You need to test once more that all my refactorings worked and we might change the labels/identifiers (e.g.
childId1
,childId2
) in the configuration. Nevertheless, I updated the JAR again in case you want to do intermediate tests anyways.
Hi @david-pace, I will wait until advised. Happy to test when you are ready.
I second Isiepelβs suggestion to sort and force a deterministic order as one option. In my PoV relying on the order of a result set is always risky unless it is a documented feature of the called function.Β Iβd ask the question why the order is relevant at all? If there is a sort criteria: Do you need to store the values in an ordered sequence? The idβs need to have a unique and deterministic identifier. I donβt know the details of the implementation but I could imagine that using an associative array/list would resolve the problem. Regards Michael
Hi @david-pace, I have wired and configured a new Light Module II and loaded the new JAR. I have labeled outlet Q1 as "taste 1" and outlet Q2 as "taste 2". In the Bosch App "taste 1" correctly triggers lamp wired to Q1.
I have not yet done thorough testing but wanted to share few observations:
"taste 2" is discovered first with index #3
.
2024-02-26 19:33:38.252 [TRACE] [rnal.discovery.ThingDiscoveryService] - Discovering device taste 2 2024-02-26 19:33:38.269 [TRACE] [rnal.discovery.ThingDiscoveryService] - - details: id hdm:ZigBee:3425b4fffe3fcb04#3, roomId hz_16, deviceModel MICROMODULE_LIGHT_ATTACHED
"taste 1" is discovered next with index #2
2024-02-26 19:33:38.273 [TRACE] [rnal.discovery.ThingDiscoveryService] - Discovering device taste 1 2024-02-26 19:33:38.275 [TRACE] [rnal.discovery.ThingDiscoveryService] - - details: id hdm:ZigBee:3425b4fffe3fcb04#2, roomId hz_16, deviceModel MICROMODULE_LIGHT_ATTACHED
However, the thing's properties are the other way around:
childId2 hdm:ZigBee:70ac08fffefead2d#2
childId1 hdm:ZigBee:70ac08fffefead2d#3
I'd expect childId1
to be mapped to #2
(aka Q1, taste 1) and
childId2
to be mapped to #3
(aka Q2, taste 2). With that the user will have consistent experience between openHAB and the physical device
- Id1-->Q1
- Id2-->Q2
Hope that makes sense.
I am now going to create the items and check functionality.
Regards, Michael
PS: Both discoveries above were throwing an error which I have not seen for a while:
2024-02-26 19:33:38.271 [DEBUG] [rnal.discovery.ThingDiscoveryService] - Unknown deviceModel 'MICROMODULE_LIGHT_ATTACHED'! Please create a support request issue for this unknown device model.
Hi @david-pace, items generated and linked to the new things.
Good news: the channels are triggering the correct switches:
- Powerswitch1 switches Q1 and
- Powerswitch2 switches Q2.
That's exactly what I was expecting! Child Protection On/Off changes state in Bosch App correctly. Power consumption is consistent with app as well.
Minor observation is, that the thing parameters childId1 and childId2 do not match the numbering of the channels.
I'd consider it helpful to have these shown as Thing Properties. It might help in case of any issues.
Good Work
Thanks for the tests, @mike-bike :heart:
It's very good to know that the child devices are ordered alphabetically in the Bosch app UI (but this is only a visualization/presentation aspect).
Also very good that you mentioned the numbering on the physical device (Q1 and Q2). Our goal should be that the openHAB channels align with the physical connectors (power-switch-1
should trigger Q1 and power-switch-2
should trigger Q2). In order to do that we need to find out what the relation is between Q1, Q2 and the two childDeviceIds
.
Two things:
- we completely eliminated the configuration parameters
childId1
andchildId2
. They should not appear anymore. Did you delete the thing before you tested my JAR? If not, please delete it and create it again. Then those two configuration parameters should be gone. - Can you please query the device info of the Light Control II (parent) device and report what you see in the
childDeviceIds
array? Example from your first device:
{
"@type": "device",
"childDeviceIds": [
"hdm:ZigBee:70ac08fffefead2d#3",
"hdm:ZigBee:70ac08fffefead2d#2"
],
"deviceModel": "MICROMODULE_LIGHT_CONTROL"
}
Does it look the same for your other Light Control II? Has it changed for the other device in the mean time or is the child ID order the same?
Good morning @mike-bike, I just noticed that I removed the configuration parameters, but there were still two childId
properties that were added during the automatic discovery. I removed this code and uploaded a new JAR :+1:
These properties are not needed anymore because the child device IDs are dynamically queried from the controller during the initialization of the parent device. I added logging for debugging purposes which you can see on DEBUG
or TRACE
level. The log entries look like this:
DEBUG: Initializing child devices of Light Control II, child device IDs from device info: {}
TRACE: Child device IDs for Light Control II after sorting: {}
DEBUG: Child device IDs for Light Control II configured successfully.
If you have suggestions on how to improve these log entries, please let me know.
I rebased everything on main
and also suppressed the log entry Unknown deviceModel 'MICROMODULE_LIGHT_ATTACHED'! Please create a support request issue for this unknown device model.
.
@mike-bike please test again with the new JAR and let me know how the childDeviceIds
arrays look (for both of your Light Control II devices) when you query the device list from the controller at /devices
.
I rebased everything on
main
and also suppressed the log entryUnknown deviceModel 'MICROMODULE_LIGHT_ATTACHED'! Please create a support request issue for this unknown device model.
.
I cannot see any such log entry with the new JAR any longer. ==> Fixed!
@mike-bike please test again with the new JAR and let me know how the
childDeviceIds
arrays look (for both of your Light Control II devices) when you query the device list from the controller at/devices
.
Deleted all items and things and loaded new JAR. Devices discovered and added to Inbox. I have added 1 device to the model and tested functionality:
- switch-1 and switch-2 consistent with Bosch naming and wiring
- switches and power meter working and in sync with Bosch app
For me it looks good!
Not sure what you mean by childDeviceIds
arrays. Is this the result set from create request for https://192.168.2.61:8444/smarthome/devices
?
If so, please see snipped below. However, I could not find any of the additional logs you have mentioned earlier. No "sorting" or "successfully"...
I have loaded the following:
-rw-r--r-- 1 openhabian openhab 7073827 Feb 27 08:07 org.openhab.binding.boschshc-4.2.0-SNAPSHOT-shutter-control-2.jar
265 β Active β 80 β 4.2.0.202402270706 β openHAB Add-ons :: Bundles :: Bosch Smart Home Binding
Here the relevant extract from the log:
{"@type":"device","rootDeviceId":"64-da-a0-10-83-a7","id":"hdm:ZigBee:3425b4fffe3fcb04#3","deviceServiceIds":["PowerSwitch","ChildProtection","PowerSwitchProgram"],"manufacturer":"BOSCH","roomId":"hz_16","deviceModel":"MICROMODULE_LIGHT_ATTACHED","serial":"3425B4FFFE3FCB04","profile":"GENERIC","iconId":"icon_mm_light_generic","name":"taste 2","status":"AVAILABLE","parentDeviceId":"hdm:ZigBee:3425b4fffe3fcb04","childDeviceIds":[],"supportedProfiles":[]},{"@type":"device","rootDeviceId":"64-da-a0-10-83-a7","id":"hdm:ZigBee:3425b4fffe3fcb04#2","deviceServiceIds":["PowerSwitch","ChildProtection","PowerSwitchProgram"],"manufacturer":"BOSCH","roomId":"hz_16","deviceModel":"MICROMODULE_LIGHT_ATTACHED","serial":"3425B4FFFE3FCB04","profile":"GENERIC","iconId":"icon_mm_light_generic","name":"taste 1","status":"AVAILABLE","parentDeviceId":"hdm:ZigBee:3425b4fffe3fcb04","childDeviceIds":[],"supportedProfiles":[]}
2024-02-28 21:58:20.459 [TRACE] [rnal.discovery.ThingDiscoveryService] - Discovering device LightMM_3425b4fffe3fcb04
2024-02-28 21:58:20.461 [TRACE] [rnal.discovery.ThingDiscoveryService] - - details: id hdm:ZigBee:3425b4fffe3fcb04, roomId null, dev iceModel MICROMODULE_LIGHT_CONTROL
2024-02-28 21:58:20.462 [TRACE] [rnal.discovery.ThingDiscoveryService] - - got thingTypeID 'light-control-2' for deviceModel 'MICROM ODULE_LIGHT_CONTROL'
2024-02-28 21:58:20.464 [TRACE] [rnal.discovery.ThingDiscoveryService] - - got thingUID 'boschshc:light-control-2:192-168-2-61:hdm_ZigBee_3425b4fffe3fcb04' for device: 'Type device; RootDeviceId: 64-da-a0-10-83-a7; Id: hdm:ZigBee:3425b4fffe3fcb04; Device Service Ids: CommunicationQuality, PowerMeter, ElectricalFaults, SwitchConfiguration; Manufacturer: BOSCH; Room Id: null; Device Model: MICROMODULE_LIGHT_CONTROL; Serial: 3425B4FFFE3FCB04; Profile: GENERIC; Name: LightMM_3425b4fffe3fcb04; Status: AVAILABLE; Child Device Ids: hdm:ZigBee:3425b4fffe3fcb04#3, hdm:ZigBee:3425b4fffe3fcb04#2 '
2024-02-28 21:58:20.477 [INFO ] [g.discovery.internal.PersistentInbox] - Added new thing 'boschshc:light-control-2:192-168-2-61:hdm_ZigBee_3425b4fffe3fcb04' to inbox.
2024-02-28 21:58:20.481 [DEBUG] [rnal.discovery.ThingDiscoveryService] - Discovered device 'LightMM_3425b4fffe3fcb04' with thingTypeUID=boschshc:light-control-2:192-168-2-61:hdm_ZigBee_3425b4fffe3fcb04, thingUID=boschshc:light-control-2, id=hdm:ZigBee:3425b4fffe3fcb04, deviceModel=MICROMODULE_LIGHT_CONTROL
Please let me know if I can help any further.
PS: How do I get the code snippes into the browser window without breaking the lines whenever I paste from the terminal window?
@david-pace , correction! I did a restart after clearing the cache. After a while (the PI2 is soooo slooooow) I think I found what you were asking for (pls ignore the ugly formatting):
2024-02-28 22:54:01.932 [TRACE] [es.lightcontrol.LightControl2Handler] - Device validated and initialized: Type device; RootDeviceId: 64-da-a0-10-83-a7; Id: hdm:ZigBee:70ac08fffefead2d; Device Service Ids: PowerMeter, CommunicationQuality, ElectricalFaults, SwitchConfiguration; Manufacturer: BOSCH; Room Id: null; Device Model: MICROMODULE_LIGHT_CONTROL; Serial: 70AC08F FFEFEAD2D; Profile: GENERIC; Name: LightMM_70ac08fffefead2d; Status: AVAILABLE; Child Device Ids: hdm:ZigBee:70ac08fffefead2d#3, hdm :ZigBee:70ac08fffefead2d#2 2024-02-28 22:54:01.935 [DEBUG] [es.lightcontrol.LightControl2Handler] - Initializing child devices of Light Control II, child device IDs from device info: [hdm:ZigBee:70ac08fffefead2d#3, hdm:ZigBee:70ac08fffefead2d#2] 2024-02-28 22:54:01.937 [TRACE] [es.lightcontrol.LightControl2Handler] - Child device IDs for Light Control II after sorting: [hdm:ZigBee:70ac08fffefead2d#2, hdm:ZigBee:70ac08fffefead2d#3]
Hi @mike-bike, thank you so much for testing again π
You can paste code, log files etc. in so called fenced code blocks. Begin and end a block with triple backticks like this:
```
Code or logfile goes here
```
Thanks to your analysis we now know that the Smart Home Controller seems to list the child device IDs in a somewhat strange order. For both of your devices, we first get #3
and then #2
:
- Shutter Control II
hdm:ZigBee:70ac08fffefead2d
(Brunnen, Olivenbaum)-
hdm:ZigBee:70ac08fffefead2d#3
-
hdm:ZigBee:70ac08fffefead2d#2
-
- Shutter Control II
hdm:ZigBee:3425b4fffe3fcb04
(the newer one wired for testing purposes)-
hdm:ZigBee:3425b4fffe3fcb04#3
-
hdm:ZigBee:3425b4fffe3fcb04#2
-
It looks like #2
always corresponds to the physical Q1 pin and #3
to Q2. Since the implementation sorts the child device IDs, this association is guaranteed.
It looks like we could even hardcode the child device IDs to [parent device ID]#2
and [parent device ID]#3
but I propose to leave the code as it is and ask the controller for the child device IDs dynamically. There is no performance impact compared to the current release because we contact the controller anyway to get the device info (previously only to validate that the parent device ID is valid, now we also process the already parsed JSON result and check the child device IDs).
In this case I would say the code is open for code reviews again π
Thank you very much for your testing support @mike-bike β€οΈ
Note to the reviewers @GerdZanker, @jlaur and @lsiepel: I created two additional PRs on top of this one:
- https://github.com/openhab/openhab-addons/pull/16500 (this adds additional unit tests)
- https://github.com/openhab/openhab-addons/pull/16501 (this adds support for yet another device)
The other two PRs are much easier to review once this PR is merged, because otherwise all the commits from this PR will "clutter" the other PRs. I will therefore wait until this PR is reviewed and merged, then rebase the other ones, and then add you as reviewers.
It's not time-critical since we are not talking about bugfixes, but rather about functional enhancements and stability improvements through tests. I just wanted to let you know that this PR kind of "blocks" the other PRs and that I have prepared more code already π
@lsiepel - it looks like your review is almost finished according to https://github.com/openhab/openhab-addons/pull/16400#pullrequestreview-1876361747. Just checking if you will be able to finish your review, perhaps it just got off your radar? π I had a brief look myself, and it looks nice and clean to me (as usual). π
Nice, to see this growing support of more and more devices. Thank you @david-pace
Hi Guys, I just opened another opportunity to grow even further: #16590 π
Have a great weekend
Regards, Michael