Improve the canonical "node-wifi-mqtt" firmware

I’m sorry for being so unresponsive with respect to contributions and latency; however, I successfully tested the updated node-wifi-mqtt firmware featuring dynamic JSON payload sizing (as @Andreas asked me about it) . Also, I received all hardware sensors, and started testing the sensor acquisition firmware parts, instead of sending fake data. As a first test, I started fetching data from the DS18B20 sensor. After some debug (the sensor was not working due to the absence of the pull-up resistor) I was thinking about some aspects of the firmware:

  1. Why do we need to store the float result of the temperatureSensors.getTempC(deviceAddressArray[i]); call in a char array, and then convert back by using the toFloat() method before assigning it to the JsonObject? Why we don’t simply adopt a float array, thus saving memory and power (we avoid two string conversions, other than the overhead of calling two more functions)
  2. As when storing data in the JsonObject we use constant indexes, why don’t we perform an assignment like the following: root[“broodtemperature”] = temperatureSensors.getTempC(deviceAddressArray[0]); ? This would avoid the loop in which we fill the themperatureArrayChar array, hence saving again clock cycles and power
  3. It would be great to point out within comments that pin 5 (see const int temperaturePin = 5;) corresponds to physical pin D1 in ESP8266 MCUs

P.S. I also received the WeMos D1 pro, other than the load cell, the Bosch BME280 and the DHT sensors. I will try to test them as soon as possible.


Dear Giuseppe,

thanks for your response, please do not apologise. Your observations regarding the unnecessary data format conversion are absolutely right in the context of this basic firmware. They stem from the procedure @clemens has taken with node-gprs-http.ino, because he serialized the telemetry data into a HTTP GET string, there’s no JSON serialization in sight yet.

Because the node-wifi-mqtt.ino firmware was derived from that, this hangover is still in place. As said, you are absolutely right: We should mitigate this!

Are you capable of doing it on your own and contribute the result back to our repository or would you like to have us churn out the required changes at first?


Well I will try to make it! :-) Thanks!

I will try to submit a very much stripped down version based on your ideas in a few minutes, where you can build upon. I will completely strip away the getTemperature() and getHumidityTemperature() functions, thus mitigating this layer of abstraction to make the “basic” firmware really basic.

By doing this, sensor reading and telemetry will be more directly coupled. Everyone aiming at more complex scenarios should continue looking at the other firmwares provided by our repository.

I don’t know if it’s actually good to mitigate these two functions completely, as they encapsulate the intrinsic details required for reading the sensors. So let’s keep them but convert the data structures for holding the values from char to float.

Dear Giuseppe and @Thias ,

please have a look at the improved version of node-wifi-mqtt.ino. We followed your suggestions and mitigated the use of character arrays for collecting sensor values. On top, we added some more configuration capabilities to enable/disable sensors conditionally following a (hopefully) sensible naming scheme ("SENSOR_HX711", “SENSOR_DHTxx” and “SENSOR_DS18B20”).

We also streamlined the overall structure to serve educational purposes better. In this regard, there’s now also a section running a dummy sensor to assist people getting started on the telemetry side without any sensor hardware in place ("SENSOR_DUMMY").

Please be aware this has not been tested on real hardware. We are happy to hear back from you whether this actually works :-).


1 Like

Thanks! After reducing the number of DHT22 (not DHT33) and DS18B20 devices to one each and commenting out the variable <- array assignment in the loop it ran almost out of the box. Very nice!

Thanks for your feedback! We just reduced the default number of devices to one (1) to make it even easier for everyone getting started with this. Besides that, we tried to improve on the “naming things” side. Would you give the new vanilla version another try on your device to reassure nothing went wrong?

Thanks in advance!

Excellent. Since I already adapted the previous version to my setup I manually migrated the changes and it all works. I’m also read battery level and make use of ESP8266WiFiMulti to avoid changing the WiFi setup every time I switch locations. Not a big deal.
I’ll share my sketch here soon:

