Categorie: ESP32

ESP32DeltaTemp

ESP32DeltaTemp

EPS32DeltaTemp is en zelfbouwproject gebaseerd op de ESP32 van Espressif System. Dit kleine IoT apparaat is goedkoop en is relatief eenvoudig te programmeren. EP32DeltaTemp is gebouwd om in en uitgaande temperatuur te meten van vloerverwarming maar kan in principe voor elke toepassing worden gebruikt waar je de temperatuur wil meten. De centrale verwarming, de kamertemperatuur, enz.

Eigenschappen

Meet de temperatuur via twee digitale sensoren en geeft deze weer op het display van de ESP32, je kunt ook een ESP32 gebruiken zonder display.  Het display kan via een aanraaktoets  worden gewisseld tussen:

  1. De ingaande en uitgaande temperatuur met een grafiek die een indicatie geeft van het verschil tussen de twee temperaturen of de wifiverbinding actief is en wanneer de temperatuur wordt uitgelezen. De temperatuur wordt met een interval van 1 seconden gemeten.
  2. Het verschilscherm geef het verschil weer tussen de twee temperaturen en wanneer de meting plaats vindt.
  3. Info scherm: geeft de softwareversie weer, de gebruikt Service Set Identifier SSID (de naam van Wifi-netwerk) en het IP-adres dat de Eps32DeltTemp gebruikt.
  4. Tot slot: het scherm gaat automatisch uit na ongeveer 60 seconden. Het Heltec schermpje wordt snel slechter als dit altijd aan staat.

De informatie wordt optioneel verzonden via wifi UDP-berichten die door elke ander applicatie/programma gelezen kan worden op het lokale netwerk. Het Wifi IP-adres wordt via DHCP opgehaald iets wat de meeste thuisrouters standaard doen.

Benodigde hardware

De lijst die ik hier geef werkt en ik heb geen relatie met de genoemde leveranciers.
• 1 x Heltec EPS32 met oled display (10,55): link
• 2 x DS18B20 digitale temperatuur sensor (~€ 1,00): link
• 1 x Weerstand van 4K7: (€ 1,98) link
• Behuizing (optioneel) (€ 1,86): link
• Een USB – Naar micro usb kabel voor het programmeren en of de 5V voeding. Let er op dat de kabel spanninmg en data doorgeeft.
• Een Micro USB 5V voeding van minimaal 0.7 Ampère (mag meer zijn), een Raspberry Pi voeding is uitstekend. (Ongeveer € 4)
• Experimenteer print, een paar euro bijvoorbeeld link ( ongeveer € 7).
• Iets wat als tiptoets knop kan werken. Ik gebruik een 4mm schroefje.
Totaal ongeveer: € 30 euro afhankelijk van je voorkeur.
Uiteraard een soldeerbout, soldeertin en e.d. om de boel in elkaar te zetten.

Aansluitschema

ESP32 aansluitschema

Tip 5v aansluiting

Bij eerder Heltec Wifi Kit32 modules bevatte deze een 5v naar 3.3V spanningsregelaar die als je 5Volt op de pin (2) 5V zette dan werd dat omgezet naar 3.3V op de pin (3) ernaast.  Bij een recent module die ik gebruikte werkte dat niet meer waardoor er 5V op de 3.3V pin kwam te staan.  Je ziet op de module ook dat er minder spanningsregelaars op de module zijn geplaats. Het effect is dat de temperatuursensor s daar niet mee werken, die verwachten 3.3V. Bij deze module wordt de 5V op de Micro UBS connector wel omgezet naar 3.3V.  Als je alleen de micro-usb gebruikt dan zal je dit probleem niet optreden.

Benodigde software.

De ESP32 is eenvoudig te programmeren via de Arduino IDE als je deze nog niet hebt geïnstalleerd volg dan deze handleiding van  randomnerdtutorials.com. Deze handleiding legt tevens uit hoe je de ESP32  uitbreiding moet toevoegen die zijn standaard niet geïnstalleerd.  

De code maakt gebruik van een extra softwarebibliotheken die eenvoudig via de Arduino IDE te installeren zijn.  Deze kun je via de IDE  Sketch -> Include Libary -> Manage Libraries toevoegen.

  • OneWire
  • U8G2
  • DallasTemperature

