zigpy / zha-device-handlers

ZHA device handlers bridge the functionality gap created when manufacturers deviate from the ZCL specification, handling deviations and exceptions by parsing custom messages to and from Zigbee devices.
Apache License 2.0
683 stars 634 forks source link

Bosch RBSH-RTH0-ZB-EU Thermostat II switch between heating and cooling #2707

Open metallmanu opened 8 months ago

metallmanu commented 8 months ago

Problem description

The Bosch Smart Home Thermostat II Supports heating and cooling in the Bosch Smart Home App. Unfortunately this switch between heating and cooling is not possible through ZHA in Homeassistant. Over climate.set_hvac_mode it is only possible to switch between off and heating

Solution description

The hvac_modes cooling, heating and off are possible to choose

Screenshots/Video

Screenshots/Video [Paste/upload your media here]

Device signature

Device signature ```json { "node_descriptor": "NodeDescriptor(logical_type=, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=, mac_capability_flags=, manufacturer_code=4617, maximum_buffer_size=82, maximum_incoming_transfer_size=255, server_mask=11264, maximum_outgoing_transfer_size=255, descriptor_capability_field=, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)", "endpoints": { "1": { "profile_id": "0x0104", "device_type": "0x0301", "input_clusters": [ "0x0000", "0x0003", "0x0201", "0x0204", "0x0405", "0x0b05" ], "output_clusters": [ "0x000a", "0x0019" ] } }, "manufacturer": "Bosch", "model": "RBSH-RTH0-ZB-EU", "class": "zigpy.device.Device" } ```

Diagnostic information

