How to split data received on the serial port?

Hi there !

I have many temperature/hydro sensors that send data (HF) to an arduino gateway connected to my raspberry pi thru USB (next step will be to use ext IO as serial to avoid the USB cable).

https://www.fabriqueurs.com/poc-domotique-arduino-raspberry-pi/

I would like to split all the information sent by my sensors in order to manage them independently in HA: Have a dedicated history graph or item in the dashboard, for each information receive in the serial port (temperature in garage, hydro in bed room, …, ).

I did a first version using a pyphon script that read the serial port and send data to the MQTT broker but I’m looking for a simplest way (using sensor template ?).

The Arduino gateway send in jason format the information (received in HF by all sensors) to the serial port:

{“capt_info”:{“Type”:“DHT22”,“id”:“S2”},“capt_value”:{“Temp”:“21.0”,“Hydro”:“49.20”}}

{“capt_info”:{“Type”:“DHT22”,“id”:“S1”},“capt_value”:{“Temp”:“18.1”,“Hydro”:“58.30”}}

Any help would be appreciated,
Pierre

Got it! Templates were the solution.

 # Sensors
sensor:
  # serial sensor
  - platform: serial
    #serial_port: /dev/ttyUSB0
    serial_port: /dev/ttyAMA0

  - platform: template
    sensors:
      # split values from serial sensor
      temperature_s1:
        friendly_name: "Température Maison"  
        value_template: >
          {% if (states.sensor.serial_sensor.attributes["capt_info"]["id"] == "S1") -%}                
            {{ states.sensor.serial_sensor.attributes["capt_value"]["Temp"] }}
          {% else -%}
            {{ states.sensor.temperature_s1.state }}
          {% endif -%}
      temperature_s2:
        friendly_name: "Température Garage"
        value_template: >
          {% if (states.sensor.serial_sensor.attributes["capt_info"]["id"] == "S2") -%}
            {{ states.sensor.serial_sensor.attributes["capt_value"]["Temp"] }}
          {% else -%}
            {{states.sensor.temperature_s2.state}}          
          {% endif -%}
      temperature_s3:
        friendly_name: "Température ext"
        value_template: >
          {% if (states.sensor.serial_sensor.attributes["capt_info"]["id"] == "S3") -%}
            {{ states.sensor.serial_sensor.attributes["capt_value"]["Temp"] }}
          {% else -%}
            {{states.sensor.temperature_s3.state}}
          {% endif -%}
 
      hydrometrie_s1:
        friendly_name: "Humidité Maison"     
        value_template: >
          {% if (states.sensor.serial_sensor.attributes["capt_info"]["id"] == "S1") -%}
            {{ states.sensor.serial_sensor.attributes["capt_value"]["Hydro"] }}
          {% else -%}
             {{ states.sensor.hydrometrie_s1.state }}
          {% endif -%}
      hydrometrie_s2:
        friendly_name: "Humidité Garage"
        value_template: >
          {% if (states.sensor.serial_sensor.attributes["capt_info"]["id"] == "S2") -%}
            {{ states.sensor.serial_sensor.attributes["capt_value"]["Hydro"] }}
          {% else -%}
            {{ states.sensor.hydrometrie_s2.state }}
          {% endif -%}
      hydrometrie_s3:
        friendly_name: "Humidité ext"
        value_template: >
          {% if (states.sensor.serial_sensor.attributes["capt_info"]["id"] == "S3") -%}
            {{ states.sensor.serial_sensor.attributes["capt_value"]["Hydro"] }}
          {% else -%}
            {{ states.sensor.hydrometrie_s3.state }}
          {% endif -%}
3 Likes

Thank you for sharing this, it looks very elegant!

I’m trying to extract the sensor number out of this string (sensor.serial_sensor):

output for the first sensor: 1+1812.50+22.9+1
output for the second sensor: 2+1805.06+22.7+1
etc.

I can’t figure out how to split my string sensor.serial_sensor. Something like

‘sensor.serial_sensor.split(’+')[0] ’

Gives the correct sensor number, but I can’t figure out how to incorporate that line of code line into your example to base an if statement on it.

Hi Guys,

Maybe you could help me…

I have a sensor that sends out:

“Z 01234 z 01234”

How can I split these 2 numbers into 2 numeric values?

I have studied your template, but can not see how this is done.

Here you go:

{% set var = "Z 01234 z 5678" | regex_replace(find="z ", replace="", ignorecase=True) %}
{% set list = var.split(' ') %}
{{ list[0] | int }} - {{ list[1] | int }}

Result:

1234 - 5678
1 Like

Hi thanks for the reply.

Honestly I do not see (yet) how to implement this to my needs. :slight_smile:
Thats due the lack of knowledge, but we will get there.

So what I think it does.

  1. it finds any z + space (not case sensitive.) then replaces (deletes) this part.
  2. Then you set up 2 variables?, and split them at the last remaining space?
  3. make a new string with the 2 variables divided by a “-” sign.

In the past I seemed to got the UART working following the UART Text sensor example.
But at the moment I do not seem to get this working again.

Should I do this part in ESPhome on the device itself? or should I do in HA?

This is my part of code I use to read out the raw sensor data:

esphome:
  name: test
  platform: ESP8266
  board: d1_mini
  includes:
    - uart_read_line_sensor.h
    
wifi:
  fast_connect: true
  networks:
    - ssid: !secret wifi_ssid
      password: !secret wifi_password
      hidden: true
       
  

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Test Fallback Hotspot"
    password: !secret wifi_password

captive_portal:

logger:

# Enable Home Assistant API
api:

ota:

uart:
  id: uart_bus
  tx_pin: D1
  rx_pin: D2
  baud_rate: 9600

text_sensor:
- platform: custom
  lambda: |-
    auto my_custom_sensor = new UartReadLineSensor(id(uart_bus));
    App.register_component(my_custom_sensor);
    return {my_custom_sensor};
  
  text_sensors:
    id: "uart_readline"
    name: "Co2-Raw"

I have got this working in HA

Values where stored starting in list 1 and then list 2, not list 0…

But can I do this directly on the device?

  - platform: template
    sensors:
      co2_converter:
        unit_of_measurement: "ppm"
        friendly_name: "Co2 value"
        value_template: >-
          {% set var = states.sensor.co2_raw.state | regex_replace(find="z ", replace="", ignorecase=True) %}
          {% set list = var.split(' ') %}
          {{ list[1] | int }}