Laad onderstaande code in de editor en pas eventueel de WIFI instellingen aan als je daar gebruik van wil maken en compileer deze door linksboven op verify te klikken.  Als dat goed gaat kun je de ESP32 aansluiten via de USB-kabel en de code uploaden naar de ESP32.   Om de code te kunnen testen moeten wel de temperatuur sensors worden aangesloten.

Wijzigingen van versie 1.0 naar versie 1.1

1: Versie nummer verhoogd naar v1.1
2: Meer debug/logging informatie toegevoegd voor de seriële monitor.
3: Debug meldingen naar het Engels omgezet.
4: Mogelijk bug met screen dim voorkomen door overflow.
5: Tijd van dimmen scherm naar ongeveer 1 minuut terug gebracht om het scherm te beschermen.
6: Gemiddelde waarde berekening aangepast om piek en dalen in de meting te onderdrukken en de code efficiënter gemaakt.
7: Controle automatische opnieuw de wifi verbinding opbouwen. Bij het wegvallen van de wiffi verbinding probeert de software een nieuw verbinding op te zetten.
8: Door DEBUG beter in te zetten is de runtime code ongeveer 3k bytes kleiner geworden. Markeer de DBUG code met // voor het compileren van de definitieve versie.
9: Voorloop nullen bug/feature opgelost in de JSON output in het UDP bericht. Met dank aan Siem.
10: JSON/UDP output aangepast: gemiddelde waarde bevat 1 decimaal en ruwe waarde twee decimalen.
11: Verschil scherm laat nu het absolute verschil zien zonder min teken.
12: De led op het board knippert elke keer als dat er geprobeerd wordt een UDP bericht te verzenden.
13: Bij het starten van de software gaat de led op board aan. aAs de WiFi werkt en de temperatuur sensors zijn gevonden dan gaat de led weer uit. Zie 12.

#include <U8g2lib.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <WiFi.h>
#include <WiFiUdp.h>

/* note, the bat(tery) led rapid blinking is a hardware "feature" of the heltec board and can not be disabled by software */

/* user setting, change these to your needs. */
/*********************************************/
/* leave SSID empty if you don't need the UDP / WIFI messages *ssid = "" */
const char *ssid = "";          // your SSID.
const char *pwd  = "";         // your WPA WIFI password.

// board specific 
#define TOUCH_PIN T7       // connected to pin 27
#define ONE_WIRE_BUS 13    // DS18B20 on GPIO 13.
#define ONBOARD_LED  25    // ESP32 board specific led
/* end of user setting,                      */
/*********************************************/

const uint8_t udp_send_interval = 45;      // interval when an udp message will be send in 0.1 secs interval 45 = ~5 secs.
                                          // use a value between 1 and a maximum of 255.

const float temp_in_adjustmend  =  0.55;  // test en adjust these to values to compensate for differences
const float temp_out_adjustmend =  1.39;  // in the readout of the temp sensors and general offset error.

/***************** end of user settings ******/

//#define DEBUG 1                         // used during development to give more verbose output to 
                                        // the serial output place '//' before the line to deactivate

#define STR_BUF_SIZE 32
#define VERSION             "1.1"         // Software version.
#define TEMPERATURE_PRECISION 12          // set temp precision (9-12).
#define DISPLAY_WIDTH 128
#define DISPLAY_HEIGHT 64
#define DIM_SCREEN 450                   // Dim screen after about a minute.

OneWire           oneWire(ONE_WIRE_BUS);  // setup OneWire devices.
DallasTemperature tempSensors(&oneWire);  // tempSensor data.
DeviceAddress     tempDeviceAddress;      // temp adress for devices.
WiFiUDP           udp;                    // UDP sender.

int     numberOfDevices = 0;              // number of temperature devices found.
char    strbuf[STR_BUF_SIZE];             // buffer for display and serial print.
float   g_temp_in;
float   g_temp_out;
float   g_temp_in_avg;
float   g_temp_out_avg;
uint8_t temp_vdelta_arr_graphic[DISPLAY_WIDTH];
int     touch_value = 300;
bool    WIFIconnected = false;
//bool    onboard_led_on = true; // staus of the onboard led on or off