Diagnostic information ```json { "home_assistant": { "installation_type": "Home Assistant OS", "version": "2023.11.1", "dev": false, "hassio": true, "virtualenv": false, "python_version": "3.11.6", "docker": true, "arch": "x86_64", "timezone": "Europe/Berlin", "os_name": "Linux", "os_version": "6.1.59", "supervisor": "2023.10.1", "host_os": "Home Assistant OS 11.1", "docker_version": "24.0.6", "chassis": "vm", "run_as_root": true }, "custom_components": { "hacs": { "version": "1.33.0", "requirements": [ "aiogithubapi>=22.10.1" ] }, "waste_collection_schedule": { "version": "1.43.0", "requirements": [ "icalendar", "recurring_ical_events", "icalevents", "bs4", "lxml" ] }, "localtuya": { "version": "5.2.1", "requirements": [] }, "dwd_weather": { "version": "v2.0.12", "requirements": [ "simple_dwd_weatherforecast==2.0.23", "markdownify==0.6.5", "suntimes==1.1.2" ] }, "roborock": { "version": "1.0.12", "requirements": [ "python-roborock==0.34.6", "ical==5.0.0" ] } }, "integration_manifest": { "domain": "zha", "name": "Zigbee Home Automation", "after_dependencies": [ "onboarding", "usb" ], "codeowners": [ "@dmulcahey", "@adminiuga", "@puddly" ], "config_flow": true, "dependencies": [ "file_upload" ], "documentation": "https://www.home-assistant.io/integrations/zha", "iot_class": "local_polling", "loggers": [ "aiosqlite", "bellows", "crccheck", "pure_pcapy3", "zhaquirks", "zigpy", "zigpy_deconz", "zigpy_xbee", "zigpy_zigate", "zigpy_znp", "universal_silabs_flasher" ], "requirements": [ "bellows==0.36.8", "pyserial==3.5", "pyserial-asyncio==0.6", "zha-quirks==0.0.106", "zigpy-deconz==0.21.1", "zigpy==0.59.0", "zigpy-xbee==0.19.0", "zigpy-zigate==0.11.0", "zigpy-znp==0.11.6", "universal-silabs-flasher==0.0.14", "pyserial-asyncio-fast==0.11" ], "usb": [ { "vid": "10C4", "pid": "EA60", "description": "*2652*", "known_devices": [ "slae.sh cc2652rb stick" ] }, { "vid": "1A86", "pid": "55D4", "description": "*sonoff*plus*", "known_devices": [ "sonoff zigbee dongle plus v2" ] }, { "vid": "10C4", "pid": "EA60", "description": "*sonoff*plus*", "known_devices": [ "sonoff zigbee dongle plus" ] }, { "vid": "10C4", "pid": "EA60", "description": "*tubeszb*", "known_devices": [ "TubesZB Coordinator" ] }, { "vid": "1A86", "pid": "7523", "description": "*tubeszb*", "known_devices": [ "TubesZB Coordinator" ] }, { "vid": "1A86", "pid": "7523", "description": "*zigstar*", "known_devices": [ "ZigStar Coordinators" ] }, { "vid": "1CF1", "pid": "0030", "description": "*conbee*", "known_devices": [ "Conbee II" ] }, { "vid": "10C4", "pid": "8A2A", "description": "*zigbee*", "known_devices": [ "Nortek HUSBZB-1" ] }, { "vid": "0403", "pid": "6015", "description": "*zigate*", "known_devices": [ "ZiGate+" ] }, { "vid": "10C4", "pid": "EA60", "description": "*zigate*", "known_devices": [ "ZiGate" ] }, { "vid": "10C4", "pid": "8B34", "description": "*bv 2010/10*", "known_devices": [ "Bitron Video AV2010/10" ] } ], "zeroconf": [ { "type": "_esphomelib._tcp.local.", "name": "tube*" }, { "type": "_zigate-zigbee-gateway._tcp.local.", "name": "*zigate*" }, { "type": "_zigstar_gw._tcp.local.", "name": "*zigstar*" }, { "type": "_uzg-01._tcp.local.", "name": "uzg-01*" }, { "type": "_slzb-06._tcp.local.", "name": "slzb-06*" } ], "is_built_in": true }, "data": { "ieee": "**REDACTED**", "nwk": 21837, "manufacturer": "Bosch", "model": "RBSH-RTH0-ZB-EU", "name": "Bosch RBSH-RTH0-ZB-EU", "quirk_applied": false, "quirk_class": "zigpy.device.Device", "quirk_id": null, "manufacturer_code": 4617, "power_source": "Mains", "lqi": 176, "rssi": -56, "last_seen": "2023-11-07T09:42:08", "available": true, "device_type": "Router", "signature": { "node_descriptor": "NodeDescriptor(logical_type=, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=, mac_capability_flags=, manufacturer_code=4617, maximum_buffer_size=82, maximum_incoming_transfer_size=255, server_mask=11264, maximum_outgoing_transfer_size=255, descriptor_capability_field=, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)", "endpoints": { "1": { "profile_id": "0x0104", "device_type": "0x0301", "input_clusters": [ "0x0000", "0x0003", "0x0201", "0x0204", "0x0405", "0x0b05" ], "output_clusters": [ "0x000a", "0x0019" ] } }, "manufacturer": "Bosch", "model": "RBSH-RTH0-ZB-EU" }, "active_coordinator": false, "entities": [ { "entity_id": "button.bosch_rbsh_rth0_zb_eu_identifizieren", "name": "Bosch RBSH-RTH0-ZB-EU" }, { "entity_id": "climate.bosch_rbsh_rth0_zb_eu_thermostat", "name": "Bosch RBSH-RTH0-ZB-EU" }, { "entity_id": "sensor.bosch_rbsh_rth0_zb_eu_luftfeuchtigkeit", "name": "Bosch RBSH-RTH0-ZB-EU" }, { "entity_id": "sensor.bosch_rbsh_rth0_zb_eu_hlk_aktion", "name": "Bosch RBSH-RTH0-ZB-EU" } ], "neighbors": [], "routes": [], "endpoint_names": [ { "name": "THERMOSTAT" } ], "user_given_name": null, "device_reg_id": "7da0a02f9362df499ed16a6c119f7f83", "area_id": null, "cluster_details": { "1": { "device_type": { "name": "THERMOSTAT", "id": 769 }, "profile_id": 260, "in_clusters": { "0x0000": { "endpoint_attribute": "basic", "attributes": { "0x0003": { "attribute_name": "hw_version", "value": 0 }, "0x0004": { "attribute_name": "manufacturer", "value": "Bosch" }, "0x0005": { "attribute_name": "model", "value": "RBSH-RTH0-ZB-EU" } }, "unsupported_attributes": { "0x0014": { "attribute_name": "disable_local_config" }, "0x000c": { "attribute_name": "manufacturer_version_details" } } }, "0x0003": { "endpoint_attribute": "identify", "attributes": { "0xfffd": { "attribute_name": "cluster_revision", "value": 2 } }, "unsupported_attributes": {} }, "0x0201": { "endpoint_attribute": "thermostat", "attributes": { "0x001b": { "attribute_name": "ctrl_sequence_of_oper", "value": 0 }, "0x0000": { "attribute_name": "local_temperature", "value": 2310 }, "0x0018": { "attribute_name": "max_cool_setpoint_limit", "value": 3000 }, "0x0016": { "attribute_name": "max_heat_setpoint_limit", "value": 3000 }, "0x0017": { "attribute_name": "min_cool_setpoint_limit", "value": 500 }, "0x0015": { "attribute_name": "min_heat_setpoint_limit", "value": 500 }, "0x0002": { "attribute_name": "occupancy", "value": 0 }, "0x0011": { "attribute_name": "occupied_cooling_setpoint", "value": 2400 }, "0x0012": { "attribute_name": "occupied_heating_setpoint", "value": 1800 }, "0x0029": { "attribute_name": "running_state", "value": 0 }, "0x0030": { "attribute_name": "setpoint_change_source", "value": 2 }, "0x001c": { "attribute_name": "system_mode", "value": 3 } }, "unsupported_attributes": { "0x0004": { "attribute_name": "abs_max_heat_setpoint_limit" }, "0x001e": { "attribute_name": "running_mode" }, "0x0003": { "attribute_name": "abs_min_heat_setpoint_limit" }, "0x0005": { "attribute_name": "abs_min_cool_setpoint_limit" }, "0x0007": { "attribute_name": "pi_cooling_demand" }, "0x0008": { "attribute_name": "pi_heating_demand" }, "0x0006": { "attribute_name": "abs_max_cool_setpoint_limit" }, "0x0013": { "attribute_name": "unoccupied_cooling_setpoint" }, "0x0014": { "attribute_name": "unoccupied_heating_setpoint" } } }, "0x0204": { "endpoint_attribute": "thermostat_ui", "attributes": {}, "unsupported_attributes": {} }, "0x0405": { "endpoint_attribute": "humidity", "attributes": { "0x0000": { "attribute_name": "measured_value", "value": 5667 } }, "unsupported_attributes": {} }, "0x0b05": { "endpoint_attribute": "diagnostic", "attributes": { "0xfffd": { "attribute_name": "cluster_revision", "value": 3 } }, "unsupported_attributes": { "0x0000": { "attribute_name": "number_of_resets" } } } }, "out_clusters": { "0x000a": { "endpoint_attribute": "time", "attributes": {}, "unsupported_attributes": {} }, "0x0019": { "endpoint_attribute": "ota", "attributes": {}, "unsupported_attributes": {} } } } } } } ```

