rubenbe / comfospottwin40

Control your Zehnder ComfoSpot Twin 40
MIT License
8 stars 0 forks source link

More info on installation please #2

Open Phi2k opened 9 months ago

Phi2k commented 9 months ago

Hi this looks really cool and I will try to implement this for x-well d12 Can you give some more details (I have only about a year experience with IOBroker etc.) on: 1) why is there the dependency on home assistant? I assume an mqtt broker in IOBroker would also work? 2) is this running on a Linux-based raspberry pi? This is my plan but I am afraid of driver issues for the required hardware… Thank you very much!

Phi2k commented 8 months ago

Ok I took the next step. Software runs on raspberry pi zero. Communication with IOBroker works fine. Changes I make in IOBroker have direct effect on the values printed by the server in the terminal. However by now I was not successful with actually controlling the fans. All commands have no effect. Sensor data is also not displayed. I will post more info while I continue with troubleshooting. It would be helpful to have the mqtt settings of a running setup. Expected data type is often not obvious for me. Maybe I just have wrong parameters

rubenbe commented 8 months ago

Hi!

Sorry for the late response. There is indeed no hard dependency on home assistant, it implements the hass autodiscovery protocol. I'll update the instructions, since any mqtt broker should work. (I'm using mosquito). With regard to controlling I've seen that the thing is very picky on which signal it receives. I've tried multiple, and the only one that I've found that works is the https://www.waveshare.com/usb-to-rs232-485-ttl.htm?sku=15817 The fact that you're not seeing sensor data is expected, since the fans seem to answer with their sensor data when the new fan speed is sent. (The original controller sends the expected fan speed continuously, so do I)

Phi2k commented 8 months ago

Thanks for the reply and the support. I bought exactly this adapter despite the highest price (the one with the FT232RL chip - correct?). I have no success. fans are completely dead. Perhaps somebody can help me here.It feels like I am stuck at 99% of the project. The X-well d12 is my last project in order to connect the whole house to IOBroker.

My troubleshooting so far:

I set the jumper and the switch as described to ND and to 5V. I tried with GND connected and without. I tried running this from my Mac as well as from the Raspberry. PWR LED is on. Green TXD LED is blinking as soon as I start the server. I tried connecting the Waveshare adapter to different locations on the bus in order to avoid issues with signal strength.

I have the following setup: Zone 1: 2 Fans installed Zone 2: 1 Fan Zone 3: 1 Fan

In order to check whether this setup causes issues I only switched on one fan: ❶: 🔀🏠➡️ ⏸️ 0s (100 ma)🌡️ __C, % ♻️ __C, %; ❷: 🔀🏠⏸️ ⏸️ 0s (100 ma)🌡️ __C, % ♻️ __C, %; ❸: 🔀🏠⏸️ ⏸️ 0s (100 ma)🌡️ __C, % ♻️ __C, %

state as json:

{ "v1": { "1": { "fan": { "on": true, "speed": 100, "forward": true, "oscillation": true }, "counterfan": { "state": "Off" } }, "2": { "fan": { "on": false, "speed": 100, "forward": false, "oscillation": true }, "counterfan": { "state": "Off" } }, "3": { "fan": { "on": false, "speed": 100, "forward": false, "oscillation": true }, "counterfan": { "state": "Off" } } } }

I also tried to sniff the bus by leaving the original controller connected. Every few seconds I get the following message:

