🛠 Publier capteurs et batterie en MQTT via une passerelle
Objectives
Build a battery-powered sensor node that publishes temperature and battery level to an MQTT broker. The hardware architecture is fixed: the Nicla (no WiFi) acts as a BLE peripheral with a custom service, while the MKR WiFi 1010 host board serves as the BLE-to-MQTT gateway. On the Nicla side, the Nicla_System API provides an accurate battery level read from the BQ25120 charger registers (nicla::getBatteryVoltagePercentage, nicla::getCurrentBatteryVoltage), which is much more reliable than a simple voltage divider. This is the reference schema for Nicla-format wireless sensor networks as described by Arduino Pro.
Hardware
- Nicla Sense ME (ABX00050) + LiPo battery on J4 (with or without NTC depending on the battery:
nicla::setBatteryNTCEnabled(false)if absent) - MKR WiFi 1010 (or Portenta C33) as the gateway; ArduinoBLE libraries on the Nicla, WiFi101 + PubSubClient on the host
- Accessible MQTT broker (local or hosted)
- >
Complete Code
// Sketch NICLA : peripheral BLE batterie + temperature
#include "Nicla_System.h"
#include "Arduino_BHY2.h"
#include <ArduinoBLE.h>
Sensor temp(SENSOR_ID_TEMP);
BLEService batteryService("180F");
BLEUnsignedCharCharacteristic battLevel("2A19", BLERead | BLENotify);
BLEFloatCharacteristic tempChar("2A6E", BLERead | BLENotify);
void setup {
Serial.begin(9600);
nicla::begin;
nicla::setBatteryNTCEnabled(false);
nicla::leds.begin;
nicla::leds.setColor(green);
BHY2.begin;
temp.begin;
if (!BLE.begin) { while (1); }
BLE.setLocalName("NiclaNode");
BLE.setAdvertisedService(batteryService);
batteryService.addCharacteristic(battLevel);
batteryService.addCharacteristic(tempChar);
BLE.addService(batteryService);
BLE.advertise;
}
void loop {
static auto t = millis;
BHY2.update;
BLE.poll;
if (millis - t >= 10000) {
t = millis;
battLevel.writeValue((unsigned char)nicla::getBatteryVoltagePercentage);
if (temp.dataAvailable) tempChar.writeValue(temp.value);
}
}
// Sketch HOTE (MKR WiFi 1010) : passerelle BLE -> MQTT
#include <WiFi101.h>
#include <PubSubClient.h>
WiFiClient net;
PubSubClient mqtt(net);
BLEDevice node;
void setup {
WiFi.begin("MON_WIFI", "MON_MOT_DE_PASSE");
mqtt.setServer("192.168.1.40", 1883);
BLE.begin;
BLE.setScanTimeout(5000);
node = BLE.scanForName("NiclaNode");
while (!node) { node = BLE.scanForName("NiclaNode"); }
node.connect;
mqtt.connect("nicla-gateway");
}
void loop {
if (!node.connected || !mqtt.connected) { return; } // reconnexion a gerer
BLE.poll;
static auto t = millis;
if (millis - t >= 30000) {
t = millis;
unsigned char batt = node.characteristic("2A19").readValue;
char payload[96];
snprintf(payload, sizeof(payload), "{\"batt_pct\":%u}", batt);
mqtt.publish("maison/nicla1", payload);
}
}
Expected Verification
mosquitto_sub -t 'maison/nicla1' displays periodic JSON containing the battery percentage read from the charger. The green LED on the Nicla indicates power; using nRF Connect, you can audit the 2A19/2A6E characteristics between publications. As the LiPo discharges, the percentage should decrease regularly (recalibrate if the curve appears flat, as LiPo voltage is not very linear).
Common Errors
- Publishing blindly without handling disconnections: the Nicla's BLE sleeps, and the host's WiFi drops; plan for complete reconnection loops before leaving the node alone in production.
- Forgetting
BLE.pollon the Nicla: central devices read frozen values; the same symptom occurs ifBHY2.updateis missing. - Relying on a raw percentage without accounting for charging:
nicla::getOperatingStatusand the charging voltage affect the reading; also display the raw voltage for debugging. - Publishing too frequently: 10 s on the Nicla and 30 s on MQTT are comfortable for a 200 mAh LiPo; the datasheet specifies 1.15 mA typical during advertising + one measurement per hour, and every extra second of radio use costs battery life.
- >
Other tutorials for this board
Code examples for this board
led_rgb.inoArduinoimu_bhi260.inoArduinorotation_fusion.inoArduinopression_bmp390.inoArduinonose_electronique.inoArduinoboussole_bmm150.inoArduino