zomertijd ophalen met ESP8266
3 berichten
• Pagina 1 van 1
zomertijd ophalen met ESP8266
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
Hieronder de volledige
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);
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
Re: zomertijd ophalen met ESP8266
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.
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.
Re: zomertijd ophalen met ESP8266
- 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)
(Don't Drink and Root)
3 berichten
• Pagina 1 van 1
Wie is er online?
Gebruikers in dit forum: Geen geregistreerde gebruikers en 1 gast