Logs

Logs ```python [Paste the logs here] ```

Custom quirk

Custom quirk ```python [Paste your custom quirk here] ```

Additional information

No response

jclsn commented 8 months ago

I am planning to write a quirk to expose all of the endpoints to Home Assistant.

For now you can set the available modes by

-> going to the ZHA device page -> pressing the dot menu -> selecting "manage zigbee device" -> thermostat endpoint -> ctrl_sequence_of_oper (id: 0x001b) -> read current value (and post it here) :)

I have found the following so far

ControlSequenceOfOperation.Heating_Only ControlSequenceOfOperation.Cooling_Only

But there is probably an easier way to query all possible values from the device.

Ah, here they are: https://docs.bosch-iot-suite.com/gateway-software/API/modules/com.prosyst.mbs.zigbee.driver.api/com/prosyst/mbs/services/zigbee/zcl/hvac/ThermostatCluster.html

metallmanu commented 8 months ago

I am planning to write a quirk to expose all of the endpoints to Home Assistant.

For now you can set the available modes by

-> going to the ZHA device page -> pressing the dot menu -> selecting "manage zigbee device" -> thermostat endpoint -> ctrl_sequence_of_oper (id: 0x001b) -> read current value (and post it here) :)

I have found the following so far

ControlSequenceOfOperation.Heating_Only ControlSequenceOfOperation.Cooling_Only

But there is probably an easier way to query all possible values from the device.

Ah, here they are: https://docs.bosch-iot-suite.com/gateway-software/API/modules/com.prosyst.mbs.zigbee.driver.api/com/prosyst/mbs/services/zigbee/zcl/hvac/ThermostatCluster.html