WARNING:root:Unknown packet ['0x55', '0x0', '0x55', '0x59', '0x69', '0xea', '0x0', '0x55', '0x59', '0xd1', '0xf2', '0xfb', '0xff', '0xfd', '0xfb', '0xff', '0xff', '0x9f', '0xfd', '0x0', '0x55', '0x59', '0xd1', '0xf2', '0xf7', '0xfd', '0xff', '0xd7', '0xaf', '0x25', '0xff', '0xfe', '0x40', '0x55', '0xd6', '0x6b', '0xed', '0xef', '0xfb', '0x1f', '0xc7', '0xfb', '0xfd', '0xc3', '0xd3', '0xd3', '0x85', '0x0', '0x55', '0x59', '0xd3', '0xf2', '0xfd', '0xfb', '0xff', '0xd1', '0xff', '0x0', '0x55', '0x59', '0xb8', '0xba', '0xba', '0x1', '0xc0', '0xff', '0x0', '0x55', '0x59', '0xba', '0xba', '0xc0', '0x0', '0x0', '0x55', '0x59', '0x6b', '0xfe', '0xba', '0x2', '0x0', '0x55', '0x59', '0xd1', '0xf2', '0xff', '0xfd', '0xff', '0xcf', '0xaf', '0x25', '0xf5', '0xcf', '0xf5', '0xff', '0xfd', '0x0', '0x55', '0x59', '0x69', '0xea', '0xef', '0xf9', '0xfd', '0xc1', '0x0', '0x55', '0x59', '0xd3', '0xf2', '0xfb']

I wonder if this is a hint that the X-well has a tiny different protocol? The only thing left I can try would be to change the setting of the internal jumper of the waveshare.

Any more ideas? 1) does it help to disconnect fans in order to simplify the protocol? Or did you figure out that the system is robust also in case you send commands to fans that are not installed? 2) did you check voltage levels on the bus? your description that only one Waveshare adapter was working might be due to weak signal? Unfortunately I have no oscilloscope or logic analyzer. I have rather long distances on the bus. Therefore I checked different positions to make sure that at least one fan is close to the controller. 3) I noticed that If you only connect the two power cables to the original controller but not the bus the fans are already starting. What did you do with the power cables? just leaving them unconnected? Or did you connect the power cables to the original controller 4) I did not try swapping the BUS lines. might there be some differences in nomenclature for the master and the slave?

Phi2k commented 8 months ago

Update: I swapped A and B on the Bus and it is partly working (with errors). The server is crashing after a few iterations. changing the settings via mqtt and restarting will change the settings of the system.