//U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ 16, /* clock=*/15, /* data=*/4);   // (rotation, [reset [, clock, data]])
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ 15, /* data=*/ 4, /* reset=*/ 16);

// IP address to send UDP data to.
const char *udpAddress = "255.255.255.255";  // udp broadcast address for the local lan only.
const int   udpPort    = 30721;              // udp port number to listen to as a client.

void setup() {
  
    // set led configuration
    pinMode( ONBOARD_LED, OUTPUT );
    digitalWrite( ONBOARD_LED, HIGH );  // led on to show the prg is running

    Serial.begin(115200);
    #if DEBUG
        Serial.println("Serial output started at 115200");
    #endif
    u8g2.begin();
    u8g2.clearBuffer();
    u8g2.setFont(u8g2_font_ncenB12_tf);
    u8g2.drawStr(20, 40, "ZTATZ.NL");
    u8g2.sendBuffer();
    delay( 3000 );

    // load temperature sensors.
    tempSensors.begin();

    // check if we can find the two temp sensors.
    u8g2.clearBuffer();
    while ( setTempPrecision() < 2 ) {
        tempSensors.begin();
        u8g2.drawStr(1, 12, "wacht op de");
        u8g2.drawStr(1, 26, "temperatuur");
        u8g2.drawStr(1, 40, "sensors.");
        u8g2.sendBuffer();
        delay(500);
    }

    // make sure we have some temperature values.
    readTemperatures();

    if ( String(ssid).length() > 0 ) {

        // try to connect to wifi.
        connectToWiFi(ssid, pwd);

        // Wait for connection
        for (uint8_t i = 0; i < 60; i++) {
            if (WiFi.status() == WL_CONNECTED ) {
                break; // we have a network connection
            }
            u8g2.clearBuffer();
            u8g2.drawStr(1, 12, "wacht op de");
            u8g2.drawStr(1, 27, "wifi");
            u8g2.drawStr(1, 41, "verbinding.");
            String str = "seconden: " + String( i );
            str.toCharArray(strbuf, STR_BUF_SIZE);
            u8g2.drawStr(1, 57, strbuf);
            u8g2.sendBuffer();
            delay(1000); // try every 1 secs
        }
    }
}

void loop()
{
    static uint8_t display_select_counter = 0;
    static uint16_t pseudo_secs = 0;
    static uint16_t dim_screen_secs = 0;
    static uint8_t touch_counter = 0;
    static uint8_t udp_send_counter = 0;
    static bool    wifi_retry_is_on = false;
    static bool    screen_dimmed_is_on = false;

    // pseudo timer.
    pseudo_secs++;
    dim_screen_secs++;

    //digitalWrite( ONBOARD_LED, HIGH ); 
    digitalWrite( ONBOARD_LED, LOW );  // set it show the prg ready with setup and entering the loop.

    if ( pseudo_secs > 599 ) {
        pseudo_secs = 0;  // reset secs to 0
    }

    if (dim_screen_secs > DIM_SCREEN && !screen_dimmed_is_on) {
        screen_dimmed_is_on = true;
        dim_screen_secs = 0;
        showDisplay(3);
        #ifdef DEBUG
            Serial.println("Dim Screen activated.");
        #endif
    }

    // read temperature values from sensors and update data buffers.
    // every second.
    if ( (pseudo_secs % 10 ) == 0 ) {
        readTemperatures();
        fillGraphicBufferValues();
        calcAvgTemperature( g_temp_in, g_temp_out );
        if (!screen_dimmed_is_on) {
            showDisplay(display_select_counter);
        }
    }

    // Send UDP broadcast messages.
    if ( WIFIconnected ) {
        udp_send_counter++;
        if ( udp_send_counter > udp_send_interval ) {
            digitalWrite( ONBOARD_LED, HIGH );   // onboard led flashes when a UDP message is send.
            udpSendMessage( makeJsonMessage() ); // SEND UPD message
            udp_send_counter = 0;
        }
    }

    // touch selection.
    touch_value = touchRead( TOUCH_PIN );

    if (touch_value < 50 ) {
        touch_counter++;
        if ( touch_counter > 4 ) { // must held the touch contact to filter out noise.
            touch_counter = 0;
            dim_screen_secs = 0;

            if (!screen_dimmed_is_on) {
                display_select_counter++;
            
                if ( display_select_counter > 2 ) {
                    display_select_counter = 0;        // remove blank screen option
                }
                
                showDisplay( display_select_counter ); // to get quick feedback on pressing touch "button".
                // screen_dimmed_is_on = false;
            } else {
                screen_dimmed_is_on = false;
                showDisplay(display_select_counter); // to get quick feedback on pressing touch "button".
            }
        }
    } else {
        touch_counter = 0; //reset the touch counter,
    }

    delay( 100 ); // 0.1 sec delay.
    if ( digitalRead( ONBOARD_LED ) ) { // reset the led after a short while. 
        digitalWrite( ONBOARD_LED, LOW );
    }
    
}

