zomertijd ophalen met ESP8266

Software vragen voor ESP chip familie
Berichten: 132
Geregistreerd: 21 Feb 2013, 16:04

zomertijd ophalen met ESP8266

Berichtdoor René » 14 Mei 2020, 18:59

Jarenlang kon ik de met een functie de zomertijd ophalen van een website (zie mijn eerdere posts). Die zomertijd-indicatie gebruikte ik bij een programma om de pulsen van een KWH meter (van mijn zonnepanelen) door te geven aan PV-Output.org die er mooie grafieken van maakte. De website waar ik de zomertijd-wijsheid vandaan haalde ondersteunt dat niet meer. Ik ben op zoek gegaan naar een alternatief en vond deze mogelijkheid https://www.arduinoslovakia.eu/blog/201 ... as?lang=en . Daarvan heb ik een deel "vertaald" naar mijn situatie.
Ik loop tegen het volgende probleem aan. Met de opdracht "printTime(CE.toLocal(epoch, &tcr));" in de loop krijg ik keurig het juiste (zomertijd) uur van onze tijdzone, maar dat gaat naar de seriële monitor. Ik wil dat het resultaat naar een unit8_t variabele "uur" gaat. Nu probeerde ik
Code: Alles selecteren
uur = (CE.toLocal(epoch, &tcr));
      Serial.println("");
      Serial.println(uur);
Maar wist eigenlijk al dat dat niet zou werken. Mijn vraag is dan ook hoe moet het wel?
Hieronder de volledige
Code: Alles selecteren
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <Timezone.h> //nnn

//
// internet specifieke zaken
//
const char* ssid        = "XXXXXXXXXXXXXXXXXXXX";
const char* password    = "XXXXXXXXXXXXX";
const char* host        = "pvoutput.org";
const char* SystemId    = "49832";
const char* APIKey      = "XXXXXXXXXXXXXXXXXXXXXX";

//
// NTP stuff
//
IPAddress       timeServerIP;
const char*     ntpServerName = "nl.pool.ntp.org";
const int       NTP_PACKET_SIZE = 48;                   // NTP time stamp is in the first 48 bytes of the message
byte            packetBuffer[NTP_PACKET_SIZE+1];        //buffer to hold incoming and outgoing packets
 
//     
//tijd zone stuff
//Central European Time (Frankfurt, Paris) //nnnn
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120};     //Central European Summer Time //nnnn
TimeChangeRule CET = {"CET", Last, Sun, Oct, 3, 60};       //Central European Standard Time  //nnnn
Timezone CE(CEST, CET); //nnn

//
// udp object
//
unsigned int localPort = 265;   // local port to listen for UDP packets
WiFiUDP udp;

//
// klok stuff
//
uint32_t    epoch;                      // seconden teller in UNIX tijd
struct tm   *lt;                        // struct om UNIX tijd op te breken in losse onderdelen
struct tm   myTime;
time_t      t;                          // Unix tijd in seconden
char *      c_time_string;              // pointer naar geformatteerde char array van datum en tijd
uint32_t    timer = 0;                  // onze klok timer
uint8_t     dag;                        // dagnummer
uint8_t     vorigedag = 1;              // dagnummer
uint8_t     maand;                      // maandnummer
uint16_t    jaar;                       // jaartal
uint8_t     uur;                        // uren
uint8_t     minuut;                     // minuten
uint8_t     seconde;                    // seconden
uint8_t     dagvdw;                     // dag van de week zondag is 0

//
// programma constanten
//

const int UPDATE_FREQ   =1000;         // elke sec de tijd  updaten
const uint32_t SEND_TIME        = 60000;             // tijd tussen verzenden data TIJDELIJK op 30 seconden normaal 5 minuten
//const uint32_t SEND_TIME        = 300000;             // tijd tussen verzenden data TIJDELIJK op 30 seconden normaal 5 minuten
const uint32_t NO_POWER_TIME    = 1000 * 60 * 10;     // tijdsduur geen pulsen meer ontvangen (normaliter 10 minuten)
 
//
// Stroom en puls variabelen
//
uint32_t    pulseCount = 0;                         // Number of pulses, used to measure energy.
uint32_t    pulseTime;                              // moment waarop de pulse wordt verwerkt
uint32_t    lastTime;                               // vorige moment waarop de puls is verwerkt
volatile    boolean pulse = false;                  // indicator dat er een puls is geweest
volatile    boolean maximum = true;                 // indicator om maximale power binnen sentTime te berekenen

