Skip to content

About

STM32 firmware for environmental telemetry, HTTP reporting, MQTT-triggered Wake-on-LAN, watchdog recovery, and Wi-Fi connectivity on the B-L475E-IOT01A.

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Repository files navigation

STM32 IoT Telemetry Client

Firmware for the ST B-L475E-IOT01A board. The device connects to a 2.4 GHz Wi-Fi network, reads onboard environmental sensors, periodically sends telemetry to an HTTP API behind Traefik, and listens for MQTT Wake-on-LAN commands.

The main use case is to keep a remote server informed that the home network is alive. Because every API call reaches the server through the Livebox public IP, the backend can infer and log the current public IP address without the STM32 needing to know it.

What It Does

  • Initializes the STM32 HAL and board peripherals generated by STM32CubeIDE.
  • Connects the ISM43362 Wi-Fi module to a configured 2.4 GHz SSID.
  • Reads onboard temperature, humidity, and pressure sensors.
  • Applies a configurable temperature offset to compensate for board self-heating.
  • Builds a structured JSON payload with telemetry, runtime counters, network metadata, and firmware information.
  • Sends the payload with an HTTP POST request to the configured API endpoint.
  • Maintains an MQTT connection and subscribes to a Wake-on-LAN command topic.
  • Sends a UDP Magic Packet on the local network when it receives the wake MQTT command.
  • Logs boot, Wi-Fi, telemetry, and API status over UART.
  • Runs an independent watchdog and self-healing recovery loop so the board can reboot if firmware or Wi-Fi operations get stuck.

Hardware

Target board:

  • ST B-L475E-IOT01A Discovery kit
  • STM32L475 MCU
  • ISM43362 Wi-Fi module
  • HTS221 humidity and temperature sensor
  • LPS22HB pressure sensor

This project currently includes BSP drivers for temperature, humidity, and pressure only. The board has additional sensors physically present, but their BSP drivers are not part of this workspace yet.

Project Structure

Application code lives in Core/Inc and Core/Src:

  • app.c / app.h: high-level application loop, scheduling, counters, and retry behavior.
  • app_config.h: versioned application configuration.
  • app_secrets.h: local Wi-Fi credentials, ignored by Git.
  • app_secrets.example.h: safe template for local secrets.
  • telemetry.c / telemetry.h: sensor initialization and averaged readings.
  • wifi_service.c / wifi_service.h: small wrapper around ST's wifi.h API.
  • api_client.c / api_client.h: JSON payload creation and HTTP request sending.
  • mqtt_client.c / mqtt_client.h: minimal MQTT 3.1.1 client for CONNECT, SUBSCRIBE, QoS 1 wake commands, keepalive, and reconnects.
  • wol.c / wol.h: Wake-on-LAN Magic Packet builder and UDP broadcast sender.
  • log.c / log.h: UART logging helpers.
  • system_health.c / system_health.h: reset reason capture, independent watchdog startup, watchdog refresh, and forced MCU reset.
  • main.c: STM32CubeIDE-generated initialization plus calls to App_Init() and App_Loop().

Configuration

Versioned configuration is in Core/Inc/app_config.h.

Important values:

#define APP_DEVICE_ID "stm32-room"
#define APP_FIRMWARE_VERSION "1.3.0"
#define APP_LOCATION "room"

#define APP_API_HOST "iot.mathislambert.fr"
#define APP_API_IP_ADDR {82U, 67U, 120U, 109U}
#define APP_API_PATH "/api/ingest?device=" APP_DEVICE_ID
#define APP_API_PORT 80U
#define APP_MQTT_KEEPALIVE_SECONDS 60U

#define APP_WOL_BROADCAST_PORT 9U

#define APP_SEND_INTERVAL_MS 300000UL
#define APP_SEND_RETRY_INTERVAL_MS 60000UL
#define APP_WIFI_RECOVERY_FAILURE_THRESHOLD 3U
#define APP_SYSTEM_RESET_FAILURE_THRESHOLD 12U
#define APP_TEMPERATURE_OFFSET_C 6.0f

The firmware uses a static API IP address to avoid DNS issues observed with the Wi-Fi module. It still sends the HTTP Host header, so Traefik can route by hostname.

Local Secrets

Wi-Fi credentials must be stored locally in:

Core/Inc/app_secrets.h

That file is ignored by Git. Use Core/Inc/app_secrets.example.h as a template:

#ifndef APP_SECRETS_H
#define APP_SECRETS_H

#define APP_WIFI_SSID "your-2.4ghz-ssid"
#define APP_WIFI_PASSWORD "your-wifi-password"

#define APP_MQTT_HOST "your-mqtt-host.example.com"
#define APP_MQTT_IP_ADDR_VALUE_0 192U
#define APP_MQTT_IP_ADDR_VALUE_1 0U
#define APP_MQTT_IP_ADDR_VALUE_2 2U
#define APP_MQTT_IP_ADDR_VALUE_3 10U
#define APP_MQTT_IP_ADDR {192U, 0U, 2U, 10U}
#define APP_MQTT_PORT 1883U
#define APP_MQTT_USERNAME "your-mqtt-username"
#define APP_MQTT_PASSWORD "your-mqtt-password"
#define APP_MQTT_WAKE_TOPIC "your/private/wake/topic"
#define APP_MQTT_STATUS_TOPIC "your/private/status/topic"

#define APP_WOL_PC_MAC {0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U}

#endif

Do not commit Core/Inc/app_secrets.h.

