Template Sensors help for a string of text! Heat Recovery (MVHR) using serial (RS-485)

Greetings fellow HA earthlings… hope you can advise me with my dilemma to create some sensor templates

Background:
I just figured out how to connect to our Heat Recovery Ventilation System (MVHR) using a USB to RS-485 serial adaptor (see post here). I don’t believe its using Modbus though.

After consulting a technical document I found online (link), I can connect a Linux VM using Minicom (terminal emulator) and the settings provided in the manual. I can send it commands and they work successfully. The output looks like this (with the system typically generating a command output every 15 seconds automatically - note none of my efforts to copy/paste commands are listed in this example):

1510+00000
151+00000
1520+00000
152+00000
1540+00000
154+00000
3260+00000
326+00000
0601+00000
060+45505
061+02050
061+02050

(then repeats this output again every 15 seconds).

Progress to date:
So using the vendors technical document and a bit of trial and error, i’ve divised a ‘codebook’ which looks something like this:

Value Description Submit/Receive Msg. Notes
1510+00000 Speed 1 off Submit >>>
1510+00001 Speed 1 on Submit >>>
1520+00000 Speed 3 off Submit >>>
1520+00001 Speed 3 on Submit >>>
1540+00000 Speed 4 off Submit >>>
1540+00001 Speed 4 on Submit >>>
3260+00000 Boost off Submit >>>
3260+00001 Boost on Submit >>>
0301xxxxxx Thermistor 1 (stale in) Submit >>>
030+00207 Thermistor 1 (stale in) Receive <<< Translates 20.7 Degrees C.
0311xxxxxx Thermistor 2 (stale out) Submit >>>
031+00137 Thermistor 2 (stale out) Receive <<< Translates to 13.7 Degrees C.
0321xxxxxx Thermistor 2 (fresh in) Submit >>>
032+00107 Thermistor 2 (fresh in) Receive <<< Translates to 10.7 Degrees C.
0361xxxxxx Internal Humidity Submit >>>
036+00055 Internal Humidity Receive <<< Translates to 55% Relative Humidity (RH)
0601xxxxxx Time Running (hours) since commissioning Submit >>>
060+45482 Time Running (hours) since commissioning Receive <<< 45482 hours = 5.19 years
3411xxxxxx Filter remaining time (if all zeros, needs replacing Needs checking/validation
0611xxxxxx Any errors to report? Submit >>>
061+02050 Response 1 example Receive <<<

The Goal:
It would be great to build a number of sensors and switches to essentially manage the MVHR unit via serial (RS-485). Below is an incorrect ‘work in progress’ of starting to put these templates together. I need help in how to finish the “Sensor” templates correctly. I just can’t figure out how to tell it to output the last few digits as seperate sensors, which are based on what the 1st part of the message code is (i.e before the “+” delimiter).

EG: 032+00107 is broken down as:
“032+” is the reference for “Fresh in” and the output state/attribute is “10.7°C”

Any feedback greatly appreciated :slight_smile:

Sample 1st draft of templates below (i’m aware its incorrect (and not finding the specific ‘if’ syntax):

sensor:
  - platform: serial
    serial_port: /dev/ttyUSB1
    name: MVHR
    baudrate: 1200

template:
  sensor:
    - name: MVHR Temperature (Stale in)
      unit_of_measurement: "°C"
      state: "{{ states('sensor.MVHR').split('+')[1] | float(default=0) }}"

    - name: MVHR Temperature (Stale out)
      unit_of_measurement: "°C"
      state: "{{ states('sensor.MVHR').split('+')[1] | float(default=0) }}"

    - name: MVHR Temperature fresh in)
      unit_of_measurement: "°C"
      state: "{{ states('sensor.MVHR').split('+')[1] | float(default=0) }}"

    - name: MVHR Humidity
      unit_of_measurement: "%"
      state: "{{ states('sensor.MVHR').split('+')[1] | float(default=0) }}"

    - name: MVHR uptime (total)
      unit_of_measurement: "h"
      state: "{{ states('sensor.MVHR').split('+')[1] | float(default=0) }}"

    - name: MVHR Current Speed (1-4)
      unit_of_measurement: ""
      state: "{{ states('sensor.MVHR').split('+')[1] | float(default=0) }}"

    - name: MVHR Boost Status 
      unit_of_measurement: ""
      state: "{{ states('sensor.MVHR').split('+')[1] | float(default=0) }}"

    - name: MVHR Summer Bypass Mode (on/off)
      unit_of_measurement: ""
      state: "{{ states('sensor.MVHR').split(':')[4] | float(default=0) }}"

   - name: MVHR Frost Protection Mode (on/off)
      unit_of_measurement: ""
      state: "{{ states('sensor.MVHR').split(':')[4] | float(default=0) }}"

    - name: MVHR Fault Code
      unit_of_measurement: ""
      state: "{{ states('sensor.MVHR').split(':')[4] | float(default=0) }}"

I haven’t made an attempt to propose a switch example (don’t want to embaress myself further!). Would be great to get a suggestion for such. There may also need to be automations to trigger requests for sensor data such as sensor temperatures etc… but thats for a later date :blush:
As above, any constructive pointers and/or feedback greatly appreciated :slight_smile:

1 Like

I’ll let you do the rest of them, but here’s a couple examples:

template:
  - trigger:
      - platform: state
        entity_id: sensor.mvhr
        not_to:
          - 'unknown'
          - 'unavailable'
    sensor:
      - name: MVHR Temperature (Stale in)
        unit_of_measurement: "°C"
        state: 
          {% set current = this.state | default(0, 1) %}
          {% set list = (trigger.to_state.state).split('+') %}
          {{ list[1] if list[0] == '030'  else current }}

      - name: MVHR Temperature (Stale out)
        unit_of_measurement: "°C"
        state: 
          {% set current = this.state | default(0, 1) %}
          {% set list = (trigger.to_state.state).split('+') %}
          {{ list[1] if list[0] == '031'  else current }}

....
1 Like

Thanks for the suggestions @Didgeridrew… i’ll play around with them in the Template editor (Developer Tools) and see how it goes… sincere thanks for taking the time :blush:

Just be aware that neither the self-referencing variable this nor the variable trigger will be defined in the Template editor tool, so testing it that way is not straight-forward.

1 Like

Finally got to test this @Didgeridrew (thanks again). I’ve got the first one to work (need to debug the 2nd one to see where I’m going wrong). Can you suggest how I incorporate ‘round’ to one decimal point?

For example, I’m getting into the sample you kindly provided. EG getting a return value of “195 °C” but need it to read as “19.5 °C”. Thanks :slight_smile:

The value comes from list[1], so you’ll need to replace it in each last line with something like:

{{ (list[1] | int / 10) if list[0] == '031'  else current }}
1 Like