python3 server.py --mqtt '192.168.178.3' --dev /dev/ttyUSB0
Subscribe (('comfospot40_zone1_fan/direction/set', <function Fanspeed.do_subscribes.<locals>.<lambda> at 0xb5e6ebf8>), ('comfospot40_zone1_fan/oscillation/set', <function Fanspeed.do_subscribes.<locals>.<lambda> at 0xb5e6ec40>), ('comfospot40_zone1_fan/on/set', <function Fanspeed.do_subscribes.<locals>.<lambda> at 0xb5e6ec88>), ('comfospot40_zone1_fan/preset/set', <function Fanspeed.do_subscribes.<locals>.<lambda> at 0xb5e6ecd0>), ('comfospot40_zone1_fan/speed/percentage', <function Fanspeed.do_subscribes.<locals>.<lambda> at 0xb5e6ed18>))
Subscribe comfospot40_zone1_fan/direction/set
Subscribe comfospot40_zone1_fan/oscillation/set
Subscribe comfospot40_zone1_fan/on/set
Subscribe comfospot40_zone1_fan/preset/set
Subscribe comfospot40_zone1_fan/speed/percentage
Subscribe (('comfospot40_zone1_counter/set', <function Counterfan.do_subscribes.<locals>.<lambda> at 0xb5e6ee38>),)
Subscribe comfospot40_zone1_counter/set
Subscribe (('comfospot40_zone2_fan/direction/set', <function Fanspeed.do_subscribes.<locals>.<lambda> at 0xb5e6e970>), ('comfospot40_zone2_fan/oscillation/set', <function Fanspeed.do_subscribes.<locals>.<lambda> at 0xb5e6eda8>), ('comfospot40_zone2_fan/on/set', <function Fanspeed.do_subscribes.<locals>.<lambda> at 0xb5e6ed60>), ('comfospot40_zone2_fan/preset/set', <function Fanspeed.do_subscribes.<locals>.<lambda> at 0xb5e6efa0>), ('comfospot40_zone2_fan/speed/percentage', <function Fanspeed.do_subscribes.<locals>.<lambda> at 0xb5e87028>))
Subscribe comfospot40_zone2_fan/direction/set
Subscribe comfospot40_zone2_fan/oscillation/set
Subscribe comfospot40_zone2_fan/on/set
Subscribe comfospot40_zone2_fan/preset/set
Subscribe comfospot40_zone2_fan/speed/percentage
Subscribe (('comfospot40_zone2_counter/set', <function Counterfan.do_subscribes.<locals>.<lambda> at 0xb5e87070>),)
Subscribe comfospot40_zone2_counter/set
Subscribe (('comfospot40_zone3_fan/direction/set', <function Fanspeed.do_subscribes.<locals>.<lambda> at 0xb5e870b8>), ('comfospot40_zone3_fan/oscillation/set', <function Fanspeed.do_subscribes.<locals>.<lambda> at 0xb5e87100>), ('comfospot40_zone3_fan/on/set', <function Fanspeed.do_subscribes.<locals>.<lambda> at 0xb5e87148>), ('comfospot40_zone3_fan/preset/set', <function Fanspeed.do_subscribes.<locals>.<lambda> at 0xb5e87190>), ('comfospot40_zone3_fan/speed/percentage', <function Fanspeed.do_subscribes.<locals>.<lambda> at 0xb5e871d8>))
Subscribe comfospot40_zone3_fan/direction/set
Subscribe comfospot40_zone3_fan/oscillation/set
Subscribe comfospot40_zone3_fan/on/set
Subscribe comfospot40_zone3_fan/preset/set
Subscribe comfospot40_zone3_fan/speed/percentage
Subscribe (('comfospot40_zone3_counter/set', <function Counterfan.do_subscribes.<locals>.<lambda> at 0xb5e87340>),)
Subscribe comfospot40_zone3_counter/set
❶: 🔀🏠➡️ ⏸️   0s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❷: 🔀🏠⏸️ ⏸️   0s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❸: 🔀🏠⏸️ ⏸️   0s (100 ma)🌡️ ____C, __% ♻️  ____C, __%
❶: 🔀🏠➡️ ⏸️   1s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❷: 🔀🏠⏸️ ⏸️   1s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❸: 🔀🏠⏸️ ⏸️   1s (100 ma)🌡️ ____C, __% ♻️  ____C, __%
❶: 🔀🏠➡️ ⏸️   3s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❷: 🔀🏠⏸️ ⏸️   2s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❸: 🔀🏠⏸️ ⏸️   2s (100 ma)🌡️ ____C, __% ♻️  ____C, __%
WARNING:root:Unknown packet ['0x55', '0x53', '0xf8', '0x55', '0x53', '0x0', '0x98', '0x5', '0x4', '0x1', '0x41', '0x0', '0xd0', '0xfa', '0x55', '0x53', '0x0', '0x98', '0x5', '0x0', '0xff', '0x55', '0x53', '0x0', '0x98', '0x5', '0x4', '0x1', '0x41', '0x0', '0xd0', '0xfa', '0x55', '0x53', '0x0', '0x98', '0x5', '0x55', '0x53', '0x0', '0x98', '0x5', '0x4', '0x1', '0x41', '0x0', '0xd0', '0xfa', '0x55', '0x53', '0x0', '0x98', '0x5', '0x0', '0xfe', '0x55', '0x53', '0x0', '0x98', '0x5', '0x4', '0x1', '0x41', '0x0', '0xd0', '0xfa', '0x55', '0x53', '0x0', '0x98', '0x5', '0xff', '0x55', '0x53', '0x0', '0x98', '0x5', '0x4', '0x1', '0x41', '0x0', '0xd0', '0xfa', '0x55', '0x53', '0x0', '0x98', '0x5', '0xe0']
❶: 🔀🏠➡️ ⏸️   4s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❷: 🔀🏠⏸️ ⏸️   3s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❸: 🔀🏠⏸️ ⏸️   3s (100 ma)🌡️ 20.8C, 65% ♻️  ____C, __%
❶: 🔀🏠➡️ ⏸️   5s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❷: 🔀🏠⏸️ ⏸️   5s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❸: 🔀🏠⏸️ ⏸️   4s (100 ma)🌡️ 20.8C, 65% ♻️  ____C, __%
❶: 🔀🏠➡️ ⏸️   6s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❷: 🔀🏠⏸️ ⏸️   6s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❸: 🔀🏠⏸️ ⏸️   6s (100 ma)🌡️ 20.8C, 65% ♻️  ____C, __%
WARNING:root:Unknown packet ['0x55', '0x53', '0x0', '0xf8', '0x55', '0x53', '0x0', '0x98', '0x5', '0x4', '0x1', '0x41', '0x0', '0xd1', '0xf9', '0x55', '0x53', '0xfc', '0x55', '0x53', '0x0', '0x98', '0x5', '0x4', '0x1', '0x41', '0x0', '0xd1', '0xf9', '0x55', '0x53', '0x0', '0x98', '0x5', '0x0', '0x55', '0x53', '0x0', '0x98', '0x5', '0x4', '0x1', '0x41', '0x0', '0xd1', '0xf9', '0x55', '0x53', '0x0', '0x98', '0x5', '0x0', '0xf2', '0x55', '0x53', '0x0', '0x98', '0x5', '0x4', '0x1', '0x41', '0x0', '0xd1', '0xf9', '0x55', '0x53', '0x0', '0x98', '0x5', '0x0', '0x2', '0x49', '0x0', '0x7c', '0x49', '0x55', '0x53', '0x0', '0x98', '0x5', '0x4', '0x1', '0x41', '0x0', '0xd1', '0xf9', '0x55', '0x53', '0x0', '0x98', '0x5']
❶: 🔀🏠➡️ ⏸️   8s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❷: 🔀🏠⏸️ ⏸️   7s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❸: 🔀🏠⏸️ ⏸️   7s (100 ma)🌡️ 20.9C, 65% ♻️  ____C, __%
❶: 🔀🏠➡️ ⏸️   9s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❷: 🔀🏠⏸️ ⏸️   8s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❸: 🔀🏠⏸️ ⏸️   8s (100 ma)🌡️ 20.9C, 65% ♻️  ____C, __%
❶: 🔀🏠➡️ ⏸️  10s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❷: 🔀🏠⏸️ ⏸️  10s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❸: 🔀🏠⏸️ ⏸️  10s (100 ma)🌡️ 20.9C, 65% ♻️  ____C, __%
❶: 🔀🏠➡️ ⏸️  11s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❷: 🔀🏠⏸️ ⏸️  11s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❸: 🔀🏠⏸️ ⏸️  11s (100 ma)🌡️ 20.9C, 65% ♻️  ____C, __%
❶: 🔀🏠➡️ ⏸️  13s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❷: 🔀🏠⏸️ ⏸️  12s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❸: 🔀🏠⏸️ ⏸️  12s (100 ma)🌡️ 20.9C, 65% ♻️  ____C, __%
❶: 🔀🏠➡️ ⏸️  14s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❷: 🔀🏠⏸️ ⏸️  14s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❸: 🔀🏠⏸️ ⏸️  13s (100 ma)🌡️ 20.9C, 65% ♻️  ____C, __%
❶: 🔀🏠➡️ ⏸️  15s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❷: 🔀🏠⏸️ ⏸️  15s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❸: 🔀🏠⏸️ ⏸️  15s (100 ma)🌡️ 20.9C, 65% ♻️  ____C, __%
❶: 🔀🏠➡️ ⏸️  16s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❷: 🔀🏠⏸️ ⏸️  16s (27 lo)🌡️ ____C, __% ♻️  ____C, __%; ❸: 🔀🏠⏸️ ⏸️  16s (100 ma)🌡️ 20.9C, 65% ♻️  ____C, __%
ERROR:asyncio:Task exception was never retrieved
future: <Task finished name='Task-22' coro=<Mqtt.listen() done, defined at /home/marphi/comfospottwin40/comfospot40/mqtt.py:28> exception=MqttError('Disconnected during message iteration')>
Traceback (most recent call last):
  File "/home/marphi/comfospottwin40/comfospot40/mqtt.py", line 30, in listen
    async for message in messages:
  File "/home/marphi/.local/lib/python3.9/site-packages/aiomqtt/client.py", line 684, in _generator
    raise MqttError(msg)
