Works with the Cayenne Dashboard - ESP-Now temperature sensor device (part 7)

Now to round off this series a simple inexpensive device based on ESP8266 with one or two DS18B20 Sensors. Since the device is only active every 5 minutes for a few milliseconds, it can be operated very well with batteries. The battery on the image is symbolic. If you use the +5V pin of the D1-Mini to use the built-in voltage regulator to 3.3 V, you need at least 3 batteries with 1.5 V each.

Attention! The orange wire connection is used to wake you out of sleep mode and must be removed for flashing.

Now the code:

For the final version you want to run with battery, the DEBUG flag should be set to false.


 Wi-Fi temperature sensor
 ESP Now to mqTT gateway
 If no MAC address has yet been determined
 the sensor is looking for a WLAN with SSID MQTTGateway
 When he finds the AP, he remembers the MAC address 
 as long as the power supply has not been interrupted
 The ESP Now protocol is very fast so only very short time (us)
 higher current flows. The sensor sends temperature data and then goes into the 
 deep sleep so that very little energy is consumed and the
 sensor can therefore be operated with batteries. 

Library for WiFi
#include <ESP8266WiFi.H>
Libraries for temperature sensor DS18B20
#include <OneWire.H>
#include <DallasTemperature.H>
#include <CayenneLPP.H>

