🪟 Windows TippsThe Gemini desktop app is now available for Windows(11.09.2026 um 17:06 Uhr)
🕵️ SicherheitslückenBurn Out, Or Fade Away(14.09.2026 um 14:25 Uhr)
🪟 Windows TippsProfi-Edelstahlpfanne von WMF jetzt zum halben Preis erhältlich(15.09.2026 um 08:05 Uhr)
🪟 Windows TippsThe Gemini desktop app is now available for Windows(11.09.2026 um 17:06 Uhr)
🕵️ SicherheitslückenBurn Out, Or Fade Away(14.09.2026 um 14:25 Uhr)
🪟 Windows TippsProfi-Edelstahlpfanne von WMF jetzt zum halben Preis erhältlich(15.09.2026 um 08:05 Uhr)

🔧 Programmierung 🕛 vor 5 Monaten 8 Min Lesezeit
0

How to send sensor data to a gateway using PainlessMesh in ESP8266?

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

Hello, I'm Ganesh. I'm building git-lrc, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github.





What We will be achieving?



Painlessmesh is very heavy library. It does lot of operations to keep network alive. With this if we send data without compressing it. It will consume lot of power and data. Casuing network to be unstable.



Main Goal is




  1. Receive data from multiple sensors

  2. Compress the data

  3. Send the data to gateway

  4. Publish the data from received at gateway to cloud using MQTT

  5. Scallable MQTT topics publishing



I will be combining all the above mentioned in single project.



In this article we will be covering first 2 points.




  1. Receiving Data from Multiple Sensors

  2. Compressing the data

  3. Send the data to gateway





Receiving Data from Multiple Sensors and Compressing it



For this example we will use DHT11 sensor and MQ2 gas sensor.




  1. Setup connection with painlessmesh
    We will use these credentials for painlessmesh.



CODE
#define MESH_PREFIX "secreat_name"
#define MESH_PASSWORD "SecreateKey"
#define MESH_PORT 5555






With this funtion we create scheduler and painlessmesh object.




CODE
#include <painlessMesh.h>

mesh.init(MESH_PREFIX, MESH_PASSWORD, &scheduler, MESH_PORT);
mesh.onReceive(&onReceive);
mesh.onNewConnection(&onNewConnection);







  1. Setup connection with DHT11 sensor



We use DHT library sensor to measure temperature and humidity.



We use D2 pin to connect DHT11 sensor.




CODE
#include <DHT.h>
#define DHT_PIN D2
#define DHT_TYPE DHT11

DHT dht(DHT_PIN, DHT_TYPE);






Read the temperature and humidity from the sensor.




CODE
float t = dht.readTemperature();
float h = dht.readHumidity();






As Dht sensor should have 1 second delay between readings. We will use scheduler to read the temperature and humidity from the sensor.