aiomqtt.error.MqttError: Disconnected during message iteration
Traceback (most recent call last):
  File "/home/marphi/comfospottwin40/server.py", line 81, in <module>
    asyncio.run(
  File "/usr/lib/python3.9/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "/home/marphi/comfospottwin40/server.py", line 34, in main
    await hal.sendState(state, new_print)
  File "/home/marphi/comfospottwin40/comfospot40/hal.py", line 29, in sendState
    for zoneid, zonestate in state.zones.items():
RuntimeError: dictionary changed size during iteration

Any Ideas? Not all zones have a sensor installed. Only Zone 1 and 3. The sensor data of Zone 1 is sometimes parsed incorrectly but not always. Would you try disconnecting the sensors? Did you ever test without sensors installed? Did you ever test with a setup where some zones do not have pairs of fans? lease provide the JSON file of your setup. I will adopt mine for testing. (e.g. by disconnecting Fans and changing zones setup)

rubenbe commented 8 months ago

That crash is weird, I'll try to have a look. Since you seem to have bigger setup than I do (I only have two fans in one zone here). IIRC I have tested without sensors too, also ran the setup quite long with only one fan. The failed packets seem to be due to incorrectly parsed packets. The data packets are usually not that long. (see reverser.py for some examples) I'd try with one zone first (since I have only one here)

does it help to disconnect fans in order to simplify the protocol? Or did you figure out that the system is robust also in case you send commands to fans that are not installed?

The protocol is fairly simple, the number of fans on the bus does not matter, the number of sensors might give problem though.

did you check voltage levels on the bus? your description that only one Waveshare adapter was working might be due to weak signal? Unfortunately I have no oscilloscope or logic analyzer. I have rather long distances on the bus. Therefore I checked different positions to make sure that at least one fan is close to the controller.

Yes I did, the reason for the waveshare is because it seems to be the only adapter that sends the correct signal form. (IIRC it actually properly drives the RS485, while most cheap adapters don't)

I noticed that If you only connect the two power cables to the original controller but not the bus the fans are already starting. What did you do with the power cables? just leaving them unconnected? Or did you connect the power cables to the original controller

I have my power from the original power supply. My fans remained still when powering up. They only start spinning when the first packet is received. Then they actually keep spinning forever even after stopping the software, so the repetitive sending of the requested fan level is mostly to get the sensor data back.

I tried connecting the Waveshare adapter to different locations on the bus in order to avoid issues with signal strength.

In my setup the waveshare is at the end of the bus, with both fans about 15meter? away. I use for wires of a CAT5 cable for both the power and the data (maybe that helps with the signal integrity).

is this running on a Linux-based raspberry pi? This is my plan but I am afraid of driver issues for the required hardware…

I run this on a Linux PC, so you don't need a raspberry pi.

FYI my setup is 1 zone, 2 fans, 1 sensor.

Phi2k commented 8 months ago

Thanks for the help! As soon as I removed the second sensor the whole setup of Zone 1 pair Zone2 single Zone 3 single + sensor seems to be working.

If you or somebody else is interested to fix this let me know how I can support this with more detailed logging or sniffing of the packets. I feel not comfortable editing the parser myself (yet). Otherwise I will just install a separate smart sensor like shelly HT etc.

rubenbe commented 8 months ago

That's very interesting info (since switching to one sensor helps, that might be an indication). Thanks. When I have time I'll have a look to find the bug.

Phi2k commented 8 months ago

Update: Setup with only one sensor is now running since one week without any issues. Very cool :-)