core
core copied to clipboard
HomeKit Valve Support
The problem
Currently when adding a HomeKit device with a valve (specifically the U by Moen Shower) it shows up as a climate entity. This actually causes the device to be inoperable.
The device exposes:
- a valve (currently interpreted as a climate entity)
- two (or four depending on the model) shower "outlets" (heads) as switch entities
- a temperature sensor as a sensor entity
- an identify button as a button entity
Setting the climate mode to "Heat" (which is where it ends up if you turn it on manually) does not actually turn on the shower. Setting it to off also does not work once turned on manually.
The temperature setting does work correctly, and the individual shower heads (outlets) can be turned on and off once the shower itself is turned on.
The reason it shows up as a climate entity is because until 2024.10, HA did not support Valve entities.
With the addition of Valve entity type this long-standing bug can be fixed and hopefully it will resolve the on/off issue.
This was previously mentioned in #66345 but at the time Valves were unsupported.
What version of Home Assistant Core has the issue?
core-2024.10.0
What was the last working version of Home Assistant Core?
No response
What type of installation are you running?
Home Assistant OS
Integration causing the issue
homekit_controller
Link to integration documentation on our website
https://www.home-assistant.io/integrations/homekit_controller
Diagnostics information
No response
Example YAML snippet
No response
Anything in the logs that might be useful for us?
No response
Additional information
No response
Hey there @jc2k, @bdraco, mind taking a look at this issue as it has been labeled with an integration (homekit_controller) you are listed as a code owner for? Thanks!
Code owner commands
Code owners of homekit_controller can trigger bot actions by commenting:
@home-assistant closeCloses the issue.@home-assistant rename Awesome new titleRenames the issue.@home-assistant reopenReopen the issue.@home-assistant unassign homekit_controllerRemoves the current integration label and assignees on the issue, add the integration domain after the command.@home-assistant add-label needs-more-informationAdd a label (needs-more-information, problem in dependency, problem in custom component) to the issue.@home-assistant remove-label needs-more-informationRemove a label (needs-more-information, problem in dependency, problem in custom component) on the issue.
(message by CodeOwnersMention)
homekit_controller documentation homekit_controller source (message by IssueLinks)
The new entity type does not help and lack of it was not the problem.
We create a climate entity in this case because your shower either exposes (in homekit terms) a thermostat service or a heater/cooler service. The outlets are the valves. And if we turned the outlets into valves we would still need a temperature control entity. Home Assistant valves on their own do not have temperature control.
The real problem was there is a lack of public documentation about the homekit "faucet" service. Previously i've read "faucet" as the uk english "tap", like an additional outlet. But based on your description of the problem, it is likely the on/off switch for the entire system, rather than a valve. In HomeKit, a valve has an "in use" characteristic when water is flowing through it. The faucet type does not. In Home Assistant, a valve has properties like how open it is. A faucet does not.
So it's likely that just adding a new switch type that binds to faucet would fix this.
@Jc2k is there anything I can provide that might help resolve this? It's a little hard to understand that there is the valve inside the wall which is independent of the outlets (shower heads). When you turn on the device using the physical button it turns on both the bit in the wall to start mixing hot and cold water to temp and the first outlet. It can also be set to "pause" once it gets to temp to keep the water ready for you to shower but turning off the outlets to avoid wasting water.
As I said, there issue right now is that it doesn't turn on the in-wall valve part that current shows as a climate control (the control panel is always powered FYI) so even when you turn on the outlets there is no water flow (and the panel doesn't reflect the outlet on state).
Setting the climate control mode to heat and then opening an outlet also doesn't work as the control mode change doesn't actually turn on the valve.
The extra context you have provided should be enough. Though an updated diagnostics JSON download would be helpful.
Now it's just time. Which is in short supply, unfortunately.
@Jc2k attached is a diagnostics JSON, thanks for your time so far!
homekit_controller-01J9BG63P7J3RT1T2SP774Q1W5-U by Moen-011FD9-f404484da552ee3d0c2df9a345595262.json
I have been looking into this as well and found the Faucet type documented here: https://forum.iobroker.net/assets/uploads/files/1634848447889-apple-spezifikation-homekit.pdf
I was looking at it using the HomeDevices App: https://apps.apple.com/us/app/homedevices-for-homekit/id1582369733
This app shows the "Faucet" service listed as the primary service and it has an "Active" characteristic. My assumption is that toggling this to active will allow the other aspects of the valve to work. As @dshafik noted, if you manually turn on the shower you can control the individual valves and temperature but until the main control is "on" which I assume is this "Faucet" service, the other controls are inoperable.
This also looks like how the system may handle Presets. In the native Moen app you can define a preset as a set of valves being on or off and a temperature set point. I assume behind the scenes that these simply set the various valve states + temperature and set the main faucet service to "Active".
I was hoping to run some tests on my local unit but I am not entirely sure where to start with getting a 'dev' environment setup where I can modify the homekit_controller code to try setting that service as "Active"
The HomeKitValve class defined here: https://github.com/home-assistant/core/blob/dev/homeassistant/components/homekit_controller/switch.py#L105 looks like a good starting point. Would we simply need to make a new HomeKitFaucet with the 'Active' characteristic mapped and then add that as a mapped service to a Switch?
Don't pay too much attention to HomeKitValve because its a "valve". It's a switch, not a valve. At somepoint it needs reimplementing as a valve, thats a new entity type that homekit_controller doesn't ahve yet (https://developers.home-assistant.io/docs/core/entity/valve) and a breaking change.
I have the R2 HomeKit spec. It does have some information on the faucet service, but I find it lacking on how the linked services interact. Part of that is because its describing what the accessory must do, and not what the controller must do (theres no public documentation for implementing controllers).
The big sticking point for this has been more of a philosophical one than a technical one. Is a faucet a switch or a valve? Many people think of it is a tap, right? So surely it should be a valve, not a switch. But why make a dedicated service? If it's modelling a Valve, why not have another Valve service. Also, the information we do have from Apple make it sound like the on/off switch the the system as a whole.
I have been swayed both ways on this now. Ultimately, we will only ever have on or off for this. The other valves in the system don't work unless the system is "switched on". You can't have a Faucet without a Valve. So I think a HomeKit "Faucet" is a switch for a system made up of one or more valves.
If you agree with that, what we need is:
- A new entity in switch.py, probably based on HomeKitSwitch, but remove
extra_state_attributesentirely, CharacteristicsTypes.ON becomes CharacteristicsTypes.ACTIVE. - Also in switch.py, update ENTITY_TYPES to map ServicesTypes.FAUCET to your new entity class.
- In const.py, update HOMEKIT_ACCESSORY_DISPATCH to link ServicesTypes.FAUCET to the switch platform.
That should be enough to make it work. Then for your pull request:
- Update tests/components/homekit_controller/test_switch.py. You'll need a create_faucet_service, test_faucet_change_outlet_state and test_switch_read_faucet_state based on the switch versions.
- Add diagnostic json to components/homekit_controller/fixtures. You can get this by downloading a JSON diagnostic from your production home assistant for this device. Not the entire file, just the "entity-map" part.
- Run the tests for homekit_controller and tell them to update syrupy. pytest -k homekit_controller --snapshot-update (see https://developers.home-assistant.io/docs/development_testing/#snapshot-testing).
We already added Faucet to aiohomekit, so I don't think you'll need to change it.
Makes sense. I feel like we can learn a lot about the behavior if we can send command to set the Faucet Active state to true and observe how the other services react. I know from the physical control that when I press on, i can see the climate entity change to heat and the temperature change to the preconfigured setpoint. Additionally the valve switch for the main shower head turns on.
I am curious how the expect "presets" to work. i.e. can i just send all the parameters together (temperature set point, valves, and faucet) or do i need to sequence them by setting setupoint and valves and then toggling faucet once that is done.
With your suggestions I think i can get an initial test going. While I have extensive Python experience, this is my first attempt at changing a Home Assistant component. I am currently running HA on a Yellow board. Do you have any suggestions in how to setup a dev environment or to deploy the changes I make to homekit_controller to my production instance to test.
If possible I would like to avoid re-registering the HomeKit side of the Moen shower as that pairing process can be a bit fiddly in their implementation, but if thats the only way to test then so be it.
What desktop machine would you be developing on? Windows? Mac? Linux?
I am on a Mac
Ok, great news - i figured out how to override homekit_controller in my installation using the 'custom_components' folder.
I did the steps you outlined in your first 3 bullet points and after rebooting HA a new switch entity was created. Toggling this setting on was initially the same as pressing the power button on the Moen wall controller. The shower turned on, went to the default temperature, and water came out of valve 1 (the main shower head).
From here I could modify the temperature, turn on other shower heads, etc.
Here are some notable observations:
- If you shut off all valves, the controller remains "active" and displays "Shower is paused" on the controller.
- If you toggle valves on BEFORE you set the main service to active, then when you toggle the main service active, those valves will be used instead of the default.
- The state of these toggles will be remembered by the controller internally. So If i toggle off the main service/controller, you will see all the entities toggle off in HA, but if i turn the main service back on the valves previously turned on via HomeKit will come back on. This has some interesting flows in that it is internally remembering state even when off but that "remembered" state is not reflected in the HA entites (i.e. they show off when the main controller is off).
- I can revert to "default" behavior by toggling the valves that were "remembered" on and then off while the main service is off. This is not the case if you turn the valves off while the main service is active. If that is done, the "remembered" state will come back next time you turn on the main service.
- The remembered state is lost when the power is cut from the Moen controller (i.e. reboot of the device)
- I am still not sure how the native HomeKit integration populates presets. I wonder if perhaps the App does some injecting of them because I remember back when I had the Moen linked to my Apple TV, i initially did not see any presets come through, but then some days later (perhaps after opening the app and triggering something unknowingly) they populated in the Apple Home app and i could trigger them. Not that I am overly concerned with them for Home Assistant as I can simply invent my own presets by toggling the relevant switches via automation/scene
Needless to say, this is all extremely exciting to me. This was one of the last items in my house that was cloud dependent for it to work and this fix will allow it to operate 100% local 😁
Let me know if there any other scenarios you think I should test. One interesting thing in my mind is if there is a way to reflect that "remembered" state into the Valves so that they dont need the weird toggle on/off to reset them to off when their "internal" state is on.
The notes sound like the behaviour is reasonable, and it doesn't sound like we need any "compound" actions (turning a valve and faucet active in the same API call etc).
Presets (if you mean homekit scenes?) are as you say. Theres nothing in the HomeKit Accessory Protocol for scenes, its all handled at the iOS app level.
Looking forward to a PR, then :-) If you make a PR, I can review it, the cut off for merging stuff for the November release is next Wednesday, so there is still time to slip it in.
I also propose we rename this issue to be "HomeKit Faucet Support" since Valves are already mapped to a switch, but the Faucet is the new component here.