Commandline sensor - json - value in IEEE-754(?) to decimal?

I have a commandline sensor that give me values from my solar system, but the value is formated in a secial way. (maybe IEEE-754 ???)

command_line:
  - sensor:
      unique_id: senec002
      name: senec_mpp
      command: 'curl -d "{\"PV1\":{}}"  http://192.168.1.247/lala.cgi'
      scan_interval: 60
      value_template: "{{ value_json.PV1.MPP_POWER[1] }}"
      json_attributes:
        - result

That gives me this, for example:

fl_43F54001

could that be: IEEE-754 ?
How can I convert this in decimal?

From line 78 of this file, it looks like you need to do the following in Python (and yes, it is IEEE-754):

>>> import struct
>>> struct.unpack('!f',bytes.fromhex('fl_43F54001'[3:]))[0]
490.5000305175781

If that value seems reasonable, here’s the same in Jinja:

{% set s = "fl_43F54001" %}
{% set hl = s[3:]|regex_findall('..')|map('int', base=16)|list %}
{% set b = "%c%c%c%c" % (hl[0],hl[1],hl[2],hl[3]) %}
{{ b.encode('latin-1')|unpack('!f') }}

# which returns:
490.5000305175781

So:

command_line:
  - sensor:
      unique_id: senec002
      name: senec_mpp
      command: 'curl -d "{\"PV1\":{}}"  http://192.168.1.247/lala.cgi'
      scan_interval: 60
      value_template: >
        {% set s = value_json.PV1.MPP_POWER[1] %}
        {% set hl = s[3:]|regex_findall('..')|map('int', base=16)|list %}
        {% set b = "%c%c%c%c" % (hl[0],hl[1],hl[2],hl[3]) %}
        {{ b.encode('latin-1')|unpack('!f') }}
      json_attributes:
        - result

There’s probably a better way to get from hl to b. This method breaks if there are a different number of characters in the response.

Note that the latin-1 encoding is important. At first, I used the default utf-8 and ended up with a smaller answer than the Python solution. I’m not enough of an expert to understand this, but utf-8 encoding turned the 0xf5 (245) into 0xc3 (195), and gave an answer of 391 instead of 490.

EDIT:

Slightly more compact solution that allows for different-length hex strings:

        {% set s = value_json.PV1.MPP_POWER[1] %}
        {% set hl = s[3:]|regex_findall('..')|map('int',base=16)|list %}
        {{ ("{:c}"*hl|count).format(*hl).encode('latin-1')|unpack('!f') }}
1 Like

Thank you very much!!! That work for now and I will watch it.

I see from your other topic that there may be a few places you need to convert values like this.

Since 2023.4, you can create reusable templates as macros. So, create the /config/custom_templates folder, and add this code in the file fl_convert.jinja in that folder:

REMOVED: See GitHub link in later post for complete version

Reload by either restarting HA or calling the homeassistant.reload_custom_templates service (link to do this on your system).

Then your sensor can do this:

      value_template: >
        {% from 'fl_convert.jinja' import fl_convert %}
        {{ fl_convert(value_json.PV1.MPP_POWER[1]) }}

1 Like

Whow, that is an even nicer solution!
I just added |round(2) to the sensor to get less decimals.

1 Like

For completeness, having looked up how IEEE-754 works, here’s a version of the converter macro without all the encoding mess that will handle half, single, and double precision formats, prefix of fl_ or not, and spacing in the hex. Save it as custom_templates/ieee754.jinja.

REMOVED: see GitHub link below for latest complete version

Use thus:

{% from 'ieee754.jinja' import ieee754 %}
{{ ieee754("7bff") }}
{{ ieee754("fl_43F54001") }}
{{ ieee754("4037 0000 0000 0000") }}

EDIT: Complete version now at:

1 Like