// function to connect to the wifi network
void connectToWiFi(const char * ssid, const char * pwd) {
    #ifdef DEBUG
        Serial.println("Connecting to the WiFi network: " + String(ssid));
    #endif

    // delete old config
    WiFi.disconnect(true);

    delay(1000);

    //register event handler
    WiFi.onEvent(WiFiEvent);

    //Initiate connection
    WiFi.begin(ssid, pwd);
}

//wifi event handler
void WiFiEvent(WiFiEvent_t event) {
    #ifdef DEBUG
        Serial.print("WiFiEvent: ");
        Serial.println(event);
    #endif
    switch (event) {
        case SYSTEM_EVENT_STA_CONNECTED:
            //When connected set
            #ifdef DEBUG
                Serial.println( "WiFi connected with Access point." );
            #endif
            break;
        case SYSTEM_EVENT_STA_GOT_IP:
            //When connected set
            #ifdef DEBUG
                Serial.print( "Wi-Fi connected! IP address: " );
                Serial.println( WiFi.localIP() );
            #endif
            //initializes the UDP state
            //This initializes the transfer buffer
            udp.begin(WiFi.localIP(), udpPort);
            WIFIconnected = true;
            break;
        case SYSTEM_EVENT_STA_DISCONNECTED:
            #ifdef DEBUG
                Serial.println( "Lost WiFi connection.." );
            #endif
            WIFIconnected = false;
            WiFi.disconnect(true);
            WiFi.begin(ssid, pwd);
            break;
    }
}

// function select display mode
void showDisplay(uint8_t index) {
  switch (index) {
    case 0:
      showTempInfo();
      break;
    case 1:
      showDeltaTempInfo();
      break;
    case 2:
      showInitInfo();
      break;
    case 3:
      // blank screen
      u8g2.clearBuffer();
      u8g2.sendBuffer();
      break;
  }
}

// function to show temperature on display.
void showDeltaTempInfo() {
    static bool temp_icon;

    floatTempFormater( abs(g_temp_in_avg - g_temp_out_avg) ).toCharArray(strbuf, STR_BUF_SIZE);

    #ifdef DEBUG
        Serial.println ( String("showDeltaTempInfo() delta temperature = ") + strbuf );
    #endif 

    u8g2.clearBuffer();
    u8g2.setFont(u8g2_font_fub30_tf);
    u8g2.drawStr(   5,  35, strbuf);
    u8g2.drawGlyph( 85, 35, 176 );
    u8g2.drawStr(   95, 35, "C" );

    u8g2.setFont(u8g2_font_ncenB18_tf);
    u8g2.drawStr( 8, 60, "verschil" );

    // activity icon toggle.
    u8g2.setFont(u8g2_font_open_iconic_gui_2x_t);
    if (temp_icon == true ) {
        u8g2.drawGlyph(112, 60, 66);
        temp_icon = false;
    } else {
        u8g2.drawGlyph(112, 60, 67);
        temp_icon = true;
    }

    u8g2.sendBuffer();
}

void showInitInfo() {
    u8g2.clearBuffer();
    u8g2.setFont(u8g2_font_courB10_tf);
    
    String str = "Version " + String(VERSION);
    
    #ifdef DEBUG
        Serial.println ( String("ShowInitInfo() ") + str );
    #endif
    
    str.toCharArray(strbuf, STR_BUF_SIZE);
    u8g2.drawStr(1, 15, strbuf);

    str = "SSID:" + String( ssid );
    str.toCharArray(strbuf, STR_BUF_SIZE);
    u8g2.drawStr(1, 30, strbuf);

    str = ipAddress2String( WiFi.localIP() );
    str.toCharArray(strbuf, STR_BUF_SIZE);
    u8g2.drawStr(1, 45, strbuf);

    u8g2.sendBuffer();
}