APP_WOL_PC_MAC must be replaced with the Ethernet MAC address of the PC to wake. If it stays all zeroes, the firmware will refuse to send the Magic Packet and log an error.

MQTT Wake-on-LAN

The firmware currently uses MQTT over plain TCP for STM32 compatibility. The public broker should restrict this account with ACLs to the wake and status topics only.

Runtime flow:

  1. The board connects to Wi-Fi.
  2. It opens an MQTT TCP connection to APP_MQTT_HOST:APP_MQTT_PORT.
  3. It authenticates with the configured username and password.
  4. It subscribes to APP_MQTT_WAKE_TOPIC with QoS 1.
  5. When it receives payload wake, it sends a 102-byte Wake-on-LAN Magic Packet to the local /24 broadcast address on UDP port 9.

Example command from a remote machine:

mosquitto_pub -h "$MQTT_HOST" -p "$MQTT_PORT" \
  -u "$MQTT_USERNAME" \
  -P "$MQTT_PASSWORD" \
  -t "$MQTT_WAKE_TOPIC" \
  -m wake \
  -q 1

TLS on 8883 is intentionally not enabled in firmware yet. The local driver has low-level SSL hints, but the public wrapper used by this project only exposes TCP and UDP cleanly. Plain MQTT is the first stable implementation target; MQTTS can be tested later behind a configurable WifiService_OpenSslClient() path.

Payload

The firmware sends an HTTP POST request with a structured JSON body compatible with the /api/ingest route from iot-api.

{
  "device": {
    "id": "stm32-room",
    "firmware": "1.3.0",
    "location": "room"
  },
  "runtime": {
    "uptime_ms": 6074,
    "sequence": 1,
    "success_count": 0,
    "failure_count": 0,
    "wifi_reconnect_count": 1,
    "consecutive_failure_count": 0,
    "watchdog_enabled": 1,
    "reset_reason": "power_on"
  },
  "network": {
    "ssid": "your_wifi_2.4GHz",
    "local_ip": "192.168.1.52",
    "api_host": "iot.mathislambert.fr",
    "api_ip": "82.67.120.109",
    "api_port": 80
  },
  "config": {
    "send_interval_ms": 300000,
    "retry_interval_ms": 60000,
    "temperature_offset_c": 6.0,
    "sample_count": 5
  },
  "sensors": {
    "humidity_sensor_id": 188,
    "pressure_sensor_id": 177
  },
  "telemetry": {
    "temperature_c": 25.24,
    "raw_temperature_c": 31.24,
    "humidity_percent": 46.37,
    "pressure_hpa": 991.38
  }
}

Build And Flash

Recommended workflow:

  1. Open the project in STM32CubeIDE.
  2. Create Core/Inc/app_secrets.h from Core/Inc/app_secrets.example.h.
  3. Build the project.
  4. Flash the board with Run or Debug.
  5. Open a serial terminal on the ST-LINK COM port at 115200 8N1.

The local command-line build used during development was:

make -C Debug all

The exact make and arm-none-eabi-gcc paths may depend on the STM32CubeIDE installation.

UART Logs

The firmware logs over USART1 at 115200 baud.

Example:

[2] INFO  Starting stm32-room
[3] INFO  Reset reason=power_on watchdog=enabled
[5] INFO  Sensors initialized
[588] INFO  WiFi module initialized
[591] INFO  Connecting to WiFi SSID "your_wifi_2.4GHz"
[5660] INFO  WiFi connected with local IP 192.168.1.52
[5665] INFO  Opening MQTT TCP connection to your-mqtt-host.example.com:1883 (192.0.2.10)
[5901] INFO  MQTT connected and subscribed
[6074] INFO  Telemetry temp=25.24C raw=31.24C hum=46.37% pressure=991.38hPa
[6081] INFO  Opening TCP connection to iot.mathislambert.fr:80 (82.67.120.109)
[9247] INFO  Sent 339/339 bytes to API
[9496] INFO  API response received (255 bytes)
[9588] INFO  Telemetry sent successfully

Self-Healing Behavior

The firmware is designed to keep running unattended:

  • The independent watchdog (IWDG) starts early during boot and uses the STM32L4 LSI clock with the maximum practical timeout, about 32 seconds.
  • The watchdog is refreshed only from the main application loop. If the firmware blocks inside Wi-Fi, SPI, HAL, a fault handler, or Error_Handler(), the board resets automatically.
  • Consecutive failures are tracked and reported in the API payload.
  • After APP_WIFI_RECOVERY_FAILURE_THRESHOLD consecutive failures, the firmware closes the socket, disconnects Wi-Fi, resets the Wi-Fi module, and reconnects cleanly.
  • After APP_SYSTEM_RESET_FAILURE_THRESHOLD consecutive failures, the firmware requests a full MCU reset with NVIC_SystemReset().
  • On boot, reset flags are captured before being cleared, then the reset reason is sent in the next payload.

Notes

  • The board Wi-Fi module connects to 2.4 GHz networks. A 5 GHz-only SSID will not work.
  • HTTPS/TLS on port 443 was not reliable with the current Wi-Fi wrapper and module firmware. The working setup uses HTTP on port 80 and relies on the backend network configuration for exposure and routing.
  • Build outputs under Debug/ and Release/ are intentionally ignored.

About

STM32 firmware for environmental telemetry, HTTP reporting, MQTT-triggered Wake-on-LAN, watchdog recovery, and Wi-Fi connectivity on the B-L475E-IOT01A.

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages