Updated readme
This commit is contained in:
parent
6bd04eda97
commit
bd566a4b39
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.vscode
|
||||||
|
*.code-workspace
|
479
P1Meter.ino
479
P1Meter.ino
@ -1,22 +1,68 @@
|
|||||||
// #include <TimeLib.h>
|
#include <TimeLib.h>
|
||||||
|
#include <NTPClient.h>
|
||||||
#include <SoftwareSerial.h>
|
#include <SoftwareSerial.h>
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
#include <ESP8266mDNS.h>
|
#include <ESP8266mDNS.h>
|
||||||
#include <ESP8266HTTPClient.h>
|
#include <ESP8266HTTPClient.h>
|
||||||
#include <WiFiUdp.h>
|
#include <WiFiUdp.h>
|
||||||
#include <ArduinoOTA.h>
|
#include <ArduinoOTA.h>
|
||||||
|
#include <Button2.h>
|
||||||
|
#include <Timer.h>
|
||||||
#include "CRC16.h"
|
#include "CRC16.h"
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <Adafruit_GFX.h>
|
||||||
|
#include <Fonts/Org_01.h>
|
||||||
|
#include <Adafruit_PCD8544.h>
|
||||||
|
|
||||||
//===Change values from here===
|
// Function prototypes
|
||||||
const char* ssid = "WIFISSID";
|
void reboot();
|
||||||
const char* password = "PASSWORD";
|
time_t NTPgetTime();
|
||||||
const char* hostName = "ESPP1Meter";
|
void drawMenu();
|
||||||
const char* domoticzIP = "192.168.1.35";
|
|
||||||
const int domoticzPort = 8090;
|
// Time related settings
|
||||||
const int domoticzGasIdx = 291;
|
Timer t;
|
||||||
const int domoticzEneryIdx = 294;
|
WiFiUDP ntpUDP;
|
||||||
const bool outputOnSerial = true;
|
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 10000);
|
||||||
//===Change values to here===
|
|
||||||
|
// Display settings
|
||||||
|
//// Software SPI (slower updates, more flexible pin options):
|
||||||
|
//// pin 7 - Serial clock out (SCLK)
|
||||||
|
//// pin 6 - Serial data out (DIN)
|
||||||
|
//// pin 5 - Data/Command select (D/C)
|
||||||
|
//// pin 4 - LCD chip select (CS)
|
||||||
|
//// pin 3 - LCD reset (RST)
|
||||||
|
Adafruit_PCD8544 display = Adafruit_PCD8544(D7, D6, D5, D4, D3);
|
||||||
|
int tab = 0;
|
||||||
|
int tabCount = 3;
|
||||||
|
|
||||||
|
// LED settings
|
||||||
|
#define ledPin D8
|
||||||
|
int ledBrightness = 192;
|
||||||
|
void ledOff();
|
||||||
|
int ledTimeout;
|
||||||
|
|
||||||
|
// Button settings
|
||||||
|
#define buttonPin D2
|
||||||
|
Button2 button = Button2(buttonPin);
|
||||||
|
|
||||||
|
// Wifi Settings
|
||||||
|
const char *ssid = "*";
|
||||||
|
const char *password = "*";
|
||||||
|
const char *hostName = "ESPP1Meter";
|
||||||
|
|
||||||
|
// Server settings
|
||||||
|
const char *apiIP = "192.168.2.6";
|
||||||
|
const int apiPort = 3000;
|
||||||
|
const char *apiKey = "*";
|
||||||
|
const int gasIdx = 291;
|
||||||
|
const int energyIdx = 294;
|
||||||
|
const bool outputOnSerial = false;
|
||||||
|
|
||||||
|
// Statistics variables
|
||||||
|
unsigned long telegramsTotal = 0;
|
||||||
|
unsigned long telegramsInvalid = 0;
|
||||||
|
unsigned long postedTotal = 0;
|
||||||
|
unsigned long postedFailed = 0;
|
||||||
|
|
||||||
// Vars to store meter readings
|
// Vars to store meter readings
|
||||||
long mEVLT = 0; //Meter reading Electrics - consumption low tariff
|
long mEVLT = 0; //Meter reading Electrics - consumption low tariff
|
||||||
@ -28,233 +74,459 @@ long mEAT = 0; //Meter reading Electrics - Actual return
|
|||||||
long mGAS = 0; //Meter reading Gas
|
long mGAS = 0; //Meter reading Gas
|
||||||
long prevGAS = 0;
|
long prevGAS = 0;
|
||||||
|
|
||||||
|
|
||||||
#define MAXLINELENGTH 128 // longest normal line is 47 char (+3 for \r\n\0)
|
#define MAXLINELENGTH 128 // longest normal line is 47 char (+3 for \r\n\0)
|
||||||
char telegram[MAXLINELENGTH];
|
char telegram[MAXLINELENGTH];
|
||||||
|
unsigned int currentCRC = 0;
|
||||||
|
|
||||||
#define SERIAL_RX D5 // pin for SoftwareSerial RX
|
// P1 Serial settings
|
||||||
SoftwareSerial mySerial(SERIAL_RX, -1, true, MAXLINELENGTH); // (RX, TX. inverted, buffer)
|
#define SERIAL_RX D1 // pin for SoftwareSerial RX
|
||||||
|
SoftwareSerial mySerial(SERIAL_RX, -1, false); // (RX, TX, inverted)
|
||||||
|
|
||||||
unsigned int currentCRC=0;
|
void setup()
|
||||||
|
|
||||||
void SendToDomoLog(char* message)
|
|
||||||
{
|
{
|
||||||
char url[512];
|
// Init Serial
|
||||||
sprintf(url, "http://%s:%d/json.htm?type=command¶m=addlogmessage&message=%s", domoticzIP, domoticzPort, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
Serial.println("Booting");
|
delay(50);
|
||||||
|
|
||||||
|
// Init LED
|
||||||
|
pinMode(ledPin, OUTPUT);
|
||||||
|
analogWrite(ledPin, ledBrightness);
|
||||||
|
|
||||||
|
// Init Button
|
||||||
|
button.setReleasedHandler(press);
|
||||||
|
|
||||||
|
// Init Display
|
||||||
|
display.begin();
|
||||||
|
display.setContrast(50);
|
||||||
|
display.setFont(&Org_01);
|
||||||
|
drawMenu();
|
||||||
|
|
||||||
|
// Init WiFi
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
|
|
||||||
|
display.println("Connecting to:");
|
||||||
|
display.print(" ");
|
||||||
|
display.println(ssid);
|
||||||
|
display.display();
|
||||||
|
|
||||||
WiFi.begin(ssid, password);
|
WiFi.begin(ssid, password);
|
||||||
|
|
||||||
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
while (WiFi.waitForConnectResult() != WL_CONNECTED)
|
||||||
|
{
|
||||||
Serial.println("Connection Failed! Rebooting...");
|
Serial.println("Connection Failed! Rebooting...");
|
||||||
|
drawMenu();
|
||||||
|
display.println("Connection Failed!");
|
||||||
|
display.display();
|
||||||
delay(5000);
|
delay(5000);
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Init P1 Serial
|
||||||
mySerial.begin(115200);
|
mySerial.begin(115200);
|
||||||
|
|
||||||
// Port defaults to 8266
|
// Init ArduinoOTA
|
||||||
// ArduinoOTA.setPort(8266);
|
//// Port defaults to 8266
|
||||||
|
ArduinoOTA.setPort(8266);
|
||||||
|
|
||||||
// Hostname defaults to esp8266-[ChipID]
|
//// Hostname defaults to esp8266-[ChipID]
|
||||||
ArduinoOTA.setHostname(hostName);
|
ArduinoOTA.setHostname(hostName);
|
||||||
|
|
||||||
// No authentication by default
|
//// No authentication by default
|
||||||
// ArduinoOTA.setPassword((const char *)"123");
|
// ArduinoOTA.setPassword((const char *)"123");
|
||||||
|
|
||||||
ArduinoOTA.onStart([]() {
|
ArduinoOTA.onStart([]() {
|
||||||
|
drawMenu();
|
||||||
|
display.println("OTA Update");
|
||||||
|
display.display();
|
||||||
|
|
||||||
Serial.println("Start");
|
Serial.println("Start");
|
||||||
});
|
});
|
||||||
ArduinoOTA.onEnd([]() {
|
ArduinoOTA.onEnd([]() {
|
||||||
Serial.println("\nEnd");
|
Serial.println("\nEnd");
|
||||||
});
|
});
|
||||||
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
|
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
|
||||||
|
drawMenu();
|
||||||
|
display.println("OTA Update");
|
||||||
|
display.printf("Progress: %u%%\r", (progress / (total / 100)));
|
||||||
|
display.display();
|
||||||
|
|
||||||
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
|
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
|
||||||
});
|
});
|
||||||
ArduinoOTA.onError([](ota_error_t error) {
|
ArduinoOTA.onError([](ota_error_t error) {
|
||||||
|
drawMenu();
|
||||||
|
display.println("OTA Update");
|
||||||
|
display.printf("Error[%u]: ", error);
|
||||||
|
display.display();
|
||||||
|
|
||||||
Serial.printf("Error[%u]: ", error);
|
Serial.printf("Error[%u]: ", error);
|
||||||
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
|
if (error == OTA_AUTH_ERROR)
|
||||||
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
|
Serial.println("Auth Failed");
|
||||||
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
|
else if (error == OTA_BEGIN_ERROR)
|
||||||
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
|
Serial.println("Begin Failed");
|
||||||
else if (error == OTA_END_ERROR) Serial.println("End Failed");
|
else if (error == OTA_CONNECT_ERROR)
|
||||||
|
Serial.println("Connect Failed");
|
||||||
|
else if (error == OTA_RECEIVE_ERROR)
|
||||||
|
Serial.println("Receive Failed");
|
||||||
|
else if (error == OTA_END_ERROR)
|
||||||
|
Serial.println("End Failed");
|
||||||
});
|
});
|
||||||
ArduinoOTA.begin();
|
ArduinoOTA.begin();
|
||||||
Serial.println("Ready");
|
|
||||||
Serial.print("IP address: ");
|
// Init Time
|
||||||
Serial.println(WiFi.localIP());
|
timeClient.begin();
|
||||||
|
|
||||||
|
time_t test = NTPgetTime();
|
||||||
|
while (test < 10000)
|
||||||
|
{
|
||||||
|
test = NTPgetTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
setTime(NTPgetTime());
|
||||||
|
getExternalTime NtpTime = &NTPgetTime;
|
||||||
|
setSyncProvider(NtpTime);
|
||||||
|
setSyncInterval(3600);
|
||||||
|
|
||||||
|
display.println("Time set");
|
||||||
|
display.display();
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// Exit setup
|
||||||
|
drawTab(2);
|
||||||
|
ledTimeout = t.after(5000, ledOff, (void *)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reboot the ESP
|
||||||
|
void reboot()
|
||||||
|
{
|
||||||
|
drawMenu();
|
||||||
|
display.println("Scheduled reboot");
|
||||||
|
display.display();
|
||||||
|
delay(5000);
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
|
||||||
bool SendToDomo(int idx, int nValue, char* sValue)
|
// Update Time
|
||||||
|
time_t NTPgetTime()
|
||||||
|
{
|
||||||
|
timeClient.update();
|
||||||
|
return timeClient.getEpochTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn of the backlight LEDs
|
||||||
|
void ledOff(void *context)
|
||||||
|
{
|
||||||
|
tab = 0;
|
||||||
|
drawTab(tab);
|
||||||
|
analogWrite(ledPin, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Button action
|
||||||
|
void press(Button2 &btn)
|
||||||
|
{
|
||||||
|
analogWrite(ledPin, ledBrightness);
|
||||||
|
t.stop(ledTimeout);
|
||||||
|
ledTimeout = t.after(10000, ledOff, (void *)0);
|
||||||
|
|
||||||
|
if ((tab + 1) == tabCount)
|
||||||
|
{
|
||||||
|
tab = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tab++;
|
||||||
|
}
|
||||||
|
drawTab(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw top bar
|
||||||
|
void drawMenu()
|
||||||
|
{
|
||||||
|
display.clearDisplay();
|
||||||
|
display.setCursor(0, 4);
|
||||||
|
display.println("P1 Reader");
|
||||||
|
display.drawLine(0, 6, 84, 6, 1);
|
||||||
|
|
||||||
|
display.display();
|
||||||
|
display.setCursor(0, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawTab(int no)
|
||||||
|
{
|
||||||
|
drawMenu();
|
||||||
|
switch (no)
|
||||||
|
{
|
||||||
|
// Network
|
||||||
|
case 0:
|
||||||
|
drawMenu();
|
||||||
|
|
||||||
|
// SSID
|
||||||
|
display.println("Connected to:");
|
||||||
|
display.print(" ");
|
||||||
|
display.println(ssid);
|
||||||
|
|
||||||
|
// Own IP
|
||||||
|
display.println("IP address: ");
|
||||||
|
display.print(" ");
|
||||||
|
display.println(WiFi.localIP());
|
||||||
|
|
||||||
|
// Target server
|
||||||
|
display.println("Target host: ");
|
||||||
|
display.print(" ");
|
||||||
|
display.println(String(apiIP) + ":" + String(apiPort));
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Stats
|
||||||
|
case 1:
|
||||||
|
drawMenu();
|
||||||
|
|
||||||
|
// Telegrams
|
||||||
|
display.println("Telegrams");
|
||||||
|
display.print(" Total: ");
|
||||||
|
display.println(String(telegramsTotal));
|
||||||
|
display.print(" Invalid: ");
|
||||||
|
display.println(String(telegramsInvalid));
|
||||||
|
|
||||||
|
// Posted
|
||||||
|
display.println("Posted");
|
||||||
|
display.print(" Total: ");
|
||||||
|
display.println(String(postedTotal));
|
||||||
|
display.print(" Failed: ");
|
||||||
|
display.println(String(postedFailed));
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Time
|
||||||
|
case 2:
|
||||||
|
display.println("Current time:");
|
||||||
|
|
||||||
|
// Time
|
||||||
|
display.print(" ");
|
||||||
|
if (hour() < 10)
|
||||||
|
{
|
||||||
|
display.print("0");
|
||||||
|
}
|
||||||
|
display.print(hour());
|
||||||
|
display.print(":");
|
||||||
|
if (minute() < 10)
|
||||||
|
{
|
||||||
|
display.print("0");
|
||||||
|
}
|
||||||
|
display.println(minute());
|
||||||
|
|
||||||
|
// Date
|
||||||
|
display.print(" ");
|
||||||
|
if (day() < 10)
|
||||||
|
{
|
||||||
|
display.print("0");
|
||||||
|
}
|
||||||
|
display.print(day());
|
||||||
|
display.print("-");
|
||||||
|
if (month() < 10)
|
||||||
|
{
|
||||||
|
display.print("0");
|
||||||
|
}
|
||||||
|
display.print(month());
|
||||||
|
display.print("-");
|
||||||
|
display.println(year());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
display.display();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send data to server
|
||||||
|
bool Send(int idx, int nValue, char *sValue)
|
||||||
{
|
{
|
||||||
HTTPClient http;
|
HTTPClient http;
|
||||||
bool retVal = false;
|
bool retVal = false;
|
||||||
char url[255];
|
char httpRequestData[255];
|
||||||
sprintf(url, "http://%s:%d/json.htm?type=command¶m=udevice&idx=%d&nvalue=%d&svalue=%s", domoticzIP, domoticzPort, idx, nValue, sValue);
|
|
||||||
Serial.printf("[HTTP] GET... URL: %s\n",url);
|
// "http://%s:%d/json.htm?type=command¶m=udevice&idx=%d&nvalue=%d&svalue=%s"
|
||||||
http.begin(url); //HTTP
|
// "api_key=tPmAT5Ab3j7F9&sensor=BME280&value1=24.25&value2=49.54&value3=1005.14"
|
||||||
int httpCode = http.GET();
|
sprintf(httpRequestData, "api_key=%s&type=%d&nval=%d&sval=%s", apiKey, idx, nValue, sValue);
|
||||||
|
|
||||||
|
Serial.printf("[HTTP] GET... URL: %s\n", httpRequestData);
|
||||||
|
|
||||||
|
http.begin(String("http://" + String(apiIP) + ":" + String(apiPort))); //HTTP
|
||||||
|
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||||
|
|
||||||
|
postedTotal++;
|
||||||
|
int httpCode = http.POST(httpRequestData);
|
||||||
// httpCode will be negative on error
|
// httpCode will be negative on error
|
||||||
if (httpCode > 0)
|
if (httpCode > 0)
|
||||||
{ // HTTP header has been send and Server response header has been handled
|
{ // HTTP header has been send and Server response header has been handled
|
||||||
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
|
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
|
||||||
|
|
||||||
// file found at server
|
// file found at server
|
||||||
if (httpCode == HTTP_CODE_OK) {
|
if (httpCode == HTTP_CODE_OK)
|
||||||
|
{
|
||||||
String payload = http.getString();
|
String payload = http.getString();
|
||||||
retVal = true;
|
retVal = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
postedFailed++;
|
||||||
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
|
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
|
||||||
}
|
}
|
||||||
http.end();
|
http.end();
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update Gas info
|
||||||
|
|
||||||
void UpdateGas()
|
void UpdateGas()
|
||||||
{
|
{
|
||||||
//sends over the gas setting to domoticz
|
if (prevGAS != mGAS)
|
||||||
if(prevGAS!=mGAS)
|
|
||||||
{
|
{
|
||||||
char sValue[10];
|
char sValue[10];
|
||||||
sprintf(sValue, "%d", mGAS);
|
sprintf(sValue, "%d", mGAS);
|
||||||
if(SendToDomo(domoticzGasIdx, 0, sValue))
|
if (Send(gasIdx, 0, sValue))
|
||||||
prevGAS=mGAS;
|
prevGAS = mGAS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update Electricity info
|
||||||
void UpdateElectricity()
|
void UpdateElectricity()
|
||||||
{
|
{
|
||||||
char sValue[255];
|
char sValue[255];
|
||||||
sprintf(sValue, "%d;%d;%d;%d;%d;%d", mEVLT, mEVHT, mEOLT, mEOHT, mEAV, mEAT);
|
sprintf(sValue, "%d;%d;%d;%d;%d;%d", mEVLT, mEVHT, mEOLT, mEOHT, mEAV, mEAT);
|
||||||
SendToDomo(domoticzEneryIdx, 0, sValue);
|
Send(energyIdx, 0, sValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if value is number
|
||||||
bool isNumber(char* res, int len) {
|
bool isNumber(char *res, int len)
|
||||||
for (int i = 0; i < len; i++) {
|
{
|
||||||
if (((res[i] < '0') || (res[i] > '9')) && (res[i] != '.' && res[i] != 0)) {
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
if (((res[i] < '0') || (res[i] > '9')) && (res[i] != '.' && res[i] != 0))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FindCharInArrayRev(char array[], char c, int len) {
|
// Find char in array
|
||||||
for (int i = len - 1; i >= 0; i--) {
|
int FindCharInArrayRev(char array[], char c, int len)
|
||||||
if (array[i] == c) {
|
{
|
||||||
|
for (int i = len - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (array[i] == c)
|
||||||
|
{
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if value is valid
|
||||||
long getValidVal(long valNew, long valOld, long maxDiffer)
|
long getValidVal(long valNew, long valOld, long maxDiffer)
|
||||||
{
|
{
|
||||||
//check if the incoming value is valid
|
//check if the incoming value is valid
|
||||||
if(valOld > 0 && ((valNew - valOld > maxDiffer) && (valOld - valNew > maxDiffer)))
|
if (valOld > 0 && ((valNew - valOld > maxDiffer) && (valOld - valNew > maxDiffer)))
|
||||||
return valOld;
|
return valOld;
|
||||||
return valNew;
|
return valNew;
|
||||||
}
|
}
|
||||||
|
|
||||||
long getValue(char* buffer, int maxlen) {
|
// Get value from char buffer
|
||||||
|
long getValue(char *buffer, int maxlen)
|
||||||
|
{
|
||||||
int s = FindCharInArrayRev(buffer, '(', maxlen - 2);
|
int s = FindCharInArrayRev(buffer, '(', maxlen - 2);
|
||||||
if (s < 8) return 0;
|
if (s < 8)
|
||||||
if (s > 32) s = 32;
|
return 0;
|
||||||
|
if (s > 32)
|
||||||
|
s = 32;
|
||||||
int l = FindCharInArrayRev(buffer, '*', maxlen - 2) - s - 1;
|
int l = FindCharInArrayRev(buffer, '*', maxlen - 2) - s - 1;
|
||||||
if (l < 4) return 0;
|
if (l < 4)
|
||||||
if (l > 12) return 0;
|
return 0;
|
||||||
|
if (l > 12)
|
||||||
|
return 0;
|
||||||
char res[16];
|
char res[16];
|
||||||
memset(res, 0, sizeof(res));
|
memset(res, 0, sizeof(res));
|
||||||
|
|
||||||
if (strncpy(res, buffer + s + 1, l)) {
|
if (strncpy(res, buffer + s + 1, l))
|
||||||
if (isNumber(res, l)) {
|
{
|
||||||
|
if (isNumber(res, l))
|
||||||
|
{
|
||||||
return (1000 * atof(res));
|
return (1000 * atof(res));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool decodeTelegram(int len) {
|
// Decode P1 telegram
|
||||||
|
bool decodeTelegram(int len)
|
||||||
|
{
|
||||||
//need to check for start
|
//need to check for start
|
||||||
int startChar = FindCharInArrayRev(telegram, '/', len);
|
int startChar = FindCharInArrayRev(telegram, '/', len);
|
||||||
int endChar = FindCharInArrayRev(telegram, '!', len);
|
int endChar = FindCharInArrayRev(telegram, '!', len);
|
||||||
bool validCRCFound = false;
|
bool validCRCFound = false;
|
||||||
if(startChar>=0)
|
if (startChar >= 0)
|
||||||
{
|
{
|
||||||
//start found. Reset CRC calculation
|
//start found. Reset CRC calculation
|
||||||
currentCRC=CRC16(0x0000,(unsigned char *) telegram+startChar, len-startChar);
|
currentCRC = CRC16(0x0000, (unsigned char *)telegram + startChar, len - startChar);
|
||||||
if(outputOnSerial)
|
if (outputOnSerial)
|
||||||
{
|
{
|
||||||
for(int cnt=startChar; cnt<len-startChar;cnt++)
|
for (int cnt = startChar; cnt < len - startChar; cnt++)
|
||||||
Serial.print(telegram[cnt]);
|
Serial.print(telegram[cnt]);
|
||||||
}
|
}
|
||||||
//Serial.println("Start found!");
|
Serial.println("Start found!");
|
||||||
|
telegramsTotal++;
|
||||||
}
|
}
|
||||||
else if(endChar>=0)
|
else if (endChar >= 0)
|
||||||
{
|
{
|
||||||
//add to crc calc
|
//add to crc calc
|
||||||
currentCRC=CRC16(currentCRC,(unsigned char*)telegram+endChar, 1);
|
currentCRC = CRC16(currentCRC, (unsigned char *)telegram + endChar, 1);
|
||||||
char messageCRC[5];
|
char messageCRC[5];
|
||||||
strncpy(messageCRC, telegram + endChar + 1, 4);
|
strncpy(messageCRC, telegram + endChar + 1, 4);
|
||||||
messageCRC[4]=0; //thanks to HarmOtten (issue 5)
|
messageCRC[4] = 0; //thanks to HarmOtten (issue 5)
|
||||||
if(outputOnSerial)
|
if (outputOnSerial)
|
||||||
{
|
{
|
||||||
for(int cnt=0; cnt<len;cnt++)
|
for (int cnt = 0; cnt < len; cnt++)
|
||||||
Serial.print(telegram[cnt]);
|
Serial.print(telegram[cnt]);
|
||||||
}
|
}
|
||||||
validCRCFound = (strtol(messageCRC, NULL, 16) == currentCRC);
|
validCRCFound = (strtol(messageCRC, NULL, 16) == currentCRC);
|
||||||
if(validCRCFound)
|
if (validCRCFound)
|
||||||
|
{
|
||||||
Serial.println("\nVALID CRC FOUND!");
|
Serial.println("\nVALID CRC FOUND!");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
Serial.println("\n===INVALID CRC FOUND!===");
|
{
|
||||||
|
Serial.println("\nINVALID CRC FOUND!");
|
||||||
|
telegramsInvalid++;
|
||||||
|
}
|
||||||
currentCRC = 0;
|
currentCRC = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
currentCRC=CRC16(currentCRC, (unsigned char*)telegram, len);
|
currentCRC = CRC16(currentCRC, (unsigned char *)telegram, len);
|
||||||
if(outputOnSerial)
|
if (outputOnSerial)
|
||||||
{
|
{
|
||||||
for(int cnt=0; cnt<len;cnt++)
|
for (int cnt = 0; cnt < len; cnt++)
|
||||||
Serial.print(telegram[cnt]);
|
Serial.print(telegram[cnt]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long val =0;
|
long val = 0;
|
||||||
long val2=0;
|
long val2 = 0;
|
||||||
// 1-0:1.8.1(000992.992*kWh)
|
// 1-0:1.8.1(000992.992*kWh)
|
||||||
// 1-0:1.8.1 = Elektra verbruik laag tarief (DSMR v4.0)
|
// 1-0:1.8.1 = Elektra verbruik laag tarief (DSMR v4.0)
|
||||||
if (strncmp(telegram, "1-0:1.8.1", strlen("1-0:1.8.1")) == 0)
|
if (strncmp(telegram, "1-0:1.8.1", strlen("1-0:1.8.1")) == 0)
|
||||||
mEVLT = getValue(telegram, len);
|
mEVLT = getValue(telegram, len);
|
||||||
|
|
||||||
|
|
||||||
// 1-0:1.8.2(000560.157*kWh)
|
// 1-0:1.8.2(000560.157*kWh)
|
||||||
// 1-0:1.8.2 = Elektra verbruik hoog tarief (DSMR v4.0)
|
// 1-0:1.8.2 = Elektra verbruik hoog tarief (DSMR v4.0)
|
||||||
if (strncmp(telegram, "1-0:1.8.2", strlen("1-0:1.8.2")) == 0)
|
if (strncmp(telegram, "1-0:1.8.2", strlen("1-0:1.8.2")) == 0)
|
||||||
mEVHT = getValue(telegram, len);
|
mEVHT = getValue(telegram, len);
|
||||||
|
|
||||||
|
|
||||||
// 1-0:2.8.1(000348.890*kWh)
|
// 1-0:2.8.1(000348.890*kWh)
|
||||||
// 1-0:2.8.1 = Elektra opbrengst laag tarief (DSMR v4.0)
|
// 1-0:2.8.1 = Elektra opbrengst laag tarief (DSMR v4.0)
|
||||||
if (strncmp(telegram, "1-0:2.8.1", strlen("1-0:2.8.1")) == 0)
|
if (strncmp(telegram, "1-0:2.8.1", strlen("1-0:2.8.1")) == 0)
|
||||||
mEOLT = getValue(telegram, len);
|
mEOLT = getValue(telegram, len);
|
||||||
|
|
||||||
|
|
||||||
// 1-0:2.8.2(000859.885*kWh)
|
// 1-0:2.8.2(000859.885*kWh)
|
||||||
// 1-0:2.8.2 = Elektra opbrengst hoog tarief (DSMR v4.0)
|
// 1-0:2.8.2 = Elektra opbrengst hoog tarief (DSMR v4.0)
|
||||||
if (strncmp(telegram, "1-0:2.8.2", strlen("1-0:2.8.2")) == 0)
|
if (strncmp(telegram, "1-0:2.8.2", strlen("1-0:2.8.2")) == 0)
|
||||||
mEOHT = getValue(telegram, len);
|
mEOHT = getValue(telegram, len);
|
||||||
|
|
||||||
|
|
||||||
// 1-0:1.7.0(00.424*kW) Actueel verbruik
|
// 1-0:1.7.0(00.424*kW) Actueel verbruik
|
||||||
// 1-0:2.7.0(00.000*kW) Actuele teruglevering
|
// 1-0:2.7.0(00.000*kW) Actuele teruglevering
|
||||||
// 1-0:1.7.x = Electricity consumption actual usage (DSMR v4.0)
|
// 1-0:1.7.x = Electricity consumption actual usage (DSMR v4.0)
|
||||||
@ -264,7 +536,6 @@ bool decodeTelegram(int len) {
|
|||||||
if (strncmp(telegram, "1-0:2.7.0", strlen("1-0:2.7.0")) == 0)
|
if (strncmp(telegram, "1-0:2.7.0", strlen("1-0:2.7.0")) == 0)
|
||||||
mEAT = getValue(telegram, len);
|
mEAT = getValue(telegram, len);
|
||||||
|
|
||||||
|
|
||||||
// 0-1:24.2.1(150531200000S)(00811.923*m3)
|
// 0-1:24.2.1(150531200000S)(00811.923*m3)
|
||||||
// 0-1:24.2.1 = Gas (DSMR v4.0) on Kaifa MA105 meter
|
// 0-1:24.2.1 = Gas (DSMR v4.0) on Kaifa MA105 meter
|
||||||
if (strncmp(telegram, "0-1:24.2.1", strlen("0-1:24.2.1")) == 0)
|
if (strncmp(telegram, "0-1:24.2.1", strlen("0-1:24.2.1")) == 0)
|
||||||
@ -273,15 +544,19 @@ bool decodeTelegram(int len) {
|
|||||||
return validCRCFound;
|
return validCRCFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
void readTelegram() {
|
// Read P1 telegram
|
||||||
if (mySerial.available()) {
|
void readTelegram()
|
||||||
|
{
|
||||||
|
if (mySerial.available())
|
||||||
|
{
|
||||||
memset(telegram, 0, sizeof(telegram));
|
memset(telegram, 0, sizeof(telegram));
|
||||||
while (mySerial.available()) {
|
while (mySerial.available())
|
||||||
|
{
|
||||||
int len = mySerial.readBytesUntil('\n', telegram, MAXLINELENGTH);
|
int len = mySerial.readBytesUntil('\n', telegram, MAXLINELENGTH);
|
||||||
telegram[len] = '\n';
|
telegram[len] = '\n';
|
||||||
telegram[len+1] = 0;
|
telegram[len + 1] = 0;
|
||||||
yield();
|
yield();
|
||||||
if(decodeTelegram(len+1))
|
if (decodeTelegram(len + 1))
|
||||||
{
|
{
|
||||||
UpdateElectricity();
|
UpdateElectricity();
|
||||||
UpdateGas();
|
UpdateGas();
|
||||||
@ -290,12 +565,18 @@ void readTelegram() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
if (hour() == 0 && minute() == 0 && second() == 0)
|
||||||
|
{
|
||||||
|
reboot();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
readTelegram();
|
readTelegram();
|
||||||
|
|
||||||
|
button.loop();
|
||||||
|
|
||||||
|
t.update();
|
||||||
|
|
||||||
ArduinoOTA.handle();
|
ArduinoOTA.handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
18
README.md
18
README.md
@ -1,15 +1,23 @@
|
|||||||
|
|
||||||
|
|
||||||
# P1-Meter-ESP8266
|
# P1-Meter-ESP8266
|
||||||
|
|
||||||
|
## Original code by [jantenhove on GitHub](https://github.com/jantenhove/P1-Meter-ESP8266), I altered the code to add a screen and make it work with my own server. The original code works with Domoticz, be sure to check it out!
|
||||||
|
|
||||||
Software for the ESP2866 that sends P1 smart meter data to Domoticz (with CRC checking and OTA firmware updates)
|
Software for the ESP2866 that sends P1 smart meter data to Domoticz (with CRC checking and OTA firmware updates)
|
||||||
|
|
||||||
### Installation instrucions
|
### Installation instrucions
|
||||||
- Make sure that your ESP8266 can be flashed from the Arduino environnment: https://github.com/esp8266/Arduino
|
|
||||||
- Install the SoftSerial library from: https://github.com/plerup/espsoftwareserial
|
* Make sure that your ESP8266 can be flashed from the Arduino environnment: https://github.com/esp8266/Arduino
|
||||||
- Place all files from this repository in a directory. Open the .ino file.
|
* Install the SoftSerial library from: https://github.com/plerup/espsoftwareserial
|
||||||
- Adjust WIFI, Domoticz and debug settings at the top of the file
|
* Place all files from this repository in a directory. Open the .ino file.
|
||||||
- Compile and flash
|
* Adjust WIFI, Domoticz and debug settings at the top of the file
|
||||||
|
* Compile and flash
|
||||||
|
|
||||||
### Connection of the P1 meter to the ESP8266
|
### Connection of the P1 meter to the ESP8266
|
||||||
|
|
||||||
You need to connect the smart meter with a RJ11 connector. This is the pinout to use
|
You need to connect the smart meter with a RJ11 connector. This is the pinout to use
|
||||||
|
|
||||||
![RJ11 P1 connetor](http://gejanssen.com/howto/Slimme-meter-uitlezen/RJ11-pinout.png)
|
![RJ11 P1 connetor](http://gejanssen.com/howto/Slimme-meter-uitlezen/RJ11-pinout.png)
|
||||||
|
|
||||||
Connect GND->GND on ESP, RTS->3.3V on ESP and RxD->any digital pin on ESP. In this sketch I use D5
|
Connect GND->GND on ESP, RTS->3.3V on ESP and RxD->any digital pin on ESP. In this sketch I use D5
|
||||||
|
Loading…
Reference in New Issue
Block a user