Thanks.
I started mine less than a year ago - so still suffering from teething problems - even this week, I am still learning new things about the packets / the protocol - but I think I got it sorted now. It just took ages to work a lot of things out - like when the first two bytes of a payload are for zone 0, or they just null bytes!
I would implement MQTT/Node-RED/etc. - I am just too short of time - I think it's going to take another year to get evohome_cc working for HA (and it exposes issues in evohome_rf).
It is designed as a library to be used by a (wrapping) client - it includes a very basic client.py as a CLI. It is completely async, and includes QoS (Throttling, Priority, Retries) when transmitting packets and I could easily enough set it up to expose itself as a transport, then you can do anything by writing a wrapper as a protocol and have the benefits of callbacks.
I am keen to help people do this.
If you'd like to collaborate, then I'd be could implement the transport sooner rather than later. Then you just have to have code like below.
You could replace all your packet/payload processing with:
Code:
def self._mgtt_callback(msg.payload):
...
where msg.payload is a simple dict.
This is the full protocol. You send command to send_data, and receive messages at mqtt_callback.
Code:
class EvohomeProtocol(asyncio.Protocol):
def __init__(self, mqtt_callback) -> None:
self._transport = None
self._pause_writing = None
self._mqtt_callback = mqtt_callback
def connection_made(self, transport: SerialTransport) -> None:
"""Called when a connection is made."""
self._transport = transport
def data_received(self, msg):
"""Called when some data is received."""
self._mqtt_callback(msg.payload)
async def send_data(self, command) -> None:
"""Called when some data is to be sent (not a callaback)."""
while self._pause_writing:
asyncio.sleep(0.1)
await self._transport.write(command)
def connection_lost(self, exc: Optional[Exception]) -> None:
"""Called when the connection is lost or closed."""
if exc is not None:
pass
self._transport.loop.stop()
def pause_writing(self) -> None:
"""Called when the transport's buffer goes over the high-water mark."""
self._pause_writing = True
def resume_writing(self) -> None:
"""Called when the transport's buffer drains below the low-water mark."""
self._pause_writing = False