Skip to content

Firmware Architecture & Algorithms

The firmware implementations in 48broadbent/broadbent incorporate sophisticated on-device processing, sensor compensation algorithms, and local graphics routines. This page breaks down the core patterns used across the fleet.


1. MQTT Weather Forecast JSON Parsing

Nodes with e-paper screens (pluto, venus, alichino, etc.) subscribe to an MQTT topic sensor/weather/forecast that broadcasts 3-day weather forecasts generated by Home Assistant.

An inline C++ lambda parses the JSON array and stores the days, temperatures, rain probabilities, and Unicode weather icons directly into ESPHome vector globals:

mqtt:
  broker: !secret mqtt_broker
  discovery: false
  on_json_message:
    - topic: sensor/weather/forecast
      then:
        - lambda: |-
            int i = 0;
            for (auto k: id(keys)) {
              if (!x[k].isNull()) {
                id(days)[i] = x[k]["day"].as<const char *>();
                id(Ts)[i]   = x[k]["nT"];          // Next-day temperature
                id(pp)[i]   = x[k]["pP"];          // Precipitation probability
                id(wind)[i] = x[k]["wind"];        // Wind speed
                id(code)[i] = x[k]["condition"];   // Weather condition index
                i++;
              }
            }

2. Hypsometric Sea-Level Pressure Compensation

Barometric pressure measured by the BME280 or BME680 reflects the raw station pressure at the local elevation (~35 meters above sea level). To display standard meteorologic Mean Sea Level Pressure (MSLP), the firmware calculates:

[ P_{\text{sea}} = \frac{P_{\text{station}}}{\left(1 - \frac{L \cdot h}{T_0}\right)^{\frac{g \cdot M}{R_0 \cdot L}}} ]

For an altitude of exactly 35 meters, this yields a pre-calculated standard divisor of 0.995858 (or 0.996212 for 32 meters):

sensor:
  - platform: template
    name: "${sensor} ${devicename} Sea Level Pressure"
    id: sea_level_pressure
    unit_of_measurement: "hPa"
    accuracy_decimals: 1
    icon: "mdi:weather-partly-cloudy"
    lambda: |-
      if (id(my_pres).has_state()) {
        // Pre-calculated standard hypsometric divisor for exactly 35 meters
        return id(my_pres).state / 0.995858;
      } else {
        return 0.0;
      }

3. Sensirion SGP40 Dynamic Compensation

The Sensirion SGP40 metal-oxide gas sensor calculates the VOC Index (a standardized 1 to 500 scale where 100 represents typical indoor clean air). The raw sensor resistance is sensitive to ambient temperature and absolute humidity.

The firmware routes live readings from the adjacent BME280 sensor directly into the SGP40 compensation engine:

sensor:
  - platform: sgp4x
    address: 0x59
    i2c_id: bus_b
    update_interval: 300s
    voc_index:
      name: "${sensor_airq2} ${devicename} VOC Index"
      id: my_voc
      accuracy_decimals: 1
      filters:
        - or:
            - throttle: 300s
            - delta: 2
    compensation:
      temperature_source: my_temp
      humidity_source: my_hum

4. Optical Dust Sensor UART Processing

In dust-front.yaml, dust-kitchen.yaml, and dust-up.yaml, fine particulate matter (PM2.5) is measured via optical light scattering using the PM1006 sensor communicating over UART (9600 baud):

uart:
  rx_pin: D2
  baud_rate: 9600

sensor:
  - platform: pm1006
    pm_2_5:
      id: my_pm25
      name: ${sensor} ${devicename} concentration
      internal: false
      filters:
        # Throttle telemetry to reduce Wi-Fi radio wakeups unless values shift
        - or:
            - throttle: 600s
            - delta: 1

5. M5Stack Atom Matrix 5×5 LED Scrolling Display

In atom_matrix.yaml (named gutenberg), the firmware controls a miniature 5×5 RGB addressable LED array running on an ESP32-PICO:

  • Reads temperature and humidity from an onboard Sensirion SHT30 sensor (I2C address: 0x44).
  • Includes custom C++ driver logic (include/my_matrixled_scrolling_display.h) to scroll multi-digit temperature values across the 5×5 matrix with smooth color gradients.
  • Automatically flips display brightness down during evening hours to maintain subtle room ambient lighting.