Homeassistant Sensor Push

I have a lot of sensors connected to the GPIO pins of Raspberry PIs. They sent their data to my Flask based http API. To make the switch to homeassistant with as little changes as possible I decided to first try template sensors with webhooks.

These sensors are defined in the configuration.yaml for example for a SCD30 CO2 sensor:

template:
  - trigger:
      - platform: webhook
        webhook_id: !secret rpi-05-co2
        allowed_methods:
          - POST
        # my local network and VPN need this
        local_only: false
    unique_id: "scd30"
    sensor:
      - name: "SCD30 Temperature"
        state: "{{ trigger.json.temperature }}"
        unit_of_measurement: "°C"
        device_class: temperature
        unique_id: "scd30_temperature"
      - name: "SCD30 Humidity"
        state: "{{ trigger.json.humidity }}"
        unit_of_measurement: "%"
        device_class: humidity
        unique_id: "scd30_humidity"
      - name: "SCD30 CO2"
        state: "{{ trigger.json.co2 }}"
        unit_of_measurement: ppm
        device_class: carbon_dioxide
        unique_id: "scd30_co2"

The "device_class" automatically sets the correct icons and the "name" is the one shown in the entity list. The "unique_id" on toplevel is used to prefix all sensors and the "unique_id" per sensor allows custom definitions in the frontend, i.e. set an area.

The code to push sensor values from the Raspberry PI (with SCD30 connected) to homeassistant:

import requests
import time
from pathlib import Path
from scd30_i2c import SCD30

def push(data, secret):
    r = requests.post(f"http://192.168.0.3:8123/api/webhook/{secret}", json={
        "co2": round(data[0], 2),
        "temperature": round(data[1], 1),
        "humidity": int(data[2]),
    })
    assert r.status_code == 200

# webhook secret is read from file ".secret"
secret = (Path(__file__).parent / ".secret").open().read().strip()

scd30 = SCD30()
scd30.set_measurement_interval(2)
scd30.start_periodic_measurement()
while True:
    if scd30.get_data_ready():
        m = scd30.read_measurement()
        if m is not None:
            push(m, secret)
            time.sleep(2)
        else:
            time.sleep(0.2)
scd30.stop_periodic_measurement()

The sensor is connected via i2c. The Python library to get the values from the sensor is scd30-i2c. One special thing for the sensor is that the i2c timing has to be changed (see "I²C clock stretching" in the scd30-i2c readme).

I will change my other sensors (DHT22, BME280, BH1750 and ADS1015 (i.e. for photo resistors)) in the next weeks.