@Andreas and @Thias , thanks for such a great work!

Sounds good! Feel free to share the code right here in this topic and maybe report about your major improvements in the main topic. Then we can discuss further details here and will not pollute the main topic with too much technical details when sorting things out.

People will stumble across the code as both topics are interlinked and we will also update the code in the git repository with your changes, if you don’t mind. If you already have an account on GitHub, feel free to fork the repository there and feed back the improvements in form of a pull request. There’s no magic behind that and we are happy to help to get you started on this, as @mois is currently doing the same, see also Add firmware for Mois Box.

We are looking forward to your contributions!

Ich habe mittlerweile einigen Fortschritt gemacht und mir eurer Hilfe eine halbwegs individuelle Firmware zusammengefrickelt auf Basis von node-wifi-mqtt-basic. Siehe unten.

Zur Zeit tracke ich den Verlauf der Batterieladung ohne externe Stromversorgung. Mich interessiert dabei, ob sich die Trennung der WLAN-Verbindung nach der Datenübertragung signifikant lohnend auf die Betriebsdauer auswirkt. Den Call für den Verbindungsaufbau habe ich deshalb in loop() verschoben.

ESP8266WiFiMulti scheint auch zuverlässig zu funktionieren. Das spart mir die Umkonfiguration bei einem Standortwechel (Couch <-> Bienenstand). Für weitere Ideen zum Energiesparen bin ich auf Empfang. Für die tollen Entwicklungen hier sowieso.


  Hiveeyes node-wifi-mqtt

  Collect beehive sensor data and transmit via WiFi to a MQTT broker.

  Copyright (C) 2016-2017  The Hiveeyes Developers <>

  2016-05-18 Initial version
  2016-10-31 Beta release
  2017-01-09 Add more sensors
  2017-02-01 Serialize sensor readings en bloc using JSON
  2017-03-31 Fix JSON serialization: Transmit sensor readings as float values. Thanks, Matthias and Giuseppe!
  2017-04-05 Improve efficiency and flexibility

  GNU GPL v3 License
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, see:
  or write to the Free Software Foundation,
  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA


  Hiveeyes node sketch for Arduino based platforms. Here: ESP8266.

  This is a Arduino sketch for the Hiveeyes beehive monitoring system.
  The purpose is to collect vital data and to send it via WiFi to
  the MQTT bus at

  This code is derived from the Adafruit ESP8266 MCU demo sketch,
  see below.

  Feel free to adapt this code to your own needs. Contributions are welcome!


  Further information can be obtained at:

  The Hiveeyes Project
  System documentation
  Code repository    



  Adafruit ESP8266 Sensor Module

  Must use ESP8266 Arduino from:
  Works great with Adafruit's Huzzah ESP board:
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!
  Written by Tony DiCola for Adafruit Industries.
  MIT license, all text above must be included in any redistribution

// =====================
// General configuration
// =====================

// Measure and transmit each five minutes
#define MEASUREMENT_INTERVAL    10 * 60 * 1000

// ==========================
// Connectivity configuration
// ==========================

// ----
// WiFi
// ----
#define SSID_2 "Freifunk-Potsdam-254-11"
#define PW_2 ""
#define SSID_3 "machBar@Freifunk-Potsdam"
#define PW_3 ""
#define SSID_4 "freiLand@Freifunk-Potsdam"
#define PW_4 ""

// ----
// ----

// The address of the MQTT broker to connect to.
#define MQTT_BROKER     ""
#define MQTT_PORT       1883

// A MQTT client ID, which should be unique across multiple devices for a user.
// Maybe use your MQTT_USERNAME and the date and time the sketch was compiled
// or just use an UUID ( or other random value.
#define MQTT_CLIENT_ID  ""

// The credentials to authenticate with the MQTT broker.
#define MQTT_USERNAME   ""
#define MQTT_PASSWORD   ""