CODE
Task readDHTTask(10000, TASK_FOREVER, []() {
float t = dht.readTemperature();
float h = dht.readHumidity();
if (isnan(t) || isnan(h)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
Serial.printf("Temperature: %.2f C, Humidity: %.2f %%", t, h);
});







  1. Setup connection with MQ2 gas sensor



We use MQ2 gas sensor to measure the gas concentration.



We use A0 pin to connect MQ2 gas sensor.




CODE
#define MQ2_PIN A0






Read the gas concentration from the sensor.




CODE
float gas = analogRead(MQ2_PIN);






As MQ2 sensor should have 1 second delay between readings. We will use scheduler to read the gas concentration from the sensor.




CODE
Task readMQ2Task(10000, TASK_FOREVER, []() {
float gas = analogRead(MQ2_PIN);
if (isnan(gas)) {
Serial.println("Failed to read from MQ2 sensor!");
return;
}
Serial.printf("Gas: %.2f ppm", gas);
});







  1. Compress the data with bit packing



We use bit packing to compress the data.



As sensor will be in specified range we can use bit packing to compress the data.




CODE
String packToHex(float temp, float hum, float gas) {
uint16_t packedTemp = (uint16_t)(temp * 10.0f) & 0x1FF; // 9 bits
uint16_t packedHum = (uint16_t)((hum - 20.0f) * 10.0f) & 0x3FF; // 10 bits
uint16_t packedGas = (uint16_t)(gas / 10.0f) & 0x3FF; // 10 bits

uint32_t packed = 0;
packed |= (uint32_t)packedTemp << 20; // bits 28-20
packed |= (uint32_t)packedHum << 10; // bits 19-10
packed |= (uint32_t)packedGas; // bits 9-0

char buf[9];
snprintf(buf, sizeof(buf), "%08X", packed);
return String(buf);
}






Finaly commbining all these into one code.




CODE
/**
* sensor_node_1.cpp — PainlessMesh Sensor Node (DHT11 + MQ6)
*
* Boot flow:
* 1. Joins the mesh network
* 2. On first connection to gateway → broadcasts /config (packing schema)
* The gateway forwards /config to MQTT → backend caches the schema
* 3. After 3 s delay → starts sending /data every 5 s
* (gives backend time to process /config before first hex payload arrives)
*
* /alert is sent immediately any time gas > GAS_THRESHOLD.
*
* Bit packing layout (29 bits used, 3 MSBs unused):
* bits 28-20 (9 bits) : temp = temp_celsius * 10 (0–511 → 0–51.1°C)
* bits 19-10 (10 bits): hum = (humidity - 20) * 10 (0–1023 → 20–122.3%)
* bits 9-0 (10 bits): gas = gas_ppm / 10 (0–1023 → 0–10230
* ppm)
*/


#include <Arduino.h>
#include
<ArduinoJson.h>
#include
<DHT.h>
#include
<painlessMesh.h>

// ─── Mesh credentials (must match gateway) ───────────────────────────────────
#define MESH_PREFIX "secreat_name"
#define MESH_PASSWORD "SecreateKey"
#define MESH_PORT 5555

// ─── Sensor pins ─────────────────────────────────────────────────────────────
#define DHT_PIN D2
#define DHT_TYPE DHT11
#define MQ6_PIN A0 // analog pin

// ─── Alert threshold ─────────────────────────────────────────────────────────
#define GAS_THRESHOLD 5000 // ppm — triggers /alert

// ─── Timing ──────────────────────────────────────────────────────────────────
#define DATA_INTERVAL_MS 5000

// ─── Globals ─────────────────────────────────────────────────────────────────
Scheduler scheduler;
painlessMesh mesh;
DHT dht(DHT_PIN, DHT_TYPE);
bool configSent = false; // send /config once per gateway connection

// ─── Bit packing ─────────────────────────────────────────────────────────────

/**
* Pack temperature, humidity and gas into an 8-char hex string.
* The encoding matches what the backend's unpackHex() expects.
*
* temp → 9 bits, mult 10, min 0
* hum → 10 bits, mult 10, min 20
* gas → 10 bits, div 10, min 0
*/

String packToHex(float temp, float hum, float gas) {
uint16_t packedTemp = (uint16_t)(temp * 10.0f) & 0x1FF; // 9 bits
uint16_t packedHum = (uint16_t)((hum - 20.0f) * 10.0f) & 0x3FF; // 10 bits
uint16_t packedGas = (uint16_t)(gas / 10.0f) & 0x3FF; // 10 bits

uint32_t packed = 0;
packed |= (uint32_t)packedTemp << 20; // bits 28-20
packed |= (uint32_t)packedHum << 10; // bits 19-10
packed |= (uint32_t)packedGas; // bits 9-0

char buf[9];
snprintf(buf, sizeof(buf), "%08X", packed);
return String(buf);
}

// ─── Message builders
// ─────────────────────────────────────────────────────────

/**
* Build the /config JSON that tells the backend how to decode our hex payloads.
* This matches the NodeConfig struct on the backend.
*/

String buildConfigMsg() {
JsonDocument doc;
doc["type"] = "config";
doc["hw"] = "NodeMCUv2";

JsonObject packing = doc["packing"].to<JsonObject>();
packing["bits"] = 32;
JsonArray layout = packing["layout"].to<JsonArray>();
layout.add("temp");
layout.add("hum");
layout.add("gas");

JsonObject sensors = doc["sensors"].to<JsonObject>();
JsonObject t = sensors["temp"].to<JsonObject>();
t["model"] = "DHT11";
t["metric"] = "temperature";
t["min"] = 0;
t["max"] = 50;
t["mult"] = 10;
t["bits"] = 9;

JsonObject h = sensors["hum"].to<JsonObject>();
h["model"] = "DHT11";
h["metric"] = "humidity";
h["min"] = 20;
h["max"] = 90;
h["mult"] = 10;
h["bits"] = 10;

JsonObject g = sensors["gas"].to<JsonObject>();
g["model"] = "MQ6";
g["metric"] = "gas_mq6";
g["min"] = 0;
g["max"] = 10000;
g["div"] = 10;
g["bits"] = 10;

String out;
serializeJson(doc, out);
return out;
}

String buildDataMsg(const String &hexStr) {
JsonDocument doc;
doc["type"] = "data";
doc["d"] = hexStr;
String out;
serializeJson(doc, out);
return out;
}

String buildAlertMsg(const String &hexStr, const char *cause) {
JsonDocument doc;
doc["type"] = "alert";
doc["cause"] = cause;
doc["d"] = hexStr;
String out;
serializeJson(doc, out);
return out;
}

// ─── Periodic data task
// ────────────────────────────────────────────────────────

Task dataTask(DATA_INTERVAL_MS, TASK_FOREVER, []() {
float temp = dht.readTemperature();
float hum = dht.readHumidity();

// MQ6: raw analog 0-1023 → scale to ppm (rough calibration, adjust to yours)
int raw = analogRead(MQ6_PIN);
float gas = raw * (10000.0f / 1023.0f); // map 0-1023 → 0-10000 ppm

if (isnan(temp) || isnan(hum)) {
Serial.println("[sensor] DHT read failed");
return;
}

Serial.printf("[sensor] temp=%.1f°C hum=%.1f%% gas=%.0f ppm\n", temp, hum,
gas);

String hexStr = packToHex(temp, hum, gas);

// Always send /data
mesh.sendBroadcast(buildDataMsg(hexStr));

// Send /alert if threshold breached
if (gas > GAS_THRESHOLD) {
Serial.println("[sensor] ⚠ Gas threshold breached — sending alert");
mesh.sendBroadcast(buildAlertMsg(hexStr, "gas_mq6"));
}
});

// One-shot task: fires 3 s after /config is sent, then enables dataTask.
// The 3 s gives the gateway time to publish /config to MQTT and the backend
// time to cache the packing schema before the first hex payload arrives.
Task startupTask(3000, 1, []() {
Serial.println("[sensor] Config settle time elapsed — starting data stream");
scheduler.addTask(dataTask);
dataTask.enable();
});

// ─── Mesh callbacks
// ────────────────────────────────────────────────────────────
void onReceive(uint32_t from, String &msg) {
Serial.printf("[mesh] From %u: %s\n", from, msg.c_str());
// Future: handle /cmd messages from gateway
}

void onNewConnection(size_t nodeId) {
Serial.printf("[mesh] +Connected to %u\n", (uint32_t)nodeId);

if (!configSent) {
// First connection — push /config so backend can cache packing schema
mesh.sendBroadcast(buildConfigMsg());
Serial.println("[mesh] Sent /config — waiting 3 s before data stream");
configSent = true;

// Start the 3-second countdown before data begins
scheduler.addTask(startupTask);
startupTask.enable();
}
}

// ─── Setup / Loop
// ─────────────────────────────────────────────────────────────
void setup() {
Serial.begin(115200);
delay(100);

dht.begin();

mesh.setDebugMsgTypes(ERROR | CONNECTION);
mesh.setContainsRoot(
true); // tells node the root (gateway) is in this network
mesh.init(MESH_PREFIX, MESH_PASSWORD, &scheduler, MESH_PORT);
mesh.onReceive(&onReceive);
mesh.onNewConnection(&onNewConnection);

Serial.printf("[mesh] Node ID: %u — waiting for gateway connection...\n",
mesh.getNodeId());
}

void loop() { mesh.update(); }






By above code we can send data from multiple sensors to gateway using painlessmesh.






Conclution



In this article we have seen how to use painlessmesh with a NodeMCUv2 (ESP8266) board and send data from one ESP8266 board to another ESP8266 board.



In next article we will integrate scallable gateway.



Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
The Gemini desktop app is now available for Windows
1 Quelle
Burn Out, Or Fade Away
1 Quelle
Windows 11 KB5129195 is out after Microsoft confirms major issues with the September 2026 update, but it won’t fix AMD GPU errors
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten How to send sensor data to a gateway using PainlessMesh in ESP8266?

Thematisch verwandte Begriffe: send, sensor, data, gateway · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...