//power and energy
double      power;                                  // vermogen dat is geleverd sinds de vorige pulse
double      maxpower;                               // maximale vermogen binnen sentTime
double      opbrengst;                              // totale opbrengst van een dag
uint32_t    ppwh    = 1;                            // 1000 pulses/kwh = 1 pulse per wh
uint32_t    sent    = 0;                            // tijd tussen verzenden data
//
//
// timers
//
uint32_t    RTCTimer;           // onze softwarematige RTC
uint32_t    noPowerTimer;       // timer die vaststeld hoelang er geen power is
uint32_t    sendTimer;          // timer die bepaalt wanneer er verzonden wordt

int pin = 2;                    // Pin waarop de pulsen binnen komen
int teller = 0;                 // wordt gebruikt om de eerste puls na een reset niet te gebruiken voor power berekening omdat de tijd niet goed wordt gemeten

uint32_t startTime;             // begintijd van een pulse
uint32_t eindTime;              // eindtijd van een pulse
const uint32_t PULSE_TIME = 60; // minimale lengte van een pulse
 
void setup() {
    Serial.begin(115200);
    Serial.println();
    Serial.println();
    //
    // connectie met lokaal wifi netwerk
    //
    Serial.print("Connecting to ");
    Serial.println(ssid);
    WiFi.begin(ssid, password);
 
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    //
    // ophalen NTP tijd voor de eerste keer
    //
    if (waitForNTPTime()) {
        Serial.println("No time received after 10 retries");
    }
 
    timer = millis();                           // start onze seconden teller
    noPowerTimer    = millis();                 // start de no power timer
    sendTimer       = noPowerTimer;             // start de zend timer
 }


//
// begin loop
//

void loop() {
//Serial.println("start loop");
if (digitalRead(2) == LOW)
{
startTime=millis();
while (digitalRead(2) == LOW) {}
  if (millis()-startTime > PULSE_TIME)
  {
   pulse = true;
     }
  else
  {
  //  Serial.println("korter dan pulsetijd"); // toont ook de pulsen die korter zijn
  }
}
    uint32_t ditMoment = millis();             // nu
    //
    // een keer per dag even de tijd synchroniseren met de NTP server
    //
 
if (dag != vorigedag && uur == 4) {
          if (waitForNTPTime()) {
            Serial.println("No time received after 10 retries");
        }
        vorigedag = dag;
    }
   
    //
    // kijk of de klok bijgewerkt moet worden
    //
    if ((ditMoment - timer) > UPDATE_FREQ) {
        //
        // een seconde verlopen
        //
        epoch += 1;                                 // verhoog de seconden
        t = (time_t)epoch;                          // maak een time_t element van
        c_time_string = ctime(&t);                  // maak er een string van
        lt = localtime(&t);                         // zet onze unix tijd in een char array

// NIEUW*************

TimeChangeRule *tcr;
      printTime(CE.toLocal(epoch, &tcr));
      uur = (CE.toLocal(epoch, &tcr));
      Serial.println("");
      Serial.println(uur);

//NIEUW***************

        //
        // bewaar onze parameters omdat we ze anders kwijt zijn vanwege heap
        // tevens correctie van maand: Die lopen van 0-11
        // en jaar omdat de standaard telling vanaf 1900 loopt.
        //
        dag     = lt->tm_mday;
        maand   = lt->tm_mon + 1;                    // maanden lopen van 0-11
        jaar    = lt->tm_year + 1900;                // startpunt van tellen was 1900
//      uur     = lt->tm_hour
//      if (uur == 25) uur = 1;
        minuut  = lt->tm_min;
        seconde = lt->tm_sec;
        dagvdw  = lt->tm_wday;
        timer = ditMoment;                          // start onze timer opnieuw

       }
    //
    // check of er een puls is binnengekomen
    //
   
    if (pulse) {
       pulse       = false;                    // deze puls is verwerkt
       pulseCount++;                           // verhoog aantal pulsen voor totale opbrengst verwerking
       lastTime    = pulseTime;                // bewaar vorige puls moment
       pulseTime   = ditMoment;                // zet de huidige tijd vast
        //
        // Calculate power
        //


Serial.println(teller);
    if (teller == 1) // de eerste  pulsen na een reset wordt niet meegenomen voor de berekening van de power
                    // omdat de tijd tussen de pulsen niet goed wordt gemeten
    {
    power  = (3600000.0 / double((pulseTime - lastTime))) / (double)ppwh;
   
      if (maximum)  maxpower = power;
     
            //
Serial.print("nieuw ");
Serial.println(power);
 
       
          if (maxpower > power ) power = maxpower;
           maxpower = power;
         maximum = false;
    }
    teller = 1;

      Serial.print("max ");
Serial.println(maxpower);
   
        //Find Wh elapsed
        //
        opbrengst   = (1.0 * (double)pulseCount / (double)(ppwh));
        //
        // er komt nog steeds stroom binnen dus reset de nopower timer
        //
        noPowerTimer = ditMoment;
     }
 an m   //
    // kijk of we de limiet van geen stroom nog niet zijn overschreden
    //
    if (ditMoment - noPowerTimer < NO_POWER_TIME) {
        //
        // er is op zijn minst binnen de afgelopen 10 minuten NOG stroom geleverd
        //
        if ((ditMoment - sendTimer) > SEND_TIME) {

             //
            // We now create a URI for the request
            //
            char url [200];                 // char array om url op te bouwen
            char opbrengstStr[10];          // om een float in char array om te zetten
            char powerStr[10];              // om een float in char array om te zetten
 
            dtostrf(opbrengst, 7, 2, opbrengstStr);                 // zet de float om in een 7.2 cijfer
            strcpy(opbrengstStr, trimLeadingSpaces(opbrengstStr));  // en haal de voorloop spaties weg
 
            dtostrf(maxpower, 7, 2, powerStr);
            strcpy(powerStr, trimLeadingSpaces(powerStr));
            //
            // bouw de url op
            //
            sprintf(url, "/service/r2/addstatus.jsp?key=%s&sid=%s&d=%4d%02d%02d&t=%02d:%02d&v1=%s&v2=%s",
                                                        APIKey,
                                                        SystemId,
                                                        jaar,
                                                        maand,
                                                        dag,
                                                        uur,
                                                        minuut,
                                                        opbrengstStr,
                                                        powerStr);
       Serial.println(url);
            //
            // De data verzenden naar onze host
            //
          // Use WiFiClient class to create TCP connections
         WiFiClient client;
         const int httpPort = 80;
          if (!client.connect(host, httpPort)) {
              Serial.println("connection1 failed");
              return;
         }
 
            // This will send the request to the server
             client.print(String("GET ") + url + " HTTP/1.1\r\n" + //TIJDELIJK UITGEZET
             "Host: " + host + "\r\n" +
             "Connection: close\r\n\r\n");
             unsigned long timeout = millis();
             while (client.available() == 0) {
             if (millis() - timeout > 5000) {
             //Serial.println(">>> Client Timeout !");
             client.stop();
             return;
             }
             }
             // Read all the lines of the reply from server and print them to Serial
             while(client.available()) {
             String line = client.readStringUntil('\r');
             //Serial.print(line);
             }
            //Serial.println();
            //Serial.println("closing connection");
            //
            // reset de send timer
            //
         
            sendTimer = ditMoment;
            maximum = true;
            //
            // als er binnen 3 minuten geen pulsen zijn binnengekomen
            // dan zetten we het vermogen op 0
            //
            if ((ditMoment - pulseTime) > 180000) {
                power = 0.0; // als er 3 minuten geen pulsen zijn gekomen is power 0
                maxpower = 0;  // ook maxpower moet dan naar 0 want die wordt verzonden
            }
        }
    } else {
       
        if (uur == 22) {
            //
            // na 22:00 worden de totalen op 0 gezet
            //
            pulseCount  = 0;
            opbrengst   = 0.0;
            power       = 0.0;
        }
    }
} // einde loop