Library for ESP Now
External "C" {   #include <espnow.H>

SSID of the gateway
#define GW_SSID "MQTTGateway"

Debug flag if false all debug messages are suppressed
to save additional power
#define Debug True

Constants for WiFi
#define SEND_TIMEOUT 2000  2 seconds timeout 

Channel mapping

Pins for temperature sensors
Const Byte bus_int = 2; GPIO2
Const Byte bus_ext = 4; GPIO4

Data structure for the Rtc Memory with checksum around the validity
to check this the MAC address is saved
Struct MEMORYDATA {   uint32_t crc32;   uint8_t Mac[6];   uint32_t Channel;

Global data
volatile Bool callbackCalled;

Memory for temperature values
Float temp_int = 0;
Float temp_ext = 0;
Boolean has_int = 0;
Boolean has_ext = 0;

MAC address and Wi-Fi channel
MEMORYDATA statinfo;
buffer for data in LPP format
CayenneLPP lpp(64);

Bus to the sensors
OneWire oneWire_int(bus_int);
OneWire oneWire_ext(bus_ext);

DallasTemperature sensoren_int(&oneWire_int);
DallasTemperature sensoren_ext(&oneWire_ext);

Array to store sensor addresses
DeviceAddress adressen_int;
DeviceAddress adressen_ext;

Subprogram for calculating the checksum
uint32_t calculateCRC32(Const uint8_t *Data, Size_t length)
{   uint32_t Crc = 0xffffffff;   while (length--) {     uint8_t C = *Data++;     for (uint32_t  = 0x80;  > 0;  >>= 1) {       Bool Bit = Crc & 0x80000000;       If (C & ) {         Bit = !Bit;       }       Crc <<= 1;       If (Bit) {         Crc ^= 0x04c11db7;       }     }   }   Return Crc;

Writes the data structure statinfo with correct checksum to the RTC memory
Void UpdateRtcMemory() {     uint32_t crcOfData = calculateCRC32(((uint8_t*) &statinfo) + 4, Sizeof(statinfo) - 4);     statinfo.crc32 = crcOfData;     Esp.rtcUserMemoryWrite(0,(uint32_t*) &statinfo, Sizeof(statinfo));

searches for a suitable AccessPoint
Void ScanForSlave() {   Bool slaveFound = 0;      int8_t scanResults = Wifi.scanNetworks();   reset on each scan   If (Debug) Serial.println("Scan done");   If (scanResults == 0) {     If (Debug) Serial.println("No WiFi devices found in AP Mode");   } else {     If (Debug) Serial.Print("Found");      If (Debug) Serial.Print(scanResults);      If (Debug) Serial.println(" devices ");     for (Int  = 0;  < scanResults; ++) {       Print SSID and RSSI for each device found       String Ssid = Wifi.Ssid();       int32_t Rssi = Wifi.Rssi();       int32_t Chl = Wifi.Channel();       String BSSIDstr = Wifi.BSSIDstr();       If (Debug) {         Serial.Print( + 1);         Serial.Print(": ");         Serial.Print(Ssid);         Serial.Print(" /");         Serial.Print(Chl);         Serial.Print(" (");         Serial.Print(Rssi);         Serial.Print(")");         Serial.println("");       }       Delay(10);       Check if the current device starts with 'Thermometer'       If (Ssid == GW_SSID) {         SSID of interest         If (Debug) {           Serial.println("Found a Slave.");           Serial.Print( + 1); Serial.Print(": "); Serial.Print(Ssid); Serial.Print(" ["); Serial.Print(BSSIDstr); Serial.Print("]"); Serial.Print(" ("); Serial.Print(Rssi); Serial.Print(")"); Serial.println("");         }         Int Mac[6];         we determine the MAC address and store it in the RTC memory         If ( 6 == sscanf(BSSIDstr.c_str(), "%x:%x:%x:%x:%x:%x%c",  &Mac[0], &Mac[1], &Mac[2], &Mac[3], &Mac[4], &Mac[5] ) ) {           for (Int  = 0;  < 6; ++ ) {             statinfo.Mac[] = (uint8_t) Mac[];           }           statinfo.Channel = Chl;           UpdateRtcMemory();         }         slaveFound = 1;         After the AP is found, we can cancel         Break;       }     }   }         If (Debug) {     If (slaveFound) {       Serial.println("Slave Found, processing.".);     } else {       Serial.println("Slave Not Found, try again.");     }   }   Share RAM   Wifi.scanDelete();
function to print a sensor address
Void printAddress(DeviceAddress Addresses)
{   for (uint8_t  = 0;  < 8; ++)   {     If (Addresses[] < 16) Serial.Print("0");     Serial.Print(Addresses[], Hex);   }

Subprogram for initializing the DS18B20 sensors
Boolean initDS18B20(uint8_t Pin, DallasTemperature Sensor, DeviceAddress address ) {   Boolean Found = 0;   pinMode(Pin,INPUT_PULLUP);   sensoren_int.Begin();   If (Debug) {     Serial.Print(Sensor.getDeviceCount(), DEC);     Serial.println(" Sensors found.");   }   Now we check if one of the sensors on the bus is a temperature sensor   If (!Sensor.getAddress(address,0)) {     If (Debug) Serial.println("No temperature sensor available!");   } else {      View addresses     If (Debug) {       Serial.Print("Address: ");       printAddress(address);       Serial.println();     }     Now we set the desired resolution (9, 10, 11 or 12 bit)     Sensor.setResolution(address,10);     For control, we read the value again     If (Debug) {       Serial.Print("Resolution = ");       Serial.Print(Sensor.getResolution(address), DEC);       Serial.println();     }     Start temperature measurement     Sensor.requestTemperatures(); Commando to read the temperatures     Found = 1;   }   Return Found;

Void Setup() {   uint8_t Buf[70]; sendebuffer   If (Debug) {     Serial.Begin(115200);      Serial.println("Start");   }   determine your own MAC address and store it as a device ID in the transmit tinge memory   String strmac = Wifi.macAddress();   If (Debug) {     Serial.Print("My MAC address = ");     Serial.println(strmac);   }   Int Imac[6];   sscanf(strmac.c_str(), "%x:%x:%x:%x:%x:%x%c",  &Imac[0], &Imac[1], &Imac[2], &Imac[3], &Imac[4], &Imac[5] );   for (uint8_t  = 0; <6; ++) Buf[]=Imac[];   If (Debug) {     Serial.println("Internal Sensors");   }   has_int = initDS18B20(bus_int,sensoren_int,adressen_int);   If (Debug) {     Serial.println("External Sensors");   }   has_ext = initDS18B20(bus_ext,sensoren_ext,adressen_ext);   We read from the RTC Memory   Esp.rtcUserMemoryRead(0, (uint32_t*) &statinfo, Sizeof(statinfo));   If (Debug) Serial.println("RTC Done");   uint32_t crcOfData = calculateCRC32(((uint8_t*) &statinfo) + 4, Sizeof(statinfo) - 4);   Wifi.Fashion(WIFI_STA); Station mode for esp-now sensor node   If (Debug) Serial.println("WifiMode");   If (statinfo.crc32 != crcOfData) { we do not have a valid MAC address     If (Debug) Serial.println("Scan before Slave");     ScanForSlave();     for (uint8_t i = 0; i<6;i++) statinfo.mac[i] = gwmac[i];     If (Debug) {       Serial.Printf("This mac: %s, ", Wifi.macAddress().c_str());        Serial.Printf("target mac: %02x%02x%02x%02x%02x%02x%02x", statinfo.Mac[0], statinfo.Mac[1], statinfo.Mac[2], statinfo.Mac[3], statinfo.Mac[4], statinfo.Mac[5]);        Serial.Printf(", channel: %i'n", statinfo.Channel);      }   }   If (esp_now_init() != 0) {     If (Debug) Serial.println("*** ESP_Now init failed");     Esp.restart();   }   ESP Now Controller   Wifi.setAutoConnect(False);   esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);   uint8_t Ch = esp_now_get_peer_channel(statinfo.Mac);   Serial.Printf("Channel = %i'r"n",Ch);   Initialize peer data   Int Res = esp_now_add_peer(statinfo.Mac, ESP_NOW_ROLE_CONTROLLER, 1, Null, 0);   If (Res==0) Serial.println("Successfully paired");   we register the function to be called after sending   esp_now_register_send_cb([](uint8_t* Mac, uint8_t sendStatus) {     If (Debug) {       Serial.Print("send_cb, status = "); Serial.Print(sendStatus);        Serial.Print(", to mac: ");        Char macString[50] = {0};       Sprintf(macString,"%02X:%02X:%02x:%02X:%02X:%02X", statinfo.Mac[0], statinfo.Mac[1], statinfo.Mac[2], statinfo.Mac[3], statinfo.Mac[4], statinfo.Mac[5]);       Serial.println(macString);     }     callbackCalled = True;   });      Set flag to false   callbackCalled = False;   Start temperature measurement   If (has_int) sensoren_int.requestTemperatures();   If (has_ext) sensoren_ext.requestTemperatures();   Delay(750); 750 ms wait until the measurement is ready   Get temperature value and save it in data structure for sending   If (has_int) temp_int = sensoren_int.getTempC(adressen_int);   If (has_ext) temp_ext = sensoren_ext.getTempC(adressen_ext);    Delete Buffer   lpp.Reset();   Write data packets to the buffer   If (has_int) lpp.addTemperature(CHANNEL_TEMPI, temp_int);   If (has_ext) lpp.addTemperature(CHANNEL_TEMPE, temp_ext);   uint8_t Sz = lpp.getSize();   Copy data structure to send buffer   Memcpy(&Buf[6], lpp.Getbuffer(), Sz);   Send data to thermometer   esp_now_send(Null, Buf, Sz+6); NULL means send to all peers   If (Debug) {     Serial.Print("Internal Temperature: "); Serial.Print(temp_int); Serial.println("°C");     Serial.Print("External Temperature: "); Serial.Print(temp_ext); Serial.println("°C");   }

Void Loop() {   wait until data is sent   If (callbackCalled || (millis() > SEND_TIMEOUT)) {     If (Debug) Serial.println("Sleep");     Delay(100);     Into deep sleep mode for 300 seconds     then a reset takes place and the ESP8266 is restarted     Data in the RTC memory is not deleted during the reset.     Esp.deepSleep(300E6);   }

After the device is started, we should see it on the gateway's web page.

We can give the device a name and register it.

The device has received the device number 1 therefore channels 8 to 15. Channel 1 of the device is therefore channel 9. After a short time, we should see the two new channels (or only one if only one temperature sensor has been connected) in the Cayenne Dashboard.

Now you can add the two widgets for channel 9 and channel 10 and customize them as desired.

Have fun replicas

Esp-8266Projects for advancedSensors

Leave a comment

All comments are moderated before being published

Recommended blog posts

  1. Install ESP32 now from the board manager
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. OTA - Over the Air - ESP programming via WLAN