// The MQTT topic to transmit sensor readings to.
// Note that the "testdrive" channel is not authenticated and can be used anonymously.
// To publish to a protected data channel owned by you, please ask for appropriate
// credentials at or
#define MQTT_TOPIC      "hiveeyes/Thias/PDM/testnode/data.json"

// ====================
// Sensor configuration
// ====================

// A dummy sensor publishing static values of "temperature", "humidity" and "weight".
// Please turn this off when working with the real sensors.
#define HAS_DUMMY_SENSOR    false

// The real sensors
#define HAS_HX711           true
#define HAS_DHTxx           true
#define HAS_DS18B20         true
#define HAS_BATTERY         true

// -------------------
// HX711: Scale sensor
// -------------------

// HX711.DOUT  - pin #14
// HX711.PD_SCK - pin #12
#define HX711_PIN_DOUT      14
#define HX711_PIN_PDSCK     12

// Define here individual values for the used load cell. This is not type specific!
// Even load cells of the same type / model have individual characteristics
// - ZeroOffset is the raw sensor value for "0 kg"
//   write down the sensor value of the scale with no load and
//   adjust it here
// - KgDivider is the raw sensor value for a 1 kg weight load
//   add a load with known weight in kg to the scale, note the
//   sesor value, calculate the value for a 1 kg load and adjust
//   it here

const long loadCellZeroOffset = -41000.0f;

// 1/2 value for single side measurement, so that 1 kg is displayed as 2 kg
//const long loadCellKgDivider  = 22053;
const long loadCellKgDivider  = 11026;

// -----------------------------
// DHTxx: Humidity / Temperature
// -----------------------------

// Number of DHTxx devices connected
const int dht_device_count = 1;

// DHTxx device pins: Pin 2, Pin 4
const int dht_pins[dht_device_count] = {4};

// For more DHTxx devices, configure their pins like...
// DHTxx device pins: Pin 2, Pin 4
//const int dht_pins[dht_device_count] = {2,4};

// --------------------------
// DS18B20: Temperature array
// --------------------------

// Number of temperature devices on the 1-Wire bus
const int ds18b20_device_count = 1;

// Order of the physical array of temperature devices,
// the order is normally defined by the device id hardcoded in
// the device.
// You can physically arrange the DS18B20 in case you
// know the ID and use here {1,2,3,4 ...} or you can try out what
// sensor is on which position and adjust it here accordingly.
const int ds18b20_device_order[ds18b20_device_count] = {0};

// For more DS18B20 devices, configure them like...
//const int ds18b20_device_order[ds18b20_device_count] = {0,1};

// Resolution for all devices (9, 10, 11 or 12 bits)
const int ds18b20_precision = 12;

// 1-Wire pin for the temperature sensors
const int ds18b20_onewire_pin = 5;

// =========
// Libraries
// =========

// ------------
// Connectivity
// ------------

// ESP8266:
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>

// JSON serializer
#include <ArduinoJson.h>

// Adafruit MQTT
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"

// -------
// Sensors
// -------

#if HAS_HX711
#include "HX711.h"
HX711 hx711_sensor;  // create HX711 object

// Intermediate data structure for reading the sensor values
float weight;


// DHTxx sensor
#if HAS_DHTxx
#include <dht.h>

// Create DHT object
dht dht_sensor;

// Intermediate data structure for reading the sensor values
float dht_temperature[dht_device_count];
float dht_humidity[dht_device_count];


// DS18B20 sensor
#if HAS_DS18B20
// 1-Wire library
#include <OneWire.h>

// DS18B20/DallasTemperature library
#include <DallasTemperature.h>

// For communicating with any 1-Wire device (not just DS18B20)
OneWire oneWire(ds18b20_onewire_pin);

// Initialize DallasTemperature library with reference to 1-Wire object
DallasTemperature ds18b20_sensor(&oneWire);

// Arrays for device addresses
uint8_t ds18b20_addresses[ds18b20_device_count][8];

// Intermediate data structure for reading the sensor values
float ds18b20_temperature[ds18b20_device_count];