Hey wow thats great. When I checked the cluster for me there are also Only the values ControlSequenceOfOperation.Heating_Only ControlSequenceOfOperation.Cooling_Only

Would be very nice to see a quirk for this 👏

metallmanu commented 8 months ago

If it is possible you can also add the Installation mode for the heating: 230V, 24V or Boiler and if there are NO or NC valves

jclsn commented 8 months ago

@metallmanu There are also

ControlSequenceOfOperation.Heating_With_Reheat
ControlSequenceOfOperation.Cooling_With_Reheat

The others with the 4_Pipes from the specification do not work. No idea what they are for. Anyway, I think the issue is that the only SystemMode settings are

SystemMode.Heat
SystemMode.Cool

There is not SystemMode.Off, that HA would probably expect. I guess I would need to map it to Off.

You can find all working Endpoints I could identify yesterday here

https://github.com/zigpy/zha-device-handlers/issues/2476#issuecomment-1796390877

Feel free to test it out and maybe extend the list. My thermostat seems to have connection issues and I may have missed some.

jclsn commented 8 months ago

If it is possible you can also add the Installation mode for the heating: 230V, 24V or Boiler and if there are NO or NC valves

Oh, we may not have the same thermostat. I have the TRV for radiators. Not sure if this supports boilers etc. I could maybe support it as well though.

metallmanu commented 8 months ago

Oh yes it is another thermostat. I added the signature and diagnostic of mine. But it seems to be very similar to yours in states. For me the SystemMode.Off is working. image

jclsn commented 8 months ago

That is odd. I do have this one

grafik

Isn't yours a radiator thermostat as well? There may be many different version then.

metallmanu commented 8 months ago

I have this one:

image

It is for underfloor heating with cable system 230V. Therefore the cooling part is neccessary when you have a heat pump which can also cool the underfloor and also the valves control would be nice, because there are valves which are normaly open and some which are normaly closed. Hopefully your quirk will also work for this

jclsn commented 8 months ago

I see. I just don't see how my radiator valve would be cooling anything. Radiators only heat usually. Really weird!

metallmanu commented 8 months ago

When you have a Heating pump instead of Oil, Gas etc. you can let cold water Flow through your heating cycle. Therefore you have to put the thermostat also in cooling Mode, so that the valve is Open when you want a cooler temperature and cold water can flow through your Radiator

jclsn commented 8 months ago

Interesting. That makes sense. Guess it is a quite sophisticated thermostat. It is a pity that I am losing the connection frequently. I have to take out the batteries to be able to access it again. I put back the Tado now that I want to get rid of and will buy a radiator valve tomorrow, so the thermostat can calibrate itself to something. I will then try to implement the quirk.

I think the quirk for your device will be quite similar. There may be some endpoints working that don't work on mine and vice versa. Would be good if you could test those endpoints out, see what they return, compile a similar chart and post it here. On the Bosch documentation page you will find some examples. Some of them might be named a little differently though.

Ha! It seems like you can download diagnostic information using the button and it will show you all supported and unsupported attributes!

metallmanu commented 8 months ago

Yes the diagnostic is in my first post. Do you need more?

jclsn commented 8 months ago

Well, a bit of patience I guess. I have only edited a quirk so far. A have just tried zigbee2mqtt and everything is supported there. Even endpoints that do not work with ZHA. I wonder why that is.

Pity that @dmulcahey is not responding atm. He is usually a great help!

markoberholzer-es commented 6 months ago

Hi @metallmanu, @jclsn - I stubled accross this thread as I am facing the same issue with my Bosch Thermostat II 230V. Thx to your hints, I created a small quirk which enhances the Thermostat with the possibility to switch it into cooling mode.

However the widget now shows an additional button (the one on the left), which seems to be the auto mode, which is not supported by the affected thermostat.

grafik

Maybe you guys know how to remove that auto mode ?

Here is the simple quirk that I have written: rsbh_rth0_zb_eu.py.zip

jclsn commented 6 months ago

@markoberholzer-es

A quirk only adds missing attributes that don't comply with the Zigbee specification. It does NOT at all determine what you see in Home Assistant.

