Starting with a new solar system last year, I wanted to have access to ‘real time’ performance data, and to ultimately be able to implement some degree of inverter automation and control. My Solis Hybrid inverter does have a very nice UI screen, and a data logging stick (when it works) does provide a rich source of current and historic performance data. However, there appears to be almost zero availability for end-user access and remote control for either the inverter or the battery.
As part of a very long and time-consuming project, I have spent many hours slogging through Google searches for information to help me. To provide something by way of a ‘thank you’ to the many who publicly document their efforts, here is my update on a project to ‘read the CAN bus’ into HA from a pylontech battery.
Warning:
Lithium batteries are potentially dangerous. Pylontech batteries have a Battery Management System (BMS) that provides information, control, but most importantly protection. Changing settings on the BMS could potentially result in disruption, permanent damage, battery fires, or worse. Reading the CAN bus is a passive listening approach – it does not write anything to either battery or inverter – however without the cable between battery and inverter, my inverter stops seeing the reported SOC, assumes that the battery is ‘flat’, and immediately starts full charge from grid. After a while, the battery would fill up, and as the BMS cannot communicate to the inverter and tell it to ‘stop’, the BMS would open the MOS gate charge switches and effectively blow a fuse to cut off the unwanted charge current. Net result – a (permanently) dead battery. Hence there is an element of risk, so don’t try this at home.
Background:
CAN bus is an often used means by which batteries talk to inverters. Mostly one-way, it allows the battery to ‘tell’ the inverter what to do. Information passed will include SOC%, current and voltage limits, and alarm information. CAN bus is a high-speed, small-packet comms protocol using two wires connected to anything that wants to communicate. Everything listens all the time, and talks when it wants to.
Hardware:
I went for the simple option and purchased an industrial CAN-ethernet converter. Less than £65 in the UK, this has two CAN ports (I only need one) and also an RS485 port, connects by cable to ethernet, and provides TCP – CAN (and RS485) conversion. Needs a 5v power supply, but I ‘borrowed’ this from another serial-ethernet converter I already had. See picture – CAN unit is on the left.
Wiring:
Taking a two-port ethernet face plate, I wired pins 4/5 (the blue/blue-white) across both sockets and then out to the CAN port on the converter. Existing patch cable from battery (to inverter) plugged into one socket, and another cable from other socket to inverter completes the connection. Termination resisters are already in the battery & inverter ends, so are not required at the converter connection.
Setup:
LAN access is via cable to Wi-Fi extender/powerline/ direct cable as required. I have a small router acting as a switch, wired into a powerline adapter back to my router. The unit needs a fixed IP address, which is done by first finding the unit on the network (DHCP to start) and then using the web setup page. I did not need to change the standard settings, but did need to note the port address of the TCP server end.
Converter:
The converter I use can take inbound TCP messages and push them out to CAN bus, or can listen on the CAN bus and capture messages to TCP. As there is no formal protocol as such, all broadcast CAN bus messages are noted but will only be sent out to TCP based on either reaching a given packet length or time out, either of which will trigger buffer out to TCP. CAN bus messages have variable length, but a nice feature of the converter I have is that it puts all buffered messages into a fixed length packet for TCP, and this makes decoding them simpler!
From converter to Node-RED:
Using Node-RED, I have a simple ‘tcp in’ node, setup: connected to the converter port/host IP, and set to output a stream, of buffer payloads. Simple!
Code:
For reasons of safety and confidentiality, I am not sharing either my code or the details of the message protocol. Untested (ie my) code should never be simply copied and run, and I respect potential commercial sensitivity. There is (at the time of writing this) a copy of the protocol as well as at least one informative article by an enthusiast out there on the web, and I am sure anyone can search for pylontech can bus protocol if they so choose… Otherwise, most of the useful data can be decoded by inspection.
Message format:
The master battery sends out 6 different message packets. Each one ends up in TCP as 13 bytes long, but altogether – hence I mostly see buffers of 78 bytes arriving. The other buffers seen are 13 bytes (a heartbeat reply message from the inverter) or something between, which is just a part filled or chopped off buffer at the start, so I ignore those.
Parse buffer:
On the converter I use, each 13 byte buffer block (one ‘standard length’ CAN bus message) consists of a length field (1 byte), the CAN bus frame ID (2 bytes at offset 3) and a data packet of 8 bytes (offset 5). I only need the frame ID and the data packet. After that, each frame type is then decoded to extract the data fields.
ID 0x355 is the message that holds the SOH and SOC, as 2 byte hex, so 100% SOH will typically show as 0x6400 unsigned integer, little endian, and the other 2 byes will be the SOC. Note that only half the 8 byte CAN data buffer is used here, a side effect of the converter putting variable length CAN messages into fixed length TCP packets.
I use node-red-contrib-buffer-parser to parse the buffer, and so it only takes a few nodes to process the buffer into the fields I want. Then I use the HA entity node to create a sensor and pass the values to HA. The key field I use is just the battery SOC, which is available from the inverter, however I also lift the BMS reported voltage and current and calculate the power from this, which I find can differ from the inverter reported ‘battery power’ value by up to 150 watts.
Practicalities:
Messages on the CAN bus run at one BMS update every second, and even with a basic ‘reply’ from the inverter I have not seen any problem with capturing and processing all the message. However, I don’t need most information so I have added a flow limit node to reduce updates to every 30 or 60 seconds for just the fields I want.
Conclusion:
Although there is very little information about CAN bus battery-inverter communication, I found this project simple and easy to complete, mainly due to using the converter unit I purchased. Overall, not necessarily that useful a project to do, however I now get SOC directly from the battery, and realising the importance of the CAN bus link between battery and inverter, I may at some point consider installing a watchdog on HA. Should the CAN link stop (ie SOC goes to undefined or 0) there exists a contact port on the Pylontech that could be used to shut down the battery. Emergency stop in an emergency!