// Battery read
int battery_level;

// ===============
// Telemetry setup
// ===============

// Functions
void mqtt_connect();
void startWifi();

// Create an ESP8266 WiFiClient class to connect to the MQTT server.
WiFiClient client;
ESP8266WiFiMulti wifiMulti;

// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.

// Setup MQTT publishing handler
Adafruit_MQTT_Publish mqtt_publisher = Adafruit_MQTT_Publish(&mqtt, MQTT_TOPIC);

// ============
// Main program
// ============

void setup() {

  // Setup scale
#if HAS_HX711
  hx711_sensor.begin(HX711_PIN_DOUT, HX711_PIN_PDSCK);

  // These values are obtained by calibrating the scale with known weights; see the README for details

  //  hx711_sensor.tare();             // reset the scale to 0

  // temperature array
#if HAS_DS18B20

  ds18b20_sensor.begin();  // start DallasTemperature library
  ds18b20_sensor.setResolution(ds18b20_precision);  // set resolution of all devices

  // Assign address manually. The addresses below will need to be changed
  // to valid device addresses on your bus. Device addresses can be retrieved
  // by using either or individually via
  // ds18b20_sensor.getAddress(deviceAddress, index)
  //insideThermometer    = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 };
  //outsideThermometer   = { 0x28, 0x3F, 0x1C, 0x31, 0x2, 0x0, 0x0, 0x2 };

  // Search for devices on the bus and assign based on an index. Ideally,
  // you would do this to initially discover addresses on the bus and then
  // use those addresses and manually assign them (see above) once you know
  // the devices on your bus (and assuming they don't change).
  // method 1: by index
  // change index to order divices as in nature
  // (an other approach can be to order physical devices ascending to device address on cable)

  for (int i=0; i<ds18b20_device_count; i++) {
    if (!ds18b20_sensor.getAddress(ds18b20_addresses[ds18b20_device_order[i]], i)) {
      Serial.print(F("Unable to find address for temperature array device "));

  // method 2: search()
  // search() looks for the next device. Returns 1 if a new address has been
  // returned. A zero might mean that the bus is shorted, there are no devices,
  // or you have already retrieved all of them. It might be a good idea to
  // check the CRC to make sure you didn't get garbage. The order is
  // deterministic. You will always get the same devices in the same order
  // Must be called before search()
  // assigns the first address found to insideThermometer
  //if (! Serial.println("Unable to find address for insideThermometer");
  // assigns the seconds address found to outsideThermometer
  //if (! Serial.println("Unable to find address for outsideThermometer");



// temperature array / DS18B20
void getTemperature() {

#if HAS_DS18B20

  // request temperature on all devices on the bus
  ds18b20_sensor.setWaitForConversion(false);  // makes it async
  // initiatie temperature retrieval

  // wait at least 750 ms for conversion

  // Iterate all DS18B20 devices and read temperature values
  for (int i=0; i<ds18b20_device_count; i++) {
    float temperatureC = ds18b20_sensor.getTempC(ds18b20_addresses[i]);
    ds18b20_temperature[i] = temperatureC;



// humidity and temperature, DHTxx
void getHumidityTemperature() {

#if HAS_DHTxx

  // read humidity and temperature data
  // loop through all devices
  for (int i=0; i<dht_device_count; i++) {
    // read device
    int chk = dht_sensor.read33(dht_pins[i]);

    switch (chk) {
      // this is the normal case, all is working smoothly
    case DHTLIB_OK:
      dht_temperature[i]  = dht_sensor.temperature;
      dht_humidity[i]     = dht_sensor.humidity;

      // following are error cases
      Serial.println("Checksum error");

      Serial.println("Time out error");

      Serial.println("Unknown error");

  // we do other time consuming things after reading DHTxx, so we can skip this
  //  delay(1000);



void getWeight() {

#if HAS_HX711

  weight = hx711_sensor.get_units(5);

  // Debugging
  // Serial.println(weight);

  // Aftermath
  hx711_sensor.power_down();              // put the ADC in sleep mode



void getBatteryLevel() {

  // read the battery level from the ESP8266 analog in pin.
  // analog read level is 10 bit 0-1023 (0V-1V).
  // our 1M & 220K voltage divider takes the max
  // lipo value of 4.2V and drops it to 0.758V max.
  // this means our min analog read value should be 580 (3.14V)
  // and the max analog read value should be 774 (4.2V).
  int adc_level = analogRead(A0);
  Serial.print("ADC Level: "); Serial.println(adc_level);

  // convert battery level to percent
  battery_level = map(adc_level, 535, 759, 0, 100);
  Serial.print("Battery level: "); Serial.print(battery_level); Serial.println("%");


void loop() {


  // Grab the current state of the sensor
  //  int humidity_data = (int)dht.readHumidity();
  //  int temperature_data = (int)dht.readTemperature();

  // note: only for a single DS18B20 on the bus!!
  // must be rewritten for more DS18B20

  // output humidity and temperature, DHTxx
  Serial.println(F("Read weight"));
  Serial.println(F("Read temp"));
  Serial.println(F("Read hum temp"));

  Serial.println(F("Read Battery Level"));

  // Build JSON object containing sensor readings
  StaticJsonBuffer<512> jsonBuffer;

  // Create telemetry payload by mapping sensor readings to telemetry field names
  // Note: For more advanced use cases, please have a look at the TerkinData C++ library
  JsonObject& root = jsonBuffer.createObject();

#if HAS_HX711
  root["weight"]                      = weight;

#if HAS_DHTxx
  root["airtemperature"]              = dht_temperature[0];
  root["airhumidity"]                 = dht_humidity[0];
  if (dht_device_count >= 2) {
    root["airtemperature_outside"]  = dht_temperature[1];
    root["airhumidity_outside"]     = dht_humidity[1];

#if HAS_DS18B20
  root["entrytemperature"]            = ds18b20_temperature[0];
  if (ds18b20_device_count >= 2) {
    root["broodtemperature"]        = ds18b20_temperature[1];

  root["temperature"]                 = 42.42f;
  root["humidity"]                    = 84.84f;
  root["weight"]                      = 33.33f;

  root["battery_level"]               = battery_level;

  // Debugging

  // Serialize data
  int json_length = root.measureLength();
  char payload[json_length+1];
  root.printTo(payload, sizeof(payload));

  // Publish data
  if (mqtt_publisher.publish(payload)) {
    Serial.println(F("MQTT publish succeeded"));
  } else {
    Serial.println(F("MQTT publish failed"));

  Serial.println(F("Disconnecting Wifi"));
  // Wait for the next measurement interval


// Connect to MQTT
void mqtt_connect() {

  if (mqtt.connected()) {
    Serial.println(F("Already connected to MQTT"));

  Serial.println(F("Connecting to MQTT..."));
  int8_t ret;

  uint8_t retries = 3;
  while ((ret = mqtt.connect()) != 0) {

    Serial.println("Retrying MQTT connect in 5 seconds...");

    if (retries == 0) {
      Serial.println(F("Could not connect to MQTT, dying!"));

  Serial.println(F("Connected to MQTT!"));

void startWifi() {

  Serial.println(); Serial.println();
  Serial.print("Connecting to Wifi");

  // remove/add entries as needed
  wifiMulti.addAP(SSID_1, PW_1);
  wifiMulti.addAP(SSID_2, PW_2);
  wifiMulti.addAP(SSID_3, PW_3);
  wifiMulti.addAP(SSID_4, PW_4);

  while ( != WL_CONNECTED) {

  Serial.println("WiFi connected");
  Serial.println("IP address: ");

Hi Matthias,

vielen Dank für Deine Verbesserungen. Wir pflegen sie gerne in die kanonische “Basic” Firmware ein, wenn Du nichts dagegen hast.

Diesem Thema widmet sich @clemens bereits seit längerem intensiv, deswegen waren in dieser “Basic” Firmware solche Dinge bisher nicht vorgesehen, wir können uns aber die entsprechenden Stellen abschauen, z.B. ab hier - “go sleeping” ff. in dem Teil seiner Firmware, die für den ESP8266 vorgesehen ist:

Fein, vielen Dank an dieser Stelle für “startWifi” in Zusammenhang mit “ESP8266WiFiMulti”, @clemens hatte das auch bereits erschlossen. Diesbzgl. hatte ich per “wifi_ensure_connection()” bereits einen entsprechenden Vorstoß gewagt, den ursprünglichen Code besser zu modularisieren:

Da wir uns anhand der “Basic” Firmware gerade so viel Mühe geben, den Code ordentlich zu modularisieren, fließen Teile davon vielleicht zukünftig auch wieder in @clemens’ “Advanced” Firmware zurück. Danke!

Viele Grüße,

tue dir keinen Zwang an :)

WiFi.disconnect() ist wohl keine so gute Idee. Die Datenübertragung wird damit unzuverlässig im nächsten Loop. Obwohl die Meldung MQTT publish succeeded kommt, erreicht kein Datenpaket den MQTT Broker. Ich werde mich wohl mit den Sleep-Funktionen auseinandersetzen müssen, bzw ein paar Beispiele aus dem Netz zur Anwendung bringen.

Hi there,

node-wifi-mqtt-basic again was improved a lot. We tried our best to incorporate the contributions and suggestions from @Thias and @gtuveri, thanks a bunch again! At a glance:

  • Enable connecting to multiple WiFi access points with multiple attempts, see “WIFI_SSID_X” and “WIFI_SSID_X” as well as “WIFI_RETRY_COUNT”, “WIFI_RETRY_DELAY”, “MQTT_RETRY_COUNT” and “MQTT_RETRY_DELAY”.
  • Read and transmit battery level, see “SENSOR_BATTERY_LEVEL”.
  • Read and transmit free heap memory, see “SENSOR_MEMORY_FREE”.
  • Add deep sleep mode, see “DEEPSLEEP_ENABLED”.
  • Improve overall configurability and documentation.

We are looking forward to keep up the good flow of ping pong between both of you and us and hope the recent changes didn’t break anything again.

With kind regards,

P.S.: After things have settled a bit, we are planning to use the TerkinData and TerkinTelemetry libraries in another variant of this firmware to let the hopefully well established data collection and telemetry routines converge into them. This could help @clemensrefactored node-gprs-http firmware gaining more flexibility - a thing we are aiming at since weeks ;].

1 Like

Hi Andreas, yes, here we are :-)
This morning I tested the updated code including multiple access point support and selectable sensors. I found two small issues (the IP should be printed by calling WiFi class, as the current code prints and maybe it would be better to use elsif, when dealing with individual sensor activation, in order to better select the code branches if no sensors are present. I will try to make my commit proposal asap!
I also expect to test soon the DHT and HX711 peripherals, thus I will move to radio nodes testing.



I found two small issues… I will try to make my commit proposal asap!

Cool, thanks!

(the IP should be printed by calling WiFi class, as the current code prints


and maybe it would be better to use elsif, when dealing with individual sensor activation, in order to better select the code branches if no sensors are present.

Not sure about that, let me see what you are aiming at.

If you get the chance, i would be interested if “DEEPSLEEP_ENABLED” actually works… ;] We believe @Thias as well!

See you,

Well, I was thinking it makes no sense to add #if SENSOR* stuff if SENSOR_DUMMY is true, but in fact also I’m not sure about that :-)

Finally, I was thinking about why to proceed within execution if no WiFi connection has been estabilished,


That’s true!

Also true!

@Thias: If you could confirm the current version of the firmware is also working at your place, i’m inclined to merge the current state to the master branch and continue iterating on more improvements there. Thanks!

I’ll try to get a time slot for testing this evening

1 Like