The ZHA code takes care of creating entities for those attributes. There are e.g. different cluster handlers Tuya devices that creates entities for Tuya custom attributes. None of this exists for Bosch and therefore ZHA tries to create entities according to the Zigbee specification. The problem is though that Bosch exposes "Pause", "Manual" and "Schedule/Auto" on one attribute and "Cool" and "Heat" on another. My idea would be to combine these somehow in a Bosch thermostat cluster handler.

So you will not be able to fix it from the quirk side. The Bosch cluster handlers have to be added to the HA core, where ZHA lives. Probably here somewhere

https://github.com/home-assistant/core/blob/dev/homeassistant/components/zha/climate.py

I don't have the time or expertise yet to implement that unfortunately. It is also not documented specifically for ZHA. I guess if you know how to create general entities for HA, which is very well documented, it should not be too hard though.

markoberholzer-es commented 6 months ago

Appologies @jclsn, if my comment upset you - I just wanted to share my findings after hours of digging through the repository.

I read through the Zigbee Cluster Library Specification and the problem is that the ctrl_sequence_of_oper attribute of ther thermostat is set to Heating Only (0x02). The quirk that I posted fixes that and it is now possible to change the modes through the GUI - the only issue is, as I mentioned, that the thermostat does not support the hvac mode heat_cool - so possibly this has to be fixed in HA core.

grafik

jclsn commented 6 months ago

@markoberholzer-es No reason to be sorry. I just confused this with the other thread where a few people have asked the same thing over and over. I can also be quite impulsive sometimes. I edited the post to make it easier to understand and sound a bit nicer hopefully :)

Yeah, there are different attributes. The ctrl_sequence_of_oper exists for almost every thermostat afaik and is never exposed in HA. If you want to have it, it would probably be best to add it as select entity.

https://github.com/home-assistant/core/blob/dev/homeassistant/components/zha/select.py

Then there is also the "heat" and "cool" and then "pause", "manual" and "auto". Those should probably be added to the climate entity. I suspect that it is not so easy, but I also could be wrong.

I have added you as collaborator on my branch for which I have already created a PR. None of the maintainers has paid attention to it yet though. I think no one has time atm unfortunately

docloy commented 5 months ago

@markoberholzer-es I did try to install your quirk.

  1. At first I enabled zha custom quirks and die save your quirk in this folder.
  2. restart ha
  3. removed Bosch Thermostat II 230V
  4. added it by qr code.

But there is still no entity to switch to cooling mode. Hopefully you have a hint, why it is not working. Thanks in advance!

jclsn commented 5 months ago

Yes, because you need cluster handlers for this, which need to be implemented in the HA core. I have already started doing that, but it is not easy and the ZHA devs are very busy atm.

Btw, @markoberholzer-es did nothing else than set the CtrlSequenceOfOper attribute to HeatingAndCooling in his quirk. This is not something that is going to be supported any time soon.

markoberholzer-es commented 4 months ago

@markoberholzer-es I did try to install your quirk.

1. At first I enabled zha custom quirks and die save your quirk in this folder.

2. restart ha

3. removed Bosch Thermostat II 230V

4. added it by qr code.

But there is still no entity to switch to cooling mode. Hopefully you have a hint, why it is not working. Thanks in advance!

Hi @docloy - when the quirk is correctly applied, your Bosch Termostat should show the following modes:

grafik

If that is not the case - are your zha quirks correctly loaded ? Did you apply the following lines to your configuration.yaml?

zha:
  enable_quirks: true
  custom_quirks_path: /config/custom_zha_quirks/
docloy commented 4 months ago

@jclsn and @markoberholzer-es thanks for your reply and your input. In my configuration.yaml I have those 3 lines. But I don't know how to acitvate use the quirk. But through the zigbee device settings --> Manage Zigbee Device --> Clusters: BoschThermostatCluster (Endpoint id: 1, Id: 0x0201, Type: in) I can set manually the attribute and the value for cooling:

Attributes of the selected cluster: ctrl_sequence_of_oper (id: 0x001b)
Value: 0x00

And for heating:

Attributes of the selected cluster: ctrl_sequence_of_oper (id: 0x001b)
Value: 0x02

At the moment I'm fine with this solution because I have only to switch twice a year. Maybe it'll be implemented in core. Anyway I have no idea how to use quirks (would have been interesting as well).