|
|
@ -19,7 +19,7 @@ |
|
|
|
#include <list> |
|
|
|
|
|
|
|
#include "plugins/zeroExport/lib/sml.h" |
|
|
|
|
|
|
|
#include "utils/DynamicJsonHandler.h" |
|
|
|
typedef struct { |
|
|
|
const unsigned char OBIS[6]; |
|
|
|
void (*Fn)(double &); |
|
|
@ -46,7 +46,7 @@ class powermeter { |
|
|
|
* @param *log |
|
|
|
* @returns void |
|
|
|
*/ |
|
|
|
bool setup(IApp *app, zeroExport_t *cfg, PubMqttType *mqtt, JsonObject *log) { |
|
|
|
bool setup(IApp *app, zeroExport_t *cfg, PubMqttType *mqtt, DynamicJsonHandler *log) { |
|
|
|
mApp = app; |
|
|
|
mCfg = cfg; |
|
|
|
mMqtt = mqtt; |
|
|
@ -84,7 +84,7 @@ class powermeter { |
|
|
|
switch (mCfg->groups[group].pm_type) { |
|
|
|
#if defined(ZEROEXPORT_POWERMETER_SHELLY) |
|
|
|
case zeroExportPowermeterType_t::Shelly: |
|
|
|
result = getPowermeterWattsShelly(*mLog, group, &power); |
|
|
|
result = getPowermeterWattsShelly(group, &power); |
|
|
|
break; |
|
|
|
#endif |
|
|
|
#if defined(ZEROEXPORT_POWERMETER_TASMOTA) |
|
|
@ -105,12 +105,12 @@ class powermeter { |
|
|
|
*/ |
|
|
|
case zeroExportPowermeterType_t::Tibber: |
|
|
|
if (mCfg->groups[group].pm_refresh < 3) mCfg->groups[group].pm_refresh = 3; |
|
|
|
result = getPowermeterWattsTibber(*mLog, group, &power); |
|
|
|
result = getPowermeterWattsTibber(group, &power); |
|
|
|
break; |
|
|
|
#endif |
|
|
|
#if defined(ZEROEXPORT_POWERMETER_SHRDZM) |
|
|
|
case zeroExportPowermeterType_t::Shrdzm: |
|
|
|
result = getPowermeterWattsShrdzm(*mLog, group, &power); |
|
|
|
result = getPowermeterWattsShrdzm(group, &power); |
|
|
|
break; |
|
|
|
#endif |
|
|
|
} |
|
|
@ -118,7 +118,7 @@ class powermeter { |
|
|
|
if (result) { |
|
|
|
bufferWrite(power, group); |
|
|
|
mCfg->groups[group].power = power; |
|
|
|
|
|
|
|
|
|
|
|
// MQTT - Powermeter
|
|
|
|
/// BUG: 002 Anfang - Muss dieser Teil raus? Führt er zu abstürzen wie BUG 001?
|
|
|
|
if (mMqtt->isConnected()) { |
|
|
@ -239,7 +239,7 @@ class powermeter { |
|
|
|
|
|
|
|
bufferWrite(power, group); |
|
|
|
mCfg->groups[group].power = power; // TODO: join two sites together (PM & MQTT)
|
|
|
|
|
|
|
|
|
|
|
|
// MQTT - Powermeter
|
|
|
|
/// BUG: 001 Anfang - Dieser Teil ist deaktiviert weil er zu abstürzen der DTU führt
|
|
|
|
// if (mCfg->debug) {
|
|
|
@ -280,7 +280,7 @@ class powermeter { |
|
|
|
|
|
|
|
zeroExport_t *mCfg; |
|
|
|
PubMqttType *mMqtt = nullptr; |
|
|
|
JsonObject *mLog; |
|
|
|
DynamicJsonHandler* mLog; |
|
|
|
IApp *mApp = nullptr; |
|
|
|
|
|
|
|
unsigned long mPreviousTsp = millis(); |
|
|
@ -294,7 +294,7 @@ class powermeter { |
|
|
|
/** setHeader
|
|
|
|
* |
|
|
|
*/ |
|
|
|
void setHeader(HTTPClient *h) { |
|
|
|
void setHeader(HTTPClient *h, String auth = "", u8_t realm = NULL) { |
|
|
|
h->setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); |
|
|
|
/// h->setUserAgent("Ahoy-Agent");
|
|
|
|
/// // TODO: Ahoy-0.8.850024-zero
|
|
|
@ -303,6 +303,43 @@ class powermeter { |
|
|
|
h->setTimeout(1000); |
|
|
|
h->addHeader("Content-Type", "application/json"); |
|
|
|
h->addHeader("Accept", "application/json"); |
|
|
|
|
|
|
|
/*
|
|
|
|
Shelly PM Mini Gen3 |
|
|
|
Shelly Plus 1PM |
|
|
|
Shelly Plus 2PM |
|
|
|
Shelly Pro 3EM - 120A |
|
|
|
Shelly Pro 4PM |
|
|
|
Shelly Pro Dual Cover / Shutter PM |
|
|
|
Shelly Pro 1PM |
|
|
|
Shelly Pro 2PM |
|
|
|
Shelly Pro EM - 50 |
|
|
|
Shelly Qubino Wave 1PM Mini |
|
|
|
Shelly Qubino Wave PM Mini |
|
|
|
Shelly Qubino Wave Shutter |
|
|
|
Shelly Qubino Wave 1PM |
|
|
|
Shelly Qubino Wave 2PM |
|
|
|
Shelly Qubino Wave Pro 1PM |
|
|
|
Shelly Qubino Wave Pro 2PM |
|
|
|
Shelly 3EM |
|
|
|
Shelly EM + 120A Clamp |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
/*if (auth != NULL && realm) http.addHeader("WWW-Authenticate", "Digest qop=\"auth\", realm=\"" + shellypro4pm-f008d1d8b8b8 + "\", nonce=\"60dc59c6\", algorithm=SHA-256");
|
|
|
|
else if (auth != NULL) http.addHeader("Authorization", "Basic " + auth);*/ |
|
|
|
/*
|
|
|
|
All Required: |
|
|
|
realm: string, device_id of the Shelly device. |
|
|
|
username: string, must be set to admin. |
|
|
|
nonce: number, random or pseudo-random number to prevent replay attacks, taken from the error message. |
|
|
|
cnonce: number, client nonce, random number generated by the client. |
|
|
|
response: string, encoding of the string <ha1> + ":" + <nonce> + ":" + <nc> + ":" + <cnonce> + ":" + "auth" + ":" + <ha2> in SHA256. |
|
|
|
ha1: string, <user>:<realm>:<password> encoded in SHA256 |
|
|
|
ha2: string, "dummy_method:dummy_uri" encoded in SHA256 |
|
|
|
algorithm: string, SHA-256. |
|
|
|
*/ |
|
|
|
} |
|
|
|
|
|
|
|
#if defined(ZEROEXPORT_POWERMETER_SHELLY) |
|
|
@ -312,13 +349,13 @@ class powermeter { |
|
|
|
* @param group |
|
|
|
* @returns true/false |
|
|
|
*/ |
|
|
|
bool getPowermeterWattsShelly(JsonObject logObj, uint8_t group, float *power) { |
|
|
|
logObj["mod"] = "getPowermeterWattsShelly"; |
|
|
|
bool getPowermeterWattsShelly(uint8_t group, float *power) { |
|
|
|
mLog->addProperty("mod", "getPowermeterWattsShelly"); |
|
|
|
|
|
|
|
setHeader(&http); |
|
|
|
|
|
|
|
String url = String("http://") + String(mCfg->groups[group].pm_src) + String("/") + String(mCfg->groups[group].pm_jsonPath); |
|
|
|
logObj["HTTP_URL"] = url; |
|
|
|
mLog->addProperty("HTTP_URL", url); |
|
|
|
|
|
|
|
http.begin(url); |
|
|
|
|
|
|
@ -327,7 +364,7 @@ class powermeter { |
|
|
|
DynamicJsonDocument doc(2048); |
|
|
|
DeserializationError error = deserializeJson(doc, http.getString()); |
|
|
|
if (error) { |
|
|
|
logObj["err"] = "deserializeJson: " + String(error.c_str()); |
|
|
|
mLog->addProperty("err", "deserializeJson: " + String(error.c_str())); |
|
|
|
return false; |
|
|
|
} else { |
|
|
|
switch (mCfg->groups[group].pm_target) { |
|
|
@ -395,7 +432,7 @@ class powermeter { |
|
|
|
* @param group |
|
|
|
* @returns true/false |
|
|
|
*/ |
|
|
|
bool getPowermeterWattsTasmota(JsonObject logObj, uint8_t group, float *power) { |
|
|
|
bool getPowermeterWattsTasmota(DynamicJsonHandler logObj, uint8_t group, float *power) { |
|
|
|
logObj["mod"] = "getPowermeterWattsTasmota"; |
|
|
|
/*
|
|
|
|
// TODO: nicht komplett
|
|
|
@ -467,7 +504,7 @@ class powermeter { |
|
|
|
* @param group |
|
|
|
* @returns true/false |
|
|
|
*/ |
|
|
|
bool getPowermeterWattsHichi(JsonObject logObj, uint8_t group, float *power) { |
|
|
|
bool getPowermeterWattsHichi(DynamicJsonHandler logObj, uint8_t group, float *power) { |
|
|
|
logObj["mod"] = "getPowermeterWattsHichi"; |
|
|
|
|
|
|
|
// Hier neuer Code - Anfang
|
|
|
@ -518,17 +555,20 @@ class powermeter { |
|
|
|
{{0x01, 0x00, 0x01, 0x08, 0x00, 0xff}, &smlOBISWh, &_powerMeterImport}, |
|
|
|
{{0x01, 0x00, 0x02, 0x08, 0x00, 0xff}, &smlOBISWh, &_powerMeterExport}}; |
|
|
|
|
|
|
|
bool getPowermeterWattsTibber(JsonObject logObj, uint8_t group, float *power) { |
|
|
|
/*
|
|
|
|
Daniel92: https://tibber.com/de/api/lookup/price-overview?postalCode=
|
|
|
|
Hab ich mal ausgelesen... hintendran die PLZ eingeben |
|
|
|
energy/todayHours/<aktuelleStunde>/priceIncludingVat |
|
|
|
*/ |
|
|
|
bool getPowermeterWattsTibber(uint8_t group, float *power) { |
|
|
|
bool result = false; |
|
|
|
|
|
|
|
logObj["mod"] = "getPowermeterWattsTibber"; |
|
|
|
mLog->addProperty("mod", "getPowermeterWattsTibber"); |
|
|
|
|
|
|
|
String auth = mCfg->groups[group].pm_pass; |
|
|
|
String url = String("http://") + mCfg->groups[group].pm_src + String("/") + String(mCfg->groups[group].pm_jsonPath); |
|
|
|
|
|
|
|
setHeader(&http); |
|
|
|
setHeader(&http, auth); |
|
|
|
http.begin(url); |
|
|
|
http.addHeader("Authorization", "Basic " + auth); |
|
|
|
|
|
|
|
if (http.GET() == HTTP_CODE_OK && http.getSize() > 0) { |
|
|
|
String myString = http.getString(); |
|
|
@ -571,8 +611,8 @@ class powermeter { |
|
|
|
* @TODO: Username & Passwort wird mittels base64 verschlüsselt. Dies wird für die Authentizierung benötigt. Wichtig diese im WebUI unkenntlich zu machen und base64 im eeprom zu speichern, statt klartext. |
|
|
|
* @TODO: Abfrage Interval einbauen. Info: Datei-Size kann auch mal 0-bytes sein? |
|
|
|
*/ |
|
|
|
bool getPowermeterWattsShrdzm(JsonObject logObj, uint8_t group, float *power) { |
|
|
|
logObj["mod"] = "getPowermeterWattsShrdzm"; |
|
|
|
bool getPowermeterWattsShrdzm(uint8_t group, float *power) { |
|
|
|
mLog->addProperty("mod", "getPowermeterWattsShrdzm"); |
|
|
|
|
|
|
|
setHeader(&http); |
|
|
|
|
|
|
@ -587,7 +627,7 @@ class powermeter { |
|
|
|
DynamicJsonDocument doc(512); |
|
|
|
DeserializationError error = deserializeJson(doc, http.getString()); |
|
|
|
if (error) { |
|
|
|
logObj["err"] = "deserializeJson: " + String(error.c_str()); |
|
|
|
mLog->addProperty("err", "deserializeJson: " + String(error.c_str())); |
|
|
|
return false; |
|
|
|
} else { |
|
|
|
if (doc.containsKey(F("16.7.0"))) { |
|
|
@ -606,8 +646,7 @@ class powermeter { |
|
|
|
*/ |
|
|
|
void bufferWrite(float raw, short group) { |
|
|
|
mPowermeterBuffer[group][mPowermeterBufferPos[group]] = raw; |
|
|
|
mPowermeterBufferPos[group]++; |
|
|
|
if (mPowermeterBufferPos[group] >= 5) mPowermeterBufferPos[group] = 0; |
|
|
|
mPowermeterBufferPos[group] = (mPowermeterBufferPos[group] + 1) % 5; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|