// function to show temperature on display.
void showTempInfo() {
    static bool temp_icon;

    u8g2.clearBuffer();
    u8g2.setFont(u8g2_font_ncenB18_tf);
    u8g2.drawStr(    0, 18, "in"  );
    u8g2.drawStr(    0, 40, "uit" );

    floatTempFormater(g_temp_in_avg).toCharArray(strbuf, STR_BUF_SIZE);
    u8g2.drawStr(38, 18, strbuf);

    floatTempFormater(g_temp_out_avg).toCharArray(strbuf, STR_BUF_SIZE);
    u8g2.drawStr(38, 40, strbuf);

    u8g2.setFont(u8g2_font_ncenB14_tf);
    u8g2.drawStr(   97, 16, "C" );
    u8g2.drawStr(   97, 38, "C" );
    u8g2.drawGlyph( 90, 16, 176 );
    u8g2.drawGlyph( 90, 38, 176 );

    for ( uint8_t i = 0; i < DISPLAY_WIDTH; i++ ) {
        u8g2.drawLine(i, 64, i, DISPLAY_HEIGHT - temp_vdelta_arr_graphic[i] );
    }

    // activity icon toggle.
    //u8g2.setFont(u8g2_font_siji_t_6x10);
    u8g2.setFont(u8g2_font_open_iconic_all_2x_t);
    if ( temp_icon == true ) {
        u8g2.drawGlyph(112, 20, 141);
        //u8g2.drawGlyph(111,20,57551);
        temp_icon = false;
    } else {
        //u8g2.drawGlyph(113,20,57373);
        temp_icon = true;
    }

    if ( WIFIconnected ) {
        u8g2.setFont(u8g2_font_open_iconic_all_2x_t);
        u8g2.drawGlyph( 112, 40, 247 );
        #ifdef DEBUG
            Serial.println ( String("showTempInfo() Wifi connected"));
        #endif 
    } else {
        #ifdef DEBUG
            Serial.println ( String("showTempInfo() Wifi not connected"));
        #endif 
    }

    u8g2.sendBuffer();
}

// function IPAdress conversion to string
String ipAddress2String(const IPAddress& ipAddress) {
    return String(ipAddress[0]) + String(".") + \
        String(ipAddress[1]) + String(".") + \
        String(ipAddress[2]) + String(".") + \
        String(ipAddress[3])  ;
}

// function to format json string.
String makeJsonMessage() {
    static unsigned int sequenceNumber;
    char tmpbuf[8];

    dtostrf( g_temp_in, 2, 2, tmpbuf );
    String str_tmp_in = String( tmpbuf );
    dtostrf( g_temp_out, 2, 2, tmpbuf );
    String str_tmp_out = String( tmpbuf );

    dtostrf( g_temp_in_avg, 2, 1, tmpbuf );
    String temp_in_avg = String( tmpbuf );
    dtostrf( g_temp_out_avg, 2, 1, tmpbuf );
    String temp_out_avg = String( tmpbuf );

    //{ "t_in": 23.1, "t_out":45.6, "seq":65000 }
    String msg = "{\"id\":\"ztatz_dt\",\"version\":" + String(VERSION) + ",\"t_unit\":\"C\"";
    msg = msg + ",\"t_in_avg\":" + temp_in_avg +
            ",\"t_out_avg\":"    + temp_out_avg + 
            ",\"t_in\":"         + str_tmp_in +
            ",\"t_out\":"        + str_tmp_out +
            ",\"seq\":"          + sequenceNumber +
            "}";

    sequenceNumber++;
    if ( sequenceNumber > 32768 ) {
        sequenceNumber = 0;  //wrap around to zero.
    }
    return msg;
}

// function to send the temperature via UDP
void udpSendMessage(String msg) {

    //alloc buffer space
    uint8_t bufsize = msg.length() + 1;
    uint8_t buffer[bufsize];
    msg.getBytes( buffer, bufsize );

    udp.beginPacket( udpAddress, udpPort );
    udp.write( buffer, bufsize - 1 ); //skip trailing zero.
    udp.endPacket();
}