/**
 * @name trimLeadingSpaces
 * @param charString pointer to string containing chars
 * @return new pointer to first non space
 */
char * trimLeadingSpaces(char * charString) {
 
    char *ptr = charString;
 
    for (uint16_t i = 0; i < strlen(charString); i++) {
        //
        // kijk of het een spatie is
        if (*ptr == 0x20 ) {
            ptr++;
        } else {
            //
            // we zijn er dus klaar
            //
            break;
        }
    }
    return ptr;
}
/**
 * @name sentNTPpacket
 * @param address IP Address of server
 * Sends a request to the NTP server
 */
// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress& address) {
    Serial.println("sending NTP packet...");
    // set all bytes in the buffer to 0
    memset(packetBuffer, 0, NTP_PACKET_SIZE);
    // Initialize values needed to form NTP request
    // (see URL above for details on the packets)
    packetBuffer[0] = 0b11100011;   // LI, Version, Mode
    packetBuffer[1] = 0;     // Stratum, or type of clock
    packetBuffer[2] = 6;     // Polling Interval
    packetBuffer[3] = 0xEC;  // Peer Clock Precision
    // 8 bytes of zero for Root Delay & Root Dispersion
    packetBuffer[12] = 49;
    packetBuffer[13] = 0x4E;
    packetBuffer[14] = 49;
    packetBuffer[15] = 52;
 
    // all NTP fields have been given values, now
    // you can send a packet requesting a timestamp:
    udp.beginPacket(address, 123); //NTP requests are to port 123
    udp.write(packetBuffer, NTP_PACKET_SIZE);
    udp.endPacket();
    return 0;
}
/**
 * @ name  wait for a time back from the NPT server
 * @return 1= OK 0=Error (after 10 times)
 */
