polish SMA HomeManager integration

* remove/comment unused variables to avoid compiler warnings

* cleanups: fix indention and style, make variable private, implement
  getters in header and make const.

* optimize message output: respect verbose logging setting. prefix
  output with SMA_HM.

* use newly introduced mutex in PowerMeterClass also for SMA HomeManager

* refactor code for readibility, unindent where possible.
This commit is contained in:
Bernhard Kirchen 2024-03-17 18:34:35 +01:00 committed by Bernhard Kirchen
parent f6680bd664
commit 45c7243937
3 changed files with 184 additions and 165 deletions

View File

@ -9,21 +9,28 @@
class SMA_HMClass { class SMA_HMClass {
public: public:
void init(Scheduler& scheduler); void init(Scheduler& scheduler, bool verboseLogging);
void loop(); void loop();
void event1(); void event1();
float getPowerTotal(); float getPowerTotal() const { return _powerMeterPower; }
float getPowerL1(); float getPowerL1() const { return _powerMeterL1; }
float getPowerL2(); float getPowerL2() const { return _powerMeterL2; }
float getPowerL3(); float getPowerL3() const { return _powerMeterL3; }
uint32_t serial = 0;
private: private:
uint32_t _lastUpdate = 0; void Soutput(int kanal, int index, int art, int tarif,
char const* name, float value, uint32_t timestamp);
uint8_t* decodeGroup(uint8_t* offset, uint16_t grouplen);
bool _verboseLogging = false;
float _powerMeterPower = 0.0; float _powerMeterPower = 0.0;
float _powerMeterL1 = 0.0; float _powerMeterL1 = 0.0;
float _powerMeterL2 = 0.0; float _powerMeterL2 = 0.0;
float _powerMeterL3 = 0.0; float _powerMeterL3 = 0.0;
uint32_t previousMillis = 0; uint32_t _previousMillis = 0;
uint32_t _serial = 0;
Task _loopTask; Task _loopTask;
}; };
extern SMA_HMClass SMA_HM; extern SMA_HMClass SMA_HM;

View File

