IO-Link Sensors convert from hex to decimal

Hello, I have an IO-Link pressure transmitter from Wika which I read out via an IFM IO-Link master using Rest. The value comes in hexadecimal format e.g. 0B64, I first have to convert this value into a binary number
this results in 0000101101100100 binary,

As 14 bits remain for the pressure measurement, the last two zeros would be omitted from the binary value 0000101101100100. If I convert this value into decimal I get the value 729, this value is my pressure value (this value would then have to be shifted 2 places to the left with the decimal point)

What is the best way to create a template sensor?
this is my Rest sensor:

- sensor:
      - name: iolinknew
        value_template: "{{ states('sensor.iolink') | int(base=16) | bin }}"
        unit_of_measurement: "Binary"  

Does not work.HA indicates in the logs

Invalid config for ‘template’ at configuration.yaml, line 285: required key ‘state’ not provided Invalid config for ‘template’ at configuration.yaml, line 286: ‘value_template’ is an invalid option for ‘template’, check: sensor->0->value_template

this is my rest sensor

  - platform: rest
    name: iolink
    resource: http://192.168.1.124/00-02-01-71-85 47/iolinkmaster/port[1]/iolinkdevice/pdin/getdata
    value_template: "{{ value_json.data.value }}"
    scan_interval: 10 

i look after a good soloution to get the data ,thanks alot

Replace value_template with state.

  - sensor:
      - name: iolinknew
        state: "{{ states('sensor.iolink') | int(base=16) | bin }}"

There are two configuration methods for creating Template entities: modern and legacy. Your configuration is mostly modern format except for value_template which is legacy format. You can’t mix the two formats.

I also suggest you initially remove the unit_of_measurement option. After you have confirmed the configuration works (i.e. no error message and the sensor is created), add the option to the sensor’s configuration and confirm it still works.

1 Like

Also once you get the template working as you want you can just use it in the rest sensor value_template. There’s no need for a separate template sensor, unless you need the hexadecimal value as well.

1 Like

Thanks for your help, I have just tested again, I got a value from the rest sensor 068C was the value, the iolinknew sensor gives me 1676 back what says if I divide this value by 4 then I come to the pressure value 419 this would then have to shift the decimal places by 2 to the left, then I would have the value!

If I can get the value 419 directly from the rest sensor then that would be very good.I love keep it simple :slight_smile:
Unfortunately I’m a zero at coding so I’ll be honest…thank you very much

Use this in the REST sensor and then you don’t need the Template Sensor.

    value_template: "{{ (value_json.data.value | int(base=16)) / 400 }}"

Calculation tested in the Template Editor:

Thank you all Guys! This works perfect

1 Like

Hello again, I had the unique opportunity to get a high-quality volume flow meter from Endress+Hauser (Picomag) at a reasonable price. It is already integrated in Iolink, so I need help once again, so my well project is finished.
The flow meter outputs a 32-bit floating point number via IEEE754 (single precision). As with the pressure sensor above, I obtain the data via the second Iolink port via Rest, I then have the following data format I have taken it apart for better readability 3F000000459018664120000000C801

3F000000= conductivity of the water 45901866 = Totalizer 412000000 = Volumeflow 00C8 = process temperature 01= Device status

the values are in this order, conductivity and temperature and status I do not necessarily need, only totalizer and volume flow.
how can i best convert the required bytes as i want to omit parts in this example?
thank you very much!

{% from 'ieee754.jinja' import ieee754_float %}
{% set x = "3F000000459018664120000000C801" %}
Conductivity:  {{ x[0:8] }} = {{ ieee754_float(x[0:8]) }}
Totalizer:     {{ x[8:16] }} = {{ ieee754_float(x[8:16]) }}
Volume flow:   {{ x[16:24] }} = {{ ieee754_float(x[16:24]) }}
Process temp:  {{ x[24:28] }}     = {{ x[24:28]|int(base=16)/10 }}
Device status: {{ x[28:30] }}       = {{ x[28:30]|int(base=16) }}

1 Like

thanks @troon , I have installed the jinja extension and now it shows me the way you have it. how can I now process the values as individual entities, sorry for the question how do I now get the connection to the template that I get current values?

If you have the full hex string that I called x as sensor.x, then set up a template sensor for each.

State template for totalizer (replace sensor.x with your actual entity ID):

{% from 'ieee754.jinja' import ieee754_float %}
{{ ieee754_float(states('sensor.x')[8:16]) }}

with unit of measurement set to L and device class to volume.

and for volume flow:

{% from 'ieee754.jinja' import ieee754_float %}
{{ ieee754_float(states('sensor.x')[16:24]) }}

with unit of measurement set to L/s. There is a volume_flow_rate device class, but the docs don’t list L/s as an allowable unit. You could do this (converting the string macro output to a number with float before multiplying by 60):

{% from 'ieee754.jinja' import ieee754_float %}
{{ ieee754_float(states('sensor.x')[16:24])|float(0)*60 }}

and set the unit to L/min and device class to volume_flow_rate.

I have also done this step, unfortunately there seems to be no data coming in, I have a simulation running via the iolink program so that I can change “dry” values. but the REST sensor is updated every 10 seconds in HA from this side no problem. with the volume flow I also got this error (I took the customized template) or should I rather create them individually as yaml?


OK, so your existing sensor has a string representing a data structure as its state, with the long hex value as one of the elements of that structure.

So first create a template sensor called “iolink value” or something like that, with state template:

{{ (states('sensor.iolink_2')|from_json)['data']['value'] }}

No unit or device class. That should have a state of 3F000... — then use that sensor in the templates above in place of sensor.iolink_2.

Alternatively, you could do it in one step:

{% from 'ieee754.jinja' import ieee754_float %}
{{ ieee754_float((states('sensor.iolink_2')|from_json)['data']['value'][8:16]) }}

I have revised the initial rest sensor so that only the HEX numbers arrive, the totalizer value now comes in converted:) unfortunately the volume flow is still unknown

  - platform: rest
    name: iolink
    resource: http://192.168.1.124/00-02-01-71-85-47/iolinkmaster/port[2]/iolinkdevice/pdin/getdata
    unique_id: endress_iolink_picomag
    scan_interval: 10
    value_template: "{{ value_json.data.value }}" 

OMG, it works:) Thank you alot @Troon

1 Like

My stupid mistake. Macros always return strings and need converting before doing arithmetic on them.

For litres per minute you need:

{% from 'ieee754.jinja' import ieee754_float %}
{{ ieee754_float(states('sensor.iolink_2')[16:24])|float(0)*60 }}

Fixed in my post above also.

That’s what the NoneNoneNone... in your screenshot was all about: your prior sensor wasn’t an IEEE754 string so my macro was returning None, then the template was “multiplying” that None sixty times… :face_with_raised_eyebrow:

1 Like