// function to calculate the average values, based in AVG_TEMP_ARRAY_SIZE value
void calcAvgTemperature(float in, float out) {
    #define AVG_TEMP_ARRAY_SIZE 30         // takes about 3 secs to get a stable avg value. every 10 units is 1 second
    #define AVG_MAX_DELTA_FOR_REJECT 1.5  // degree Celsius.
    #define AVG_NUDGE 0.1                 // degree Celsius.

    static uint8_t sample_count = 0;
    static uint8_t temp_array_index = 0;
    static float temp_in_array[AVG_TEMP_ARRAY_SIZE];
    static float temp_out_array[AVG_TEMP_ARRAY_SIZE];
    static bool  enough_data = false; // only average values when there is enough data

    // drop values that are out of the range
    // if average buffer is true are set
    if ( enough_data == true) { 
        #ifdef DEBUG
            Serial.print("calcAvgTemperature delta(in)=");
            Serial.print( abs(g_temp_in_avg - in), DEC);
            Serial.print("avg = ");
            Serial.print( g_temp_in_avg , DEC);
            Serial.print("in = ");
            Serial.println( in, DEC);
        #endif
        if ( abs(g_temp_in_avg - in) > AVG_MAX_DELTA_FOR_REJECT ) {
            #ifdef DEBUG
                Serial.print("ERROR: temperature IN value out of expected range=");
                Serial.print( in , DEC);
                Serial.print(" avg=");
                Serial.println( g_temp_in_avg , DEC);
            #endif
            if ( in > g_temp_in_avg ) {
                in = in + AVG_NUDGE;
                #ifdef DEBUG
                    Serial.println("IN value nudged up.");
                #endif
            } else {
                in = in - AVG_NUDGE;
                 #ifdef DEBUG
                    Serial.println("IN value nudged down.");
                #endif
            }

        } // end of in value

        if ( abs(g_temp_out_avg - out) > AVG_MAX_DELTA_FOR_REJECT ) {
            #ifdef DEBUG
                Serial.print("ERROR: temperature OUT value out of expected range = ");
                Serial.print( out , DEC);
                Serial.print(" avg=");
                Serial.println( g_temp_out_avg , DEC);
            #endif
            if ( out > g_temp_out_avg ) {
                out = out + AVG_NUDGE;
                #ifdef DEBUG
                    Serial.println("OUT value nudged up.");
                #endif
            } else {
                out = out - AVG_NUDGE;
                 #ifdef DEBUG
                    Serial.println("OUT value nudged down.");
                #endif
            }

        } // end of OUT value

    } else {
        sample_count++;
    }

    // add to array to determine average value.
    // location in the array is not relevant for
    // the average calculation.
    if ( temp_array_index > AVG_TEMP_ARRAY_SIZE - 1) {
        temp_array_index = 0; // reset to start of array
    }
    temp_in_array[temp_array_index]  = in;
    temp_out_array[temp_array_index] = out;
    temp_array_index++;

    //sample_count++;
    if ( sample_count == AVG_TEMP_ARRAY_SIZE ) {
        enough_data = true;
    } else {
        // we don't have enough data so just send current non average value
        g_temp_in_avg  = in;
        g_temp_out_avg = out;
        #ifdef DEBUG
            Serial.print("Not enough data to calculate the average values, need " + String(AVG_TEMP_ARRAY_SIZE) + " sampels. sample_count=");
            Serial.println(sample_count, DEC);
        #endif
    }

    if (enough_data == true) { // ready to calc avg value
        #ifdef DEBUG
            Serial.print("Calculating the average values. sample_count=");
            Serial.println(  sample_count, DEC);
        #endif

        g_temp_in_avg = g_temp_out_avg = 0;
        for (uint8_t i = 0; i < AVG_TEMP_ARRAY_SIZE; i++) {
            g_temp_in_avg  = g_temp_in_avg  + temp_in_array[i];
            g_temp_out_avg = g_temp_out_avg + temp_out_array[i];
        }
        g_temp_in_avg  = g_temp_in_avg  / AVG_TEMP_ARRAY_SIZE;
        g_temp_out_avg = g_temp_out_avg / AVG_TEMP_ARRAY_SIZE;
    }

 
    #ifdef DEBUG
        Serial.print("IN=");
        Serial.print(in,DEC);
        Serial.print(" OUT=");
        Serial.print(out ,DEC);
        Serial.print(" delta(raw)=");
        Serial.println( floatTempFormater(out-in));
        Serial.print("g_temp_in_avg=");
        Serial.print(g_temp_in_avg,DEC);
        Serial.print(" g_temp_out_avg=");
        Serial.print(g_temp_out_avg,DEC);
        Serial.print(" delta(avg)=");
        Serial.println(floatTempFormater(g_temp_out_avg - g_temp_in_avg));
    #endif
}