@ -75,7 +75,7 @@ void PowerMeterClass::init(Scheduler& scheduler)
break; break;
case SOURCE_SMAHM2: case SOURCE_SMAHM2:
SMA_HM.init(scheduler); SMA_HM.init(scheduler, config.PowerMeter.VerboseLogging);
break; break;
} }
} }
@ -229,6 +229,7 @@ void PowerMeterClass::readPowerMeter()
} }
} }
else if (config.PowerMeter.Source == SOURCE_SMAHM2) { else if (config.PowerMeter.Source == SOURCE_SMAHM2) {
std::lock_guard<std::mutex> l(_mutex);
_powerMeter1Power = SMA_HM.getPowerL1(); _powerMeter1Power = SMA_HM.getPowerL1();
_powerMeter2Power = SMA_HM.getPowerL2(); _powerMeter2Power = SMA_HM.getPowerL2();
_powerMeter3Power = SMA_HM.getPowerL3(); _powerMeter3Power = SMA_HM.getPowerL3();

View File

@ -13,18 +13,22 @@ unsigned int multicastPort = 9522; // local port to listen on
IPAddress multicastIP(239, 12, 255, 254); IPAddress multicastIP(239, 12, 255, 254);
WiFiUDP SMAUdp; WiFiUDP SMAUdp;
const uint32_t interval = 1000; constexpr uint32_t interval = 1000;
static void Soutput(int kanal, int index, int art, int tarif, String Bezeichnung, double value, int timestamp){
MessageOutput.print(Bezeichnung);
MessageOutput.print('=');
MessageOutput.println(value);
}
SMA_HMClass SMA_HM; SMA_HMClass SMA_HM;
void SMA_HMClass::init(Scheduler& scheduler) void SMA_HMClass::Soutput(int kanal, int index, int art, int tarif,
char const* name, float value, uint32_t timestamp)
{ {
if (!_verboseLogging) { return; }
MessageOutput.printf("SMA_HM: %s = %.1f (timestamp %d)\r\n",
name, value, timestamp);
}
void SMA_HMClass::init(Scheduler& scheduler, bool verboseLogging)
{
_verboseLogging = verboseLogging;
scheduler.addTask(_loopTask); scheduler.addTask(_loopTask);
_loopTask.setCallback(std::bind(&SMA_HMClass::loop, this)); _loopTask.setCallback(std::bind(&SMA_HMClass::loop, this));
_loopTask.setIterations(TASK_FOREVER); _loopTask.setIterations(TASK_FOREVER);
@ -36,157 +40,164 @@ void SMA_HMClass::init(Scheduler& scheduler)
void SMA_HMClass::loop() void SMA_HMClass::loop()
{ {
uint32_t currentMillis = millis(); uint32_t currentMillis = millis();
if (currentMillis - previousMillis >= interval) { if (currentMillis - _previousMillis >= interval) {
previousMillis = currentMillis; _previousMillis = currentMillis;
event1(); event1();
} }
} }
void SMA_HMClass::event1() uint8_t* SMA_HMClass::decodeGroup(uint8_t* offset, uint16_t grouplen)
{ {
uint8_t buffer[1024]; float Pbezug = 0;
int packetSize = SMAUdp.parsePacket(); float BezugL1 = 0;
float Pbezug,BezugL1,BezugL2,BezugL3; float BezugL2 = 0;
Pbezug = 0; float BezugL3 = 0;
BezugL1 = 0; float Peinspeisung = 0;
BezugL2 = 0; float EinspeisungL1 = 0;
BezugL3 = 0; float EinspeisungL2 = 0;
float Peinspeisung,EinspeisungL1,EinspeisungL2,EinspeisungL3; float EinspeisungL3 = 0;
Peinspeisung = 0;
EinspeisungL1 = 0;
EinspeisungL2 = 0;
EinspeisungL3 = 0;
int count =0;
if (packetSize) {
int rSize = SMAUdp.read(buffer, 1024);
if (buffer[0] != 'S' || buffer[1] != 'M' || buffer[2] != 'A') {
MessageOutput.println("Not an SMA packet?");
return;
}
uint16_t grouplen;
uint16_t grouptag;
uint8_t* offset = buffer + 4;
do {
grouplen = (offset[0] << 8) + offset[1];
grouptag = (offset[2] << 8) + offset[3];
offset += 4;
if (grouplen == 0xffff) return;
if (grouptag == 0x02A0 && grouplen == 4) {
offset += 4;
} else if (grouptag == 0x0010) {
uint8_t* endOfGroup = offset + grouplen; uint8_t* endOfGroup = offset + grouplen;
uint16_t protocolID = (offset[0] << 8) + offset[1];
// not used: uint16_t protocolID = (offset[0] << 8) + offset[1];
offset += 2; offset += 2;
uint16_t susyID = (offset[0] << 8) + offset[1];
// not used: uint16_t susyID = (offset[0] << 8) + offset[1];
offset += 2; offset += 2;
uint32_t serial = (offset[0] << 24) + (offset[1] << 16) + (offset[2] << 8) + offset[3];
SMA_HM.serial=serial; _serial = (offset[0] << 24) + (offset[1] << 16) + (offset[2] << 8) + offset[3];
offset += 4; offset += 4;
uint32_t timestamp = (offset[0] << 24) + (offset[1] << 16) + (offset[2] << 8) + offset[3]; uint32_t timestamp = (offset[0] << 24) + (offset[1] << 16) + (offset[2] << 8) + offset[3];
offset += 4; offset += 4;
unsigned count = 0;
while (offset < endOfGroup) { while (offset < endOfGroup) {
uint8_t kanal = offset[0]; uint8_t kanal = offset[0];
uint8_t index = offset[1]; uint8_t index = offset[1];
uint8_t art = offset[2]; uint8_t art = offset[2];
uint8_t tarif = offset[3]; uint8_t tarif = offset[3];
offset += 4; offset += 4;
if (kanal == 144) {
// Optional: Versionsnummer auslesen... aber interessiert die?
offset += 4;
continue;
}
if (art == 8) { if (art == 8) {
uint64_t data = ((uint64_t)offset[0] << 56) +
((uint64_t)offset[1] << 48) +
((uint64_t)offset[2] << 40) +
((uint64_t)offset[3] << 32) +
((uint64_t)offset[4] << 24) +
((uint64_t)offset[5] << 16) +
((uint64_t)offset[6] << 8) +
offset[7];
offset += 8; offset += 8;
} else if (art == 4) { continue;
}
if (art == 4) {
uint32_t data = (offset[0] << 24) + uint32_t data = (offset[0] << 24) +
(offset[1] << 16) + (offset[1] << 16) +
(offset[2] << 8) + (offset[2] << 8) +
offset[3]; offset[3];
offset += 4; offset += 4;
switch (index) { switch (index) {
case (1): case (1):
Pbezug = data * 0.1; Pbezug = data * 0.1;
count +=1; ++count;
break; break;
case (2): case (2):
Peinspeisung = data * 0.1; Peinspeisung = data * 0.1;
count +=1; ++count;
break; break;
case (21): case (21):
BezugL1 = data * 0.1; BezugL1 = data * 0.1;
count +=1; ++count;
break; break;
case (22): case (22):
EinspeisungL1 = data * 0.1; EinspeisungL1 = data * 0.1;
count +=1; ++count;
break; break;
case (41): case (41):
BezugL2 = data * 0.1; BezugL2 = data * 0.1;
count +=1; ++count;
break; break;
case (42): case (42):
EinspeisungL2 = data * 0.1; EinspeisungL2 = data * 0.1;
count +=1; ++count;
break; break;
case (61): case (61):
BezugL3 = data * 0.1; BezugL3 = data * 0.1;
count +=1; ++count;
break; break;
case (62): case (62):
count +=1;
EinspeisungL3 = data * 0.1; EinspeisungL3 = data * 0.1;
++count;
break; break;
default: default:
break; // Wird nicht benötigt, wenn Statement(s) vorhanden sind break;
} }
if (count == 8){
if (count == 8) {
_powerMeterPower = Peinspeisung - Pbezug; _powerMeterPower = Peinspeisung - Pbezug;
_powerMeterL1=EinspeisungL1-BezugL1; _powerMeterL1 = EinspeisungL1 - BezugL1;
_powerMeterL2=EinspeisungL2-BezugL2; _powerMeterL2 = EinspeisungL2 - BezugL2;
_powerMeterL3=EinspeisungL3-BezugL3; _powerMeterL3 = EinspeisungL3 - BezugL3;
Soutput(kanal, index, art, tarif, "Leistung", _powerMeterPower, timestamp); Soutput(kanal, index, art, tarif, "Leistung", _powerMeterPower, timestamp);
Soutput(kanal, index, art, tarif, "Leistung L1", _powerMeterL1, timestamp); Soutput(kanal, index, art, tarif, "Leistung L1", _powerMeterL1, timestamp);
Soutput(kanal, index, art, tarif, "Leistung L2", _powerMeterL2, timestamp); Soutput(kanal, index, art, tarif, "Leistung L2", _powerMeterL2, timestamp);
Soutput(kanal, index, art, tarif, "Leistung L3", _powerMeterL3, timestamp); Soutput(kanal, index, art, tarif, "Leistung L3", _powerMeterL3, timestamp);
count=0; count = 0;
} }
} else if (kanal==144) {
// Optional: Versionsnummer auslesen... aber interessiert die? continue;
offset += 4; }
} else {
MessageOutput.printf("SMA_HM: Skipped unknown measurement: %d %d %d %d\r\n",
kanal, index, art, tarif);
offset += art; offset += art;
MessageOutput.println("Strange measurement skipped");
} }
return offset;
}
void SMA_HMClass::event1()
{
int packetSize = SMAUdp.parsePacket();
if (!packetSize) { return; }
uint8_t buffer[1024];
int rSize = SMAUdp.read(buffer, 1024);
if (buffer[0] != 'S' || buffer[1] != 'M' || buffer[2] != 'A') {
MessageOutput.println("SMA_HM: Not an SMA packet?");
return;
} }
} else if (grouptag == 0) {
uint16_t grouplen;
uint16_t grouptag;
uint8_t* offset = buffer + 4; // skips the header 'SMA\0'
do {
grouplen = (offset[0] << 8) + offset[1];
grouptag = (offset[2] << 8) + offset[3];
offset += 4;
if (grouplen == 0xffff) return;
if (grouptag == 0x02A0 && grouplen == 4) {
offset += 4;
continue;
}
if (grouptag == 0x0010) {
offset = decodeGroup(offset, grouplen);
continue;
}
if (grouptag == 0) {
// end marker // end marker
offset += grouplen; offset += grouplen;
} else { continue;
MessageOutput.print("unhandled group "); }
MessageOutput.print(grouptag);
MessageOutput.print(" with len="); MessageOutput.printf("SMA_HM: Unhandled group 0x%04x with length %d\r\n",
MessageOutput.println(grouplen); grouptag, grouplen);
offset += grouplen; offset += grouplen;
}
} while (grouplen > 0 && offset + 4 < buffer + rSize); } while (grouplen > 0 && offset + 4 < buffer + rSize);
}
}
float SMA_HMClass::getPowerTotal()
{
return _powerMeterPower;
}
float SMA_HMClass::getPowerL1()
{
return _powerMeterL1;
}
float SMA_HMClass::getPowerL2()
{
return _powerMeterL2;
}
float SMA_HMClass::getPowerL3()
{
return _powerMeterL3;
} }