Modbus PLC YAML help

Ok, New issue. Apparently my PLC is sending hex values in it’s register. I to have to convert them into a decimal with an online calc. I have value 2329 in my plc register and home assistant sees it as 9001. The calc. confirmed that. Hmm. Is there a way to do the math?

The PLC is sending binary data. It is up to the receiver how to display it (and even how to interpret it – it could be a float for example).

You are reading value this on the PLC itself, right? I guess it just displays everything in hex.
I don’t know what the number you are reading is supposed to mean, so I’ll just assume you just want it displayed in hex.
You should be able to convert the state of a sensor to hex with this template: {{ "%0x" % (states('sensor.sensor_name') | int) }}. I guess you’ll have to use it in a template sensor.

Basically I am reading the timer value on T0 register from the Koyo directlogic 06 PLC . The number in the timer in the Directsoft software on the ladder timer block is 2329. When home assistant reads it under sensor, it determines the number is 9001. I would like to get the 2329 number as displayed on my controller timer register location. I am not exactly sure what is going on yet. I mostly work with Allen Bradley controllers and software so I am still figuring this out. I assume that the value is getting converted from hex to decimal. I thought by reading a input register from the Modbus would directly read what is in the register. Still trying to wrap my head around it to fully explain what is going on.

Exactly. There are 16 bits of binary data in the register. It’s up to you to interpret it (Is it a signed integer? Unsigned integer? Float?) and display it (the number 10 in decimal can also be displayed as 0xA hex, 012 octal and so on).

To get 2329, you’ll need to create a template sensor that reads the decimal value 9001 from your modbus sensor and converts it to hex:

template:
  - sensor:
    - name: "hex value"
      unit_of_measurement: ""
      state: '{{ "%0x" % (states("sensor.sensor_decimal") | int) }}'

Replace sensor_decimal with the name of your sensor.

Is this right? I am getting value 0 on hex value. I feel so inept with this YAML coding.

modbus: 
  - name: hub1
    type: tcp    
    host: 192.168.1.243    
    port: 502

    switches:
      - name: Switch33
        slave: 255
        address: 3074
        write_type: coil
        verify:
        
    binary_sensors:
      - name: "Pool_Pump"
        address: 3074
        scan_interval: 10
        slave: 255 
        device_class: moving
        input_type: coil
        
    sensors:
      - name: Timer1
        slave: 255
        address: 256       
        data_type: int # or float
        unit_of_measurement: "Time"
        
template:
  - sensor:
      - name: "hex value"
        unit_of_measurement: ""
        state: '{{ "%0x" % (states("Timer1") | int) }}'    

Nope, that should be state: '{{ "%0x" % (states("sensor.timer1") | int) }}'

I just put this in and nothing under Modbus works now. Hmm, sure I’m not missing something more? Thanks.

modbus: 
  - name: hub1
    type: tcp    
    host: 192.168.1.243    
    port: 502

    switches:
      - name: Switch33
        slave: 255
        address: 3074
        write_type: coil
        verify:
        
    binary_sensors:
      - name: "Pool_Pump"
        address: 3074
        scan_interval: 10
        slave: 255 
        device_class: moving
        input_type: coil
        
    sensors:
      - name: Timer1
        slave: 255
        address: 256       
        data_type: int # or float
        unit_of_measurement: ""
        
template:
  - sensor:
      - name: "hex value"
        unit_of_measurement: ""
        state: '{{ "%0x" % (states("sensor.Timer1") | int) }}'    

Check your logs. Maybe you already had a template: section somewhere in your configuration.yaml (or !included files).

Some errors, not sure what they mean. Pretty vague.

Pymodbus: Modbus Error: [Input/Output] [Errno 32] Broken pipe

6:14:03 PM – (ERROR) Modbus

Setup of sensor platform modbus is taking over 10 seconds.

6:14:03 PM – (WARNING) Sensor - message first occurred at 6:14:03 PM and shows up 2 times

Setup of switch platform modbus is taking over 10 seconds.

6:14:03 PM – (WARNING) Switch

Setup of binary_sensor platform modbus is taking over 10 seconds.

6:14:03 PM – (WARNING) Binary sensor

Error doing job: Unclosed client session

6:13:49 PM – (ERROR) runner.py

No idea, sorry. Does not seem to be related to the template sensor you added. Try restarting Home Assistant.

Any idea why half the time on a restart of HA, entities for the Modbus are unavailable? I then restart and they will be working. Very odd.

Maybe you have to wait for the TCP connection to time out or something. Instead of a restart, try stopping HA, wait for 15 seconds or so and start it again.

Thank you for you suggestion.
Getting back to the template issue. I did find this error in the log that I missed before. Any idea?

Template variable error: 'sensor' is undefined when rendering '{{ "%0x" % (states(sensor.pool_temp) | int) }}'

TemplateError('UndefinedError: 'sensor' is undefined') while processing template 'Template("{{ "%0x" % (states(sensor.pool_temp) | int) }}")' for attribute '_attr_state' in entity 'sensor.hex_value'

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 389, in async_render
    render_result = _render_with_context(self.template, compiled, **kwargs)
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 1358, in _render_with_context
    return template.render(**kwargs)
  File "/usr/local/lib/python3.9/site-packages/jinja2/environment.py", line 1304, in render
    self.environment.handle_exception()
  File "/usr/local/lib/python3.9/site-packages/jinja2/environment.py", line 925, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "<template>", line 1, in top-level template code
  File "/usr/local/lib/python3.9/site-packages/jinja2/sandbox.py", line 326, in getattr
    value = getattr(obj, attribute)
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 1382, in _fail_with_undefined_error
    raise ex
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 1374, in _fail_with_undefined_error
    return super()._fail_with_undefined_error(*args, **kwargs)
jinja2.exceptions.UndefinedError: 'sensor' is undefined

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 505, in async_render_to_info
    render_info._result = self.async_render(variables, strict=strict, **kwargs)
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 391, in async_render
    raise TemplateError(err) from err
homeassistant.exceptions.TemplateError: UndefinedError: 'sensor' is undefined



`modbus: 
  - name: hub1
    type: tcp
    host: 192.168.1.243    
    port: 502

`    sensors:
      - name: Pool Temp
        address: 1024
        scan_interval: 10
        slave: 255       
        data_type: int # int or float
        unit_of_measurement: "°F"
        
template:
  - sensor:
      - name: "hex value"
        unit_of_measurement: "°F"
        state: '{{ "%0x" % (states(sensor.pool_temp) | int) }}'

sensor.pool_temp inside states() needs to be inside quotes to be a string (otherwise, the template is looking for a variable named sensor, which does not exist).

Like this?

state: '{{ "%0x" % (states("sensor.pool_temp") | int) }}'

Yes, that should work.

You rock…
That did it.
I now need to add a decimal to the value of the temp sensor. It is supposed to read 74.3

hex

Maybe something like this:

state: '{{ ("%0x" % (states("sensor.pool_temp") | int)) | int / 10 }}'

boom

Boomshakalaka… That was it…HAHA

If you lived close Id take you out for a few beers. Thanks so much.

How do you know this coding? Is there a site online to learn this or to understand these formulas?

FWIW, you can specify the number base in the int function.

state: "{{ ('0x' ~ states('sensor.pool_temp')) | int(base=16) / 10 }}"