Modbus home assistant and python struct (little endian, big endian, negative values from uint16)

449 Views Asked by At

I have a question regarding to modbus settings. I have read the documentation carefully, tried to search some topics, but unfortunately I did not find an answer to my problem.

I have a heat pump, which is able to communicate through modbus. In the past without HA I had my own application on ESP8266, reading the data, uploading them, etc. Now I would like to move it into HA. I found the modbus protocol is implemented in HA, which is great.

Now, in my custom app I had to read the registry and modify the respond for each value as the device has MSB implementation, let me provide an example:

From the device documentation, the only things I know (and it seems to be enough as I was able to implement the app) are: The heat pump communicates on ..... IP address, on .... port. It uses slave and the slave ID is .... All values are represented in MSB (most significant byte). Now about the values, for example outside temperature is on address 0, type is read only and the scale is 100 (for modbus in configuration file it should be 0.01 - lets ignore it for now), unit is °C.

So, my configuration look like:

# Modbus configuration
modbus:
  - name: ...
    type: tcp
    host: ...
    port: ...
    delay: 5
    timeout: 5
    sensors:
      - name: Heat pump outside temperature
        address: 0
        slave: 1
        input_type: holding
        device_class: temperature
        state_class: measurement
        data_type: uint16
        unique_id: "ac_heating_outside_temp"

This results to value of 65436 on this entity, which is wrong obviously. The real value at this moment is -1. The biggest value for uint16 is 65535, 65436-65535 = -99, multiplied by 0.01 (or divided by 100) is -0.99, which is (if we deduct zero) -1.00 degree... This is the value which I need. Well, in my C app, I have been doing this recalculation on my own (in bytes). Unfortunately I have no idea how to do that in "our" modbus yaml description.

I have been looking to SWAP, DATA_TYPE as well as STRUCTURE in the documentation: DOCUMENTATION (documentation link) unfortunately nothing is working for me. I know I have to set custom data_type if I would like to provide structure, but defining the custom type and ">I" in the structure requires 2 registries to read, but the address of the entity is 0, which is 1 registry. Even like that I tried that, but I am not able to get the proper value. Having the data_type to uint16 with the swap byte or even swap word does not seems to work. I tried to play (out of necessity) with uint8, 2 registries and swap together, but no combination leads to the proper result. Python struct documentation: https://docs.python.org/3.8/library/struct.html

Can anybody help me with this one?

2

There are 2 best solutions below

0
On

You can consider Modbus-to-MQTT bridge pattern, using some professional Modbus tool to poll device data and publish to MQTT, and then home assistant can easily integrate such data via MQTT integration.

There are at least 3 advantages by following the above solution,

  • A Modbus tool (e.g. modpoll) gives you much more options (Big/Little Word/Byte Endian, various data types) to handle some non-standard implementations from various vendors
  • MQTT broker decouples Modbus workload from HA, which is good for modular design principle
  • MQTT broker makes debugging/troubleshooting much easier, you can subscribe to specific topic anytime without HA downtime.
0
On

I've created mqmgateway especially for this purpose. It can convert data readed from mobus registers and present it for HomeAssistant as string values or json payload.

There are int16, uint16 convertes with MSB/LSB configuration. If this is not enough, you can add your own converter or use exprtk plugin to do more advanced math.