// function to format float type.
String floatTempFormater(float in) {
    char  tmpbuf[10];
    dtostrf( in, 2, 1, tmpbuf );
    String str = String(tmpbuf);

    if ( str.length() < 4) {
        str = "0" + str;
    }
    return str;
}

// function to fill buffer with offset values to draw a graph.
void fillGraphicBufferValues() {
    uint8_t delta_value = abs(g_temp_in - g_temp_out) * 2; //two pixels is a degree.

    temp_vdelta_arr_graphic[0] = delta_value;
    if  ( temp_vdelta_arr_graphic[0] > 22 ) {
        temp_vdelta_arr_graphic[0] = 22;  // cap maximum graph height.
    }

    for (uint8_t i = DISPLAY_WIDTH - 1; i > 0; i-- ) {
        temp_vdelta_arr_graphic[i] = temp_vdelta_arr_graphic[i - 1];
    }
}

// function to show temperature on display.
void readTemperatures() {
    /* important add or subtract values to make sure both sensors give the right temperature.
        this must be done manualy once! See top of code for temp_in_adjustmend & temp_out_adjustmend
    */

    tempSensors.requestTemperatures();

    float tempCIndex_O = tempSensors.getTempCByIndex(0);
    float tempCIndex_1 = tempSensors.getTempCByIndex(1);

    #ifdef DEBUG
        Serial.print("getTempCByIndex(0) = ");
        Serial.print( tempCIndex_O, DEC);
        Serial.print(" getTempCByIndex(1) = ");
        Serial.print( tempCIndex_1, DEC);
        Serial.print( " delta(raw) = ");
        Serial.println( tempCIndex_O - tempCIndex_1, DEC );
    #endif

    if ( tempCIndex_O > -127 ) {
        g_temp_in = tempCIndex_O + (temp_in_adjustmend);  // error offset.
    }

    if ( tempCIndex_1 > -127 ) {
        g_temp_out = tempCIndex_1 + (temp_out_adjustmend);  // error offset.
    }

    #ifdef DEBUG
        Serial.print("g_temp_in = ");
        Serial.print( g_temp_in, DEC);
        Serial.print(" g_temp_out = ");
        Serial.print( g_temp_out, DEC);
        Serial.print( " delta = ");
        Serial.println( g_temp_in - g_temp_out, DEC );
    #endif

}

// function to print a device address
void printAddress(DeviceAddress deviceAddress) {
    #ifdef DEBUG
        for (uint8_t i = 0; i < 8; i++)
        {
            if (deviceAddress[i] < 16) Serial.print("0");
            Serial.print(deviceAddress[i], HEX);
        }
    #endif
}

// function to set temp device precision.
int setTempPrecision() {
    numberOfDevices = tempSensors.getDeviceCount();
    if ( numberOfDevices < 1 ) {
        #ifdef DEBUG
            Serial.println("Error no temperature sensors found!");
         #endif
        return 0;
    }
    // Loop through each device, print out address and set the precision
    for (int i = 0; i < numberOfDevices; i++)
    {
        // Search the wire for address
        if (tempSensors.getAddress(tempDeviceAddress, i)) {
            
            #ifdef DEBUG
                Serial.print("temperature sensors found, index = ");
                Serial.print(i, DEC);
                Serial.print(" with address: ");
                printAddress(tempDeviceAddress);
                Serial.println();

                Serial.print("Resolution set to ");
                Serial.print(TEMPERATURE_PRECISION, DEC);
                Serial.println(" bits.");
            #endif
            // set the resolution to TEMPERATURE_PRECISION bit (Each Dallas/Maxim device is capable of several different resolutions)
            tempSensors.setResolution(tempDeviceAddress, TEMPERATURE_PRECISION);
            #ifdef DEBUG
                Serial.print("Actual resolution set to : ");
                Serial.print(tempSensors.getResolution(tempDeviceAddress), DEC);
                Serial.println();
            #endif

        } else {
            #ifdef DEBUG
                Serial.print("Ghost device at address: ");
                Serial.print(i, DEC);
                Serial.print(" address not found, check power supply and cabling.");
            #endif
        }
    }
    return numberOfDevices;
}