uint8_t waitForNTPTime() {
    uint8_t returnCode = 1;                 // de return code of dit wel/niet succesvol was
 
    Serial.println("Starting UDP");
    udp.begin(localPort);
    Serial.print("Local port: ");
    Serial.println(udp.localPort());
    //get a random server from the pool
    WiFi.hostByName(ntpServerName, timeServerIP);
 
    for (uint8_t i = 0; i < 10; i++) {
 
        sendNTPpacket(timeServerIP);        // send an NTP packet to a time server
                                            // wait to see if a reply is available
        delay(1000);
 
        int cb = udp.parsePacket();
        if (!cb) {
            Serial.println("no packet yet");
        } else {
            Serial.print("packet received, length=");
            Serial.println(cb);
            // We've received a packet, read the data from it
            udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
 
            //the timestamp starts at byte 40 of the received packet and is four bytes,
            // or two words, long. First, esxtract the two words:
 
            unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
            unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
            // combine the four bytes (two words) into a long integer
            // this is NTP time (seconds since Jan 1 1900):
            unsigned long secsSince1900 = highWord << 16 | lowWord;
            Serial.print("Seconds since Jan 1 1900 = ");
            Serial.println(secsSince1900);
 
            // now convert NTP time into everyday time:
            Serial.print("Unix time = ");
            // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
            const unsigned long seventyYears = 2208988800UL;
            // subtract seventy years:
            epoch = secsSince1900 - seventyYears;
          Serial.print(" print Unix time:");
          Serial.println(epoch);
            //
            // breek onze tijd op in de verschillende componenten
            //
            t = (time_t) epoch;
            returnCode = 0;
            break;
        }
    }
    return returnCode;
}

//Function to print time with time zone ///nn  vanaf hier
//void printTime(time_t t, char *tz, char *loc)
void printTime(time_t t)
{
  sPrintI00(hour(t));
}

//Print an integer in "00" format (with leading zero).
//Input value assumed to be between 0 and 99.
void sPrintI00(int val)
{
  if (val < 10) Serial.print('0');
  Serial.print(val, DEC);
  return;
}

//Print an integer in ":00" format (with leading zero).
//Input value assumed to be between 0 and 99.
void sPrintDigits(int val)
{
  Serial.print(':');
  if (val < 10) Serial.print('0');
  Serial.print(val, DEC);
}

Advertisement

Gebruikers-avatar
Berichten: 2655
Geregistreerd: 06 Aug 2016, 01:03

Re: zomertijd ophalen met ESP8266

Berichtdoor Koepel » 15 Mei 2020, 18:59

Dan zul je moeten kijken wat die CE.toLocal(epoch, &tcr) precies terug geeft.
Volgens mij een 'time_t', oftewel het aantal seconden sinds 1970.

Er viel me nog iets op.
Bij een sprintf() hoort een "%d" bij een 'int'.
Als er bij het formaat een "%d" staat, dan hoort er een 'int' op de stack te staan. Dus geen 'uint16_t', geen 'uint8_t', geen 'byte', alleen een 'int' is correct.

Als je zomaar iets willekeurigs van internet plukt, hoe weet je dan of het in orde is en niet boordevol fouten zit ?
In dit geval heb je geluk, de code staat ook op Github: https://github.com/RoboUlbricht/arduinoslovakia/blob/master/esp8266/ntp_client/ntp_client.ino en het heeft 67 sterren.

Gebruikers-avatar
Berichten: 55
Geregistreerd: 22 Sep 2016, 21:21

Re: zomertijd ophalen met ESP8266

Berichtdoor rene7777 » 25 Jan 2021, 00:57

Code: Alles selecteren
long adjustDstEurope(long epoch)
{
  // last sunday of march
  int beginDSTDate= (31 - (5* year(epoch) /4 + 4) % 7);
  int beginDSTMonth=3;
  //last sunday of october
  int endDSTDate= (31 - (5 * year(epoch) /4 + 1) % 7);
  int endDSTMonth=10;
  // DST is valid as:
  if (((month(epoch) > beginDSTMonth) && (month(epoch) < endDSTMonth))
    || ((month(epoch) == beginDSTMonth) && (day(epoch) >= beginDSTDate))
    || ((month(epoch) == endDSTMonth) && (day(epoch) < endDSTDate)))
    return true; // DST europe = GMT +2
  else return false; // nonDST europe = GMT +1
}
sudo rm -rf /
(Don't Drink and Root)

Terug naar ESP Software

Wie is er online?

Gebruikers in dit forum: Geen geregistreerde gebruikers en 5 gasten