diff --git a/lib/Hoymiles/src/Hoymiles.cpp b/lib/Hoymiles/src/Hoymiles.cpp index eac5ab7..4745e19 100644 --- a/lib/Hoymiles/src/Hoymiles.cpp +++ b/lib/Hoymiles/src/Hoymiles.cpp @@ -32,7 +32,7 @@ void HoymilesClass::loop() iv->sendAlarmLogRequest(_radio.get()); // Fetch dev info (but first fetch stats) - if (iv->Statistics()->getLastUpdate() > 0 && iv->DevInfo()->getLastUpdate() == 0) { + if (iv->Statistics()->getLastUpdate() > 0 && (iv->DevInfo()->getLastUpdateAll() == 0 || iv->DevInfo()->getLastUpdateSample() == 0)) { Serial.println(F("Request device info")); iv->sendDevInfoRequest(_radio.get()); } diff --git a/lib/Hoymiles/src/commands/DevInfoAllCommand.cpp b/lib/Hoymiles/src/commands/DevInfoAllCommand.cpp index 0ac65d0..0b2099d 100644 --- a/lib/Hoymiles/src/commands/DevInfoAllCommand.cpp +++ b/lib/Hoymiles/src/commands/DevInfoAllCommand.cpp @@ -18,11 +18,11 @@ bool DevInfoAllCommand::handleResponse(InverterAbstract* inverter, fragment_t fr // Move all fragments into target buffer uint8_t offs = 0; - inverter->DevInfo()->clearBuffer(); + inverter->DevInfo()->clearBufferAll(); for (uint8_t i = 0; i < max_fragment_id; i++) { - inverter->DevInfo()->appendFragment(offs, fragment[i].fragment, fragment[i].len); + inverter->DevInfo()->appendFragmentAll(offs, fragment[i].fragment, fragment[i].len); offs += (fragment[i].len); } - inverter->DevInfo()->setLastUpdate(millis()); + inverter->DevInfo()->setLastUpdateAll(millis()); return true; } \ No newline at end of file diff --git a/lib/Hoymiles/src/commands/DevInfoSampleCommand.cpp b/lib/Hoymiles/src/commands/DevInfoSampleCommand.cpp new file mode 100644 index 0000000..58bec8c --- /dev/null +++ b/lib/Hoymiles/src/commands/DevInfoSampleCommand.cpp @@ -0,0 +1,28 @@ +#include "DevInfoSampleCommand.h" +#include "inverters/InverterAbstract.h" + +DevInfoSampleCommand::DevInfoSampleCommand(uint64_t target_address, uint64_t router_address, time_t time) + : MultiDataCommand(target_address, router_address) +{ + setTime(time); + setDataType(0x00); + setTimeout(200); +} + +bool DevInfoSampleCommand::handleResponse(InverterAbstract* inverter, fragment_t fragment[], uint8_t max_fragment_id) +{ + // Check CRC of whole payload + if (!MultiDataCommand::handleResponse(inverter, fragment, max_fragment_id)) { + return false; + } + + // Move all fragments into target buffer + uint8_t offs = 0; + inverter->DevInfo()->clearBufferSample(); + for (uint8_t i = 0; i < max_fragment_id; i++) { + inverter->DevInfo()->appendFragmentSample(offs, fragment[i].fragment, fragment[i].len); + offs += (fragment[i].len); + } + inverter->DevInfo()->setLastUpdateSample(millis()); + return true; +} \ No newline at end of file diff --git a/lib/Hoymiles/src/commands/DevInfoSampleCommand.h b/lib/Hoymiles/src/commands/DevInfoSampleCommand.h new file mode 100644 index 0000000..5cefd5e --- /dev/null +++ b/lib/Hoymiles/src/commands/DevInfoSampleCommand.h @@ -0,0 +1,10 @@ +#pragma once + +#include "MultiDataCommand.h" + +class DevInfoSampleCommand : public MultiDataCommand { +public: + DevInfoSampleCommand(uint64_t target_address = 0, uint64_t router_address = 0, time_t time = 0); + + virtual bool handleResponse(InverterAbstract* inverter, fragment_t fragment[], uint8_t max_fragment_id); +}; \ No newline at end of file diff --git a/lib/Hoymiles/src/inverters/HM_Abstract.cpp b/lib/Hoymiles/src/inverters/HM_Abstract.cpp index 52c47cc..df492f8 100644 --- a/lib/Hoymiles/src/inverters/HM_Abstract.cpp +++ b/lib/Hoymiles/src/inverters/HM_Abstract.cpp @@ -2,6 +2,7 @@ #include "HoymilesRadio.h" #include "commands/AlarmDataCommand.h" #include "commands/DevInfoAllCommand.h" +#include "commands/DevInfoSampleCommand.h" #include "commands/RealTimeRunDataCommand.h" HM_Abstract::HM_Abstract(uint64_t serial) @@ -59,9 +60,13 @@ bool HM_Abstract::sendDevInfoRequest(HoymilesRadio* radio) time_t now; time(&now); - DevInfoAllCommand* cmd = radio->enqueCommand(); - cmd->setTime(now); - cmd->setTargetAddress(serial()); + DevInfoAllCommand* cmdAll = radio->enqueCommand(); + cmdAll->setTime(now); + cmdAll->setTargetAddress(serial()); + + DevInfoSampleCommand* cmdSample = radio->enqueCommand(); + cmdSample->setTime(now); + cmdSample->setTargetAddress(serial()); return true; } \ No newline at end of file diff --git a/lib/Hoymiles/src/parser/DevInfoParser.cpp b/lib/Hoymiles/src/parser/DevInfoParser.cpp index 69a233c..76436be 100644 --- a/lib/Hoymiles/src/parser/DevInfoParser.cpp +++ b/lib/Hoymiles/src/parser/DevInfoParser.cpp @@ -1,44 +1,98 @@ #include "DevInfoParser.h" #include -void DevInfoParser::clearBuffer() +void DevInfoParser::clearBufferAll() { - memset(_payloadDevInfo, 0, DEV_INFO_SIZE); - _devInfoLength = 0; + memset(_payloadDevInfoAll, 0, DEV_INFO_SIZE); + _devInfoAllLength = 0; } -void DevInfoParser::appendFragment(uint8_t offset, uint8_t* payload, uint8_t len) +void DevInfoParser::appendFragmentAll(uint8_t offset, uint8_t* payload, uint8_t len) { if (offset + len > DEV_INFO_SIZE) { - Serial.printf("FATAL: (%s, %d) dev info packet too large for buffer\n", __FILE__, __LINE__); + Serial.printf("FATAL: (%s, %d) dev info all packet too large for buffer\n", __FILE__, __LINE__); return; } - memcpy(&_payloadDevInfo[offset], payload, len); - _devInfoLength += len; + memcpy(&_payloadDevInfoAll[offset], payload, len); + _devInfoAllLength += len; +} + +void DevInfoParser::clearBufferSample() +{ + memset(_payloadDevInfoSample, 0, DEV_INFO_SIZE); + _devInfoSampleLength = 0; +} + +void DevInfoParser::appendFragmentSample(uint8_t offset, uint8_t* payload, uint8_t len) +{ + if (offset + len > DEV_INFO_SIZE) { + Serial.printf("FATAL: (%s, %d) dev info Sample packet too large for buffer\n", __FILE__, __LINE__); + return; + } + memcpy(&_payloadDevInfoSample[offset], payload, len); + _devInfoSampleLength += len; +} + +uint32_t DevInfoParser::getLastUpdateAll() +{ + return _lastUpdateAll; +} + +void DevInfoParser::setLastUpdateAll(uint32_t lastUpdate) +{ + _lastUpdateAll = lastUpdate; + setLastUpdate(lastUpdate); +} + +uint32_t DevInfoParser::getLastUpdateSample() +{ + return _lastUpdateSample; +} + +void DevInfoParser::setLastUpdateSample(uint32_t lastUpdate) +{ + _lastUpdateSample = lastUpdate; + setLastUpdate(lastUpdate); } uint16_t DevInfoParser::getFwBuildVersion() { - return (((uint16_t)_payloadDevInfo[0]) << 8) | _payloadDevInfo[1]; + return (((uint16_t)_payloadDevInfoAll[0]) << 8) | _payloadDevInfoAll[1]; } time_t DevInfoParser::getFwBuildDateTime() { struct tm timeinfo = { 0 }; - timeinfo.tm_year = ((((uint16_t)_payloadDevInfo[2]) << 8) | _payloadDevInfo[3]) - 1900; + timeinfo.tm_year = ((((uint16_t)_payloadDevInfoAll[2]) << 8) | _payloadDevInfoAll[3]) - 1900; - timeinfo.tm_mon = ((((uint16_t)_payloadDevInfo[4]) << 8) | _payloadDevInfo[5]) / 100 - 1; - timeinfo.tm_mday = ((((uint16_t)_payloadDevInfo[4]) << 8) | _payloadDevInfo[5]) % 100; + timeinfo.tm_mon = ((((uint16_t)_payloadDevInfoAll[4]) << 8) | _payloadDevInfoAll[5]) / 100 - 1; + timeinfo.tm_mday = ((((uint16_t)_payloadDevInfoAll[4]) << 8) | _payloadDevInfoAll[5]) % 100; - timeinfo.tm_hour = ((((uint16_t)_payloadDevInfo[6]) << 8) | _payloadDevInfo[7]) / 100; - timeinfo.tm_min = ((((uint16_t)_payloadDevInfo[6]) << 8) | _payloadDevInfo[7]) % 100; + timeinfo.tm_hour = ((((uint16_t)_payloadDevInfoAll[6]) << 8) | _payloadDevInfoAll[7]) / 100; + timeinfo.tm_min = ((((uint16_t)_payloadDevInfoAll[6]) << 8) | _payloadDevInfoAll[7]) % 100; return timegm(&timeinfo); } uint16_t DevInfoParser::getFwBootloaderVersion() { - return (((uint16_t)_payloadDevInfo[8]) << 8) | _payloadDevInfo[9]; + return (((uint16_t)_payloadDevInfoAll[8]) << 8) | _payloadDevInfoAll[9]; +} + +uint32_t DevInfoParser::getHwPartNumber() +{ + uint16_t hwpn_h; + uint16_t hwpn_l; + + hwpn_h = (((uint16_t)_payloadDevInfoSample[2]) << 8) | _payloadDevInfoSample[3]; + hwpn_l = (((uint16_t)_payloadDevInfoSample[4]) << 8) | _payloadDevInfoSample[5]; + + return ((uint32_t)hwpn_h << 16) | ((uint32_t)hwpn_l); +} + +uint16_t DevInfoParser::getHwVersion() +{ + return (((uint16_t)_payloadDevInfoSample[6]) << 8) | _payloadDevInfoSample[7]; } /* struct tm to seconds since Unix epoch */ diff --git a/lib/Hoymiles/src/parser/DevInfoParser.h b/lib/Hoymiles/src/parser/DevInfoParser.h index 115fd53..f897d35 100644 --- a/lib/Hoymiles/src/parser/DevInfoParser.h +++ b/lib/Hoymiles/src/parser/DevInfoParser.h @@ -5,16 +5,34 @@ class DevInfoParser : public Parser { public: - void clearBuffer(); - void appendFragment(uint8_t offset, uint8_t* payload, uint8_t len); + void clearBufferAll(); + void appendFragmentAll(uint8_t offset, uint8_t* payload, uint8_t len); + + void clearBufferSample(); + void appendFragmentSample(uint8_t offset, uint8_t* payload, uint8_t len); + + uint32_t getLastUpdateAll(); + void setLastUpdateAll(uint32_t lastUpdate); + + uint32_t getLastUpdateSample(); + void setLastUpdateSample(uint32_t lastUpdate); uint16_t getFwBuildVersion(); time_t getFwBuildDateTime(); uint16_t getFwBootloaderVersion(); -private: - time_t timegm(struct tm *tm); + uint32_t getHwPartNumber(); + uint16_t getHwVersion(); - uint8_t _payloadDevInfo[DEV_INFO_SIZE]; - uint8_t _devInfoLength; +private: + time_t timegm(struct tm* tm); + + uint32_t _lastUpdateAll = 0; + uint32_t _lastUpdateSample = 0; + + uint8_t _payloadDevInfoAll[DEV_INFO_SIZE]; + uint8_t _devInfoAllLength; + + uint8_t _payloadDevInfoSample[DEV_INFO_SIZE]; + uint8_t _devInfoSampleLength; }; \ No newline at end of file