Afstellen van de temperatuur sensors.

De sensors die ik gebruikt heb voor het testen wijken soms wel 1 graad Celsius of iets meer af van de werkelijkheid. Als je het belangrijk vindt dat de juiste temperatuur wordt aangeven dan kun je de sensors ijken. Dit kan via de UTP berichten of via de seriële logging van de Arduino IDE. Als je de seriële logging wil gebruiken dan moet je de DEBUG activeren door de // voor //#define DEBUG 1  te verwijderen.


   Serial.print(" in =");
   Serial.print(in,DEC); 
   Serial.print(" out =");
   Serial.print(out ,DEC); 
   Serial.print(" delta(raw) =");
   Serial.print( floatTempFormater(out-in));
   Serial.print(" temp_in_avg =");
   Serial.print(temp_in_avg,DEC);
   Serial.print(" temp_out_avg =");
   Serial.print(temp_out_avg,DEC);
   Serial.print(" delta(avg) =");
   Serial.println(floatTempFormater(temp_out_avg - temp_in_avg));
   

Met de twee variabelen temp_in_adjustmend en temp_out_adjustmend kun je de aanpassingen doorvoeren. Het is een kwestie van testen en aanpassen, testen aanpassen, enz. Het werkt het eenvoudigst als je eerst zorgt dat dezelfde waarde aangeven en daarna de waarde voor de werkelijke temperatuur aangeeft door bij beide dezelfde waarde aan te passen. Ik heb beide sensoren met duct tape bij elkaar geplaatst en in een doek gedaan tegen tocht e.d.

const float temp_in_adjustmend  =  0.36;
const float temp_out_adjustmend =  1.4;

UDP berichten

De UDP berichten zijn in JSON formaat.

{
"id":"ztatz_dt",
"version":1.0,
"t_unit":"C",
"t_in_avg":24.1,
"t_out_avg":22.0,
"t_in":24.298,
"t_out":22.150,
"seq":24464
}
  •  id: geeft de unieke naam aan van het type bericht.
  • version: versie van het bericht, in de toekomst kan het bericht uitgebreid worden.
  • t_unit: C is graden Celsius.
  • t_in_avg: de gemiddelde temperatuur in over de afgelopen 3 seconden.
  • t_out_avg: de gemiddelde temperatuur uit over de afgelopen 3 seconden.
  • t_in: de ruwe temperatuur in, wordt elke 0.1 seconde gemeten.
  • t_uit: de ruwe temperatuur uit, wordt elke 0.1 seconde gemeten.
  • seq: volgorde nummers van het bericht met een waarde van 1 tot 32768. Als de waarde 32769 wordt bereikt dan is het volgende nummer 1. Bij een reboot wordt altijd gestart met de waarde 1. Het doel is dat ontvangers kunnen vaststellen of ze een waarde al gehad hebben of er een gemist.

Onderstaande code geeft een simpele voorbeeld hoe je met Python de berichten kunt uitlezen.

#!/usr/bin/python

import socket
import time
import datetime

# bind all IP
HOST = '0.0.0.0' 
# Listen on Port 
PORT = 30721 
#Size of receive buffer   
BUFFER_SIZE = 1024    
# Create a TCP/IP socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Bind the socket to the host and port
s.bind((HOST, PORT))
while True:
    # Receive BUFFER_SIZE bytes data
    # data is a list with 2 elements
    # first is data
    #second is client address
    data = s.recvfrom(BUFFER_SIZE)
    if data:
        #print received data
        print( datetime.datetime.fromtimestamp(time.time()).strftime('%H:%M:%S') +' ' + str(data[0]) )
# Close connection
s.close()