ESP8266 PV-Output met meerdere ingangen (6 kWh-meters)

Software vragen voor ESP chip familie
Berichten: 3
Geregistreerd: 12 Jul 2018, 18:35

ESP8266 PV-Output met meerdere ingangen (6 kWh-meters)

Berichtdoor Frans1980 » 12 Jul 2018, 20:36

De ESP8266 gebruik ik om pulsen te tellen van mijn kWh-meter en die naar PV-Output op te sturen. De code heb ik gekregen van iemand. De code werkt goed, maar nu wil ik deze aanpassen zodat ik 6 kWh-meters kan loggen op 1 ESP.

De huidige code is als volgt:
Er zit vrij veel code in voor de klok c.q. NTP-server.
cpp code
/*
* versie 12 dd 01 mei 2018
* tijdsyncronisatie nu afhankelijk van dag verandering
*
*
* zomertijd aangepast
* programma meet de SO pulsen van een kwh meter die de levering van zonnepanelen meet
* programma stuurt data via HTTP GET requests naar PVoutput.org service.
* elke 5 minuten wordt de maximale power in die 5 minuten en de totale opbrangst van de dag tot op dat moment verstuurd
* programma draait op een esp8266 v1.5.0
* via NTP server nl.pool.ntp.org wordt om 00:00:30 uur de tijd opgehaald
* in het programma worden geen Strings gebruikt
* veel dank aan Nico Verduin voor de ingewikkelde zaken mbt pointers en array's
*
*/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <time.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <WiFiClientSecure.h>

const int UPDATE_FREQ =1000; // elke sec de tijd updaten
const int GMT_CORRECTIE = 3600; // pas de tijd aan aan NL. = + 1 uur

unsigned int localPort = 123; // local port to listen for UDP packets
//
// internet specifieke zaken
//
const char* ssid = "?????";
const char* password = "??????";
const char* host = "pvoutput.org";
const char* SystemId = "?????";
const char* APIKey = "????????????????????????????";

const char* hostZomertijd = "maps.googleapis.com";
const int httpsPort = 443; // localpoort voor secure verbindingen
const char* zomerTijdKey= "AIzaSyCtC0BKgufYKsLMvouXrtr66M2rY_e92X4";
//
// 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

WiFiUDP udp; // udp object
//
// 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; // 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

//
//zomertijd gedoe
//
char charArray[200];
boolean zomerTijd = false;
uint8_t zt = 0;

//
// programma constanten
//

//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;
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 = 30; // 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");
}
getStime(); // kijken of het zomertijd is bij opstarten

// Serial.println("response van char * getStime()");
// Serial.println(getStime());
if (zomerTijd == true) zt = 1;
timer = millis(); // start onze seconden teller
noPowerTimer = millis(); // start de no power timer
sendTimer = noPowerTimer; // start de zend timer

//pulseTime = 0 ;

}
/**
* @name loop
* Wordt eindeloos aangeroepen
*/
void 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 (uur == 0 && minuut == 0 && seconde == 30) {
zt = 0;
if (waitForNTPTime()) {
Serial.println("No time received after 10 retries");
}
if (zomerTijd == true) {
zt = 1;
}
}

*/
if (dag != vorigedag && uur == 4) {
zt = 0;
if (waitForNTPTime()) {
Serial.println("No time received after 10 retries");
}
getStime(); // kijken of het zomertijd
if (zomerTijd == true) {
zt = 1;
}
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

//
// 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 + zt;
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;

}

//
// 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
//
//
// //Serial.print("connecting to ");
// //Serial.println(host);
// // Use WiFiClient class to create TCP connections
WiFiClient client;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println("connection 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



/*
// zomertijdfunctie
*/
boolean getStime() // functie om zomertijd op te halen van website
{
char charArray[200]; // ff ruim genomen
charArray[0] = '\0';
uint8_t charArrayIndex = 0;
WiFiClientSecure client;
if (!client.connect(hostZomertijd, httpsPort)) {
Serial.println("connection failed");
// return;
}
String url = "/maps/api/timezone/json?location=51.643567,%205.946934&timestamp=";
url += t;
url += "&key=";
url += zomerTijdKey;
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + hostZomertijd + "\r\n" +
"Connection: close\r\n\r\n");
while(client.available() == 0) {
yield();
}
while(client.available()) {
charArray[charArrayIndex] = client.read(); // lees teken in de tabel
if (charArray[charArrayIndex] == '\n' ){ // blijven lezen tot er een return komt
charArray[charArrayIndex] = '\0'; // en sluit te tekst af met een '\0'. De return halen we gelijk weg
//
// kijk of dit de zomertijd regel is
//
char *startPositie;
Serial.println(charArray);
startPositie = strstr(charArray, "\"dstOffset\" : 3600,");
//
// is dit is onze regel?
//
if (startPositie != NULL){
//
// yep dus skip 3 posities en we hebben het startpunt
//
zomerTijd = true;
client.stop();
return zomerTijd;
}
else {
Serial.println(" niet de gewenste regel dus zet hem maar weer op 0 in else");
//
charArray[0] = '\0';
charArrayIndex = 0;
}
}
else {
charArrayIndex++;
}
}
Serial.println("als je hier terecht komt heb je niet hetgene ontvangen wat je wilde");
zomerTijd = false;
client.stop();
return zomerTijd;
}


/**
* @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;
//
// GMT correctie
//
epoch = epoch + GMT_CORRECTIE;

// print Unix time:
Serial.println(epoch);
//
// breek onze tijd op in de verschillende componenten
//
t = (time_t) epoch;
returnCode = 0;
break;
}
}
return returnCode;
}


Nu wil ik gelijktijdig 6 kWh meter loggen naar PV-output op één ESP8266. De LED op de kWh-meter brand 40ms met 1000 imp/kWh.
Hoe krijg ik het voor elkaar met 6 kWh-meters. Met name omdat er ook gelijktijdig LED's hoog kunnen zijn. De huidige code werkt zonder interupts.

Advertisement

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

Re: ESP8266 PV-Output met meerdere ingangen (6 kWh-meters)

Berichtdoor Koepel » 15 Jul 2018, 15:29

Dat gaat niet zomaar met die sketch.
Dan zouden interrupts nodig zijn om de pulsen te meten.
Ik weet niet of de ESP8266 zes interrupt ingangen heeft.
Nu zit het het meten van een puls vast in de loop() met een wachttijd totdat de puls is afgelopen.

Terug naar ESP Software

Wie is er online?

Gebruikers in dit forum: Geen geregistreerde gebruikers en 11 gasten