BREAKING CHANGE: Prometheus API!
Added additional field to the prometheus api which identifies a channel by it's type. That means that e.g. channel 0 exists for type AC and DC. This commit also introduces a additional field in the statistics byte assignment table. This field identifies whether a channel is on the AC or DC side. MQTT and WebAPI is still compatible with the previous design.
This commit is contained in:
parent
6b36369b06
commit
d4c838a16e
@ -25,7 +25,7 @@ enum {
|
||||
const char* const stateClasses[] = { 0, "measurement", "total_increasing" };
|
||||
|
||||
typedef struct {
|
||||
uint8_t fieldId; // field id
|
||||
FieldId_t fieldId; // field id
|
||||
uint8_t deviceClsId; // device class
|
||||
uint8_t stateClsId; // state class
|
||||
} byteAssign_fieldDeviceClass_t;
|
||||
@ -57,7 +57,7 @@ public:
|
||||
|
||||
private:
|
||||
void publish(const String& subtopic, const String& payload);
|
||||
void publishField(std::shared_ptr<InverterAbstract> inv, uint8_t channel, byteAssign_fieldDeviceClass_t fieldType, bool clear = false);
|
||||
void publishField(std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, byteAssign_fieldDeviceClass_t fieldType, bool clear = false);
|
||||
void publishInverterButton(std::shared_ptr<InverterAbstract> inv, const char* caption, const char* icon, const char* category, const char* deviceClass, const char* subTopic, const char* payload);
|
||||
void publishInverterNumber(std::shared_ptr<InverterAbstract> inv, const char* caption, const char* icon, const char* category, const char* commandTopic, const char* stateTopic, const char* unitOfMeasure, int16_t min = 1, int16_t max = 100);
|
||||
void publishInverterBinarySensor(std::shared_ptr<InverterAbstract> inv, const char* caption, const char* subTopic, const char* payload_on, const char* payload_off);
|
||||
|
||||
@ -10,16 +10,16 @@ public:
|
||||
void init();
|
||||
void loop();
|
||||
|
||||
static String getTopic(std::shared_ptr<InverterAbstract> inv, uint8_t channel, uint8_t fieldId);
|
||||
static String getTopic(std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId);
|
||||
|
||||
private:
|
||||
void publishField(std::shared_ptr<InverterAbstract> inv, uint8_t channel, uint8_t fieldId);
|
||||
void publishField(std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId);
|
||||
void onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total);
|
||||
|
||||
uint32_t _lastPublishStats[INV_MAX_COUNT];
|
||||
uint32_t _lastPublish;
|
||||
|
||||
uint8_t _publishFields[14] = {
|
||||
FieldId_t _publishFields[14] = {
|
||||
FLD_UDC,
|
||||
FLD_IDC,
|
||||
FLD_PDC,
|
||||
|
||||
@ -12,7 +12,7 @@ public:
|
||||
private:
|
||||
void onPrometheusMetricsGet(AsyncWebServerRequest* request);
|
||||
|
||||
void addField(AsyncResponseStream* stream, String& serial, uint8_t idx, std::shared_ptr<InverterAbstract> inv, uint8_t channel, uint8_t fieldId, const char* channelName = NULL);
|
||||
void addField(AsyncResponseStream* stream, String& serial, uint8_t idx, std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId, const char* channelName = NULL);
|
||||
|
||||
AsyncWebServer* _server;
|
||||
};
|
||||
@ -13,7 +13,7 @@ public:
|
||||
|
||||
private:
|
||||
void generateJsonResponse(JsonVariant& root);
|
||||
void addField(JsonObject& root, uint8_t idx, std::shared_ptr<InverterAbstract> inv, uint8_t channel, uint8_t fieldId, String topic = "");
|
||||
void addField(JsonObject& root, uint8_t idx, std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId, String topic = "");
|
||||
void addTotalField(JsonObject& root, String name, float value, String unit, uint8_t digits);
|
||||
void onLivedataStatus(AsyncWebServerRequest* request);
|
||||
void onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);
|
||||
|
||||
@ -13,24 +13,26 @@ public:
|
||||
|
||||
private:
|
||||
const std::list<byteAssign_t> byteAssignment = {
|
||||
{ CH1, FLD_UDC, UNIT_V, 2, 2, 10, false, 1 },
|
||||
{ CH1, FLD_IDC, UNIT_A, 4, 2, 100, false, 2 },
|
||||
{ CH1, FLD_PDC, UNIT_W, 6, 2, 10, false, 1 },
|
||||
{ CH1, FLD_YD, UNIT_WH, 12, 2, 1, false, 0 },
|
||||
{ CH1, FLD_YT, UNIT_KWH, 8, 4, 1000, false, 3 },
|
||||
{ CH1, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH1, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_UDC, UNIT_V, 2, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_IDC, UNIT_A, 4, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 6, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 12, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 8, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ CH0, FLD_UAC, UNIT_V, 14, 2, 10, false, 1 },
|
||||
{ CH0, FLD_IAC, UNIT_A, 22, 2, 100, false, 2 },
|
||||
{ CH0, FLD_PAC, UNIT_W, 18, 2, 10, false, 1 },
|
||||
{ CH0, FLD_PRA, UNIT_VA, 20, 2, 10, false, 1 },
|
||||
{ CH0, FLD_F, UNIT_HZ, 16, 2, 100, false, 2 },
|
||||
{ CH0, FLD_PF, UNIT_NONE, 24, 2, 1000, false, 3 },
|
||||
{ CH0, FLD_T, UNIT_C, 26, 2, 10, true, 1 },
|
||||
{ CH0, FLD_EVT_LOG, UNIT_NONE, 28, 2, 1, false, 0 },
|
||||
{ CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 14, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 22, 2, 100, false, 2 },
|
||||
{ TYPE_AC, CH0, FLD_PAC, UNIT_W, 18, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_PRA, UNIT_VA, 20, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_F, UNIT_HZ, 16, 2, 100, false, 2 },
|
||||
{ TYPE_AC, CH0, FLD_PF, UNIT_NONE, 24, 2, 1000, false, 3 },
|
||||
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 26, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 28, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
};
|
||||
@ -12,31 +12,33 @@ public:
|
||||
|
||||
private:
|
||||
const std::list<byteAssign_t> byteAssignment = {
|
||||
{ CH1, FLD_UDC, UNIT_V, 2, 2, 10, false, 1 },
|
||||
{ CH1, FLD_IDC, UNIT_A, 4, 2, 100, false, 2 },
|
||||
{ CH1, FLD_PDC, UNIT_W, 6, 2, 10, false, 1 },
|
||||
{ CH1, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ CH1, FLD_YT, UNIT_KWH, 14, 4, 1000, false, 3 },
|
||||
{ CH1, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH1, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_UDC, UNIT_V, 2, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_IDC, UNIT_A, 4, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 6, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 14, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ CH2, FLD_UDC, UNIT_V, 8, 2, 10, false, 1 },
|
||||
{ CH2, FLD_IDC, UNIT_A, 10, 2, 100, false, 2 },
|
||||
{ CH2, FLD_PDC, UNIT_W, 12, 2, 10, false, 1 },
|
||||
{ CH2, FLD_YD, UNIT_WH, 24, 2, 1, false, 0 },
|
||||
{ CH2, FLD_YT, UNIT_KWH, 18, 4, 1000, false, 3 },
|
||||
{ CH2, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH2, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_UDC, UNIT_V, 8, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_IDC, UNIT_A, 10, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH1, FLD_PDC, UNIT_W, 12, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_YD, UNIT_WH, 24, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH1, FLD_YT, UNIT_KWH, 18, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH1, CMD_CALC, false, 3 },
|
||||
|
||||
{ CH0, FLD_UAC, UNIT_V, 26, 2, 10, false, 1 },
|
||||
{ CH0, FLD_IAC, UNIT_A, 34, 2, 100, false, 2 },
|
||||
{ CH0, FLD_PAC, UNIT_W, 30, 2, 10, false, 1 },
|
||||
{ CH0, FLD_PRA, UNIT_VA, 32, 2, 10, false, 1 },
|
||||
{ CH0, FLD_F, UNIT_HZ, 28, 2, 100, false, 2 },
|
||||
{ CH0, FLD_PF, UNIT_NONE, 36, 2, 1000, false, 3 },
|
||||
{ CH0, FLD_T, UNIT_C, 38, 2, 10, true, 1 },
|
||||
{ CH0, FLD_EVT_LOG, UNIT_NONE, 40, 2, 1, false, 0 },
|
||||
{ CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 26, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 34, 2, 100, false, 2 },
|
||||
{ TYPE_AC, CH0, FLD_PAC, UNIT_W, 30, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_PRA, UNIT_VA, 32, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_F, UNIT_HZ, 28, 2, 100, false, 2 },
|
||||
{ TYPE_AC, CH0, FLD_PF, UNIT_NONE, 36, 2, 1000, false, 3 },
|
||||
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 38, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 40, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
};
|
||||
@ -12,45 +12,47 @@ public:
|
||||
|
||||
private:
|
||||
const std::list<byteAssign_t> byteAssignment = {
|
||||
{ CH1, FLD_UDC, UNIT_V, 2, 2, 10, false, 1 },
|
||||
{ CH1, FLD_IDC, UNIT_A, 4, 2, 100, false, 2 },
|
||||
{ CH1, FLD_PDC, UNIT_W, 8, 2, 10, false, 1 },
|
||||
{ CH1, FLD_YD, UNIT_WH, 20, 2, 1, false, 0 },
|
||||
{ CH1, FLD_YT, UNIT_KWH, 12, 4, 1000, false, 3 },
|
||||
{ CH1, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH1, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_UDC, UNIT_V, 2, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_IDC, UNIT_A, 4, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH0, FLD_PDC, UNIT_W, 8, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH0, FLD_YD, UNIT_WH, 20, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH0, FLD_YT, UNIT_KWH, 12, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH0, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH0, CMD_CALC, false, 3 },
|
||||
|
||||
{ CH2, FLD_UDC, UNIT_V, CALC_UDC_CH, CH1, CMD_CALC, false, 1 },
|
||||
{ CH2, FLD_IDC, UNIT_A, 6, 2, 100, false, 2 },
|
||||
{ CH2, FLD_PDC, UNIT_W, 10, 2, 10, false, 1 },
|
||||
{ CH2, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ CH2, FLD_YT, UNIT_KWH, 16, 4, 1000, false, 3 },
|
||||
{ CH2, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH2, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_UDC, UNIT_V, CALC_UDC_CH, CH0, CMD_CALC, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_IDC, UNIT_A, 6, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH1, FLD_PDC, UNIT_W, 10, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH1, FLD_YD, UNIT_WH, 22, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH1, FLD_YT, UNIT_KWH, 16, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH1, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH1, CMD_CALC, false, 3 },
|
||||
|
||||
{ CH3, FLD_UDC, UNIT_V, 24, 2, 10, false, 1 },
|
||||
{ CH3, FLD_IDC, UNIT_A, 26, 2, 100, false, 2 },
|
||||
{ CH3, FLD_PDC, UNIT_W, 30, 2, 10, false, 1 },
|
||||
{ CH3, FLD_YD, UNIT_WH, 42, 2, 1, false, 0 },
|
||||
{ CH3, FLD_YT, UNIT_KWH, 34, 4, 1000, false, 3 },
|
||||
{ CH3, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH3, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_UDC, UNIT_V, 24, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_IDC, UNIT_A, 26, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH2, FLD_PDC, UNIT_W, 30, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH2, FLD_YD, UNIT_WH, 42, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH2, FLD_YT, UNIT_KWH, 34, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH2, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH2, CMD_CALC, false, 3 },
|
||||
|
||||
{ CH4, FLD_UDC, UNIT_V, CALC_UDC_CH, CH3, CMD_CALC, false, 1 },
|
||||
{ CH4, FLD_IDC, UNIT_A, 28, 2, 100, false, 2 },
|
||||
{ CH4, FLD_PDC, UNIT_W, 32, 2, 10, false, 1 },
|
||||
{ CH4, FLD_YD, UNIT_WH, 44, 2, 1, false, 0 },
|
||||
{ CH4, FLD_YT, UNIT_KWH, 38, 4, 1000, false, 3 },
|
||||
{ CH4, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH4, CMD_CALC, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_UDC, UNIT_V, CALC_UDC_CH, CH2, CMD_CALC, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_IDC, UNIT_A, 28, 2, 100, false, 2 },
|
||||
{ TYPE_DC, CH3, FLD_PDC, UNIT_W, 32, 2, 10, false, 1 },
|
||||
{ TYPE_DC, CH3, FLD_YD, UNIT_WH, 44, 2, 1, false, 0 },
|
||||
{ TYPE_DC, CH3, FLD_YT, UNIT_KWH, 38, 4, 1000, false, 3 },
|
||||
{ TYPE_DC, CH3, FLD_IRR, UNIT_PCT, CALC_IRR_CH, CH3, CMD_CALC, false, 3 },
|
||||
|
||||
{ CH0, FLD_UAC, UNIT_V, 46, 2, 10, false, 1 },
|
||||
{ CH0, FLD_IAC, UNIT_A, 54, 2, 100, false, 2 },
|
||||
{ CH0, FLD_PAC, UNIT_W, 50, 2, 10, false, 1 },
|
||||
{ CH0, FLD_PRA, UNIT_VA, 52, 2, 10, false, 1 },
|
||||
{ CH0, FLD_F, UNIT_HZ, 48, 2, 100, false, 2 },
|
||||
{ CH0, FLD_PF, UNIT_NONE, 56, 2, 1000, false, 3 },
|
||||
{ CH0, FLD_T, UNIT_C, 58, 2, 10, true, 1 },
|
||||
{ CH0, FLD_EVT_LOG, UNIT_NONE, 60, 2, 1, false, 0 },
|
||||
{ CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
{ TYPE_AC, CH0, FLD_UAC, UNIT_V, 46, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_IAC, UNIT_A, 54, 2, 100, false, 2 },
|
||||
{ TYPE_AC, CH0, FLD_PAC, UNIT_W, 50, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_PRA, UNIT_VA, 52, 2, 10, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_F, UNIT_HZ, 48, 2, 100, false, 2 },
|
||||
{ TYPE_AC, CH0, FLD_PF, UNIT_NONE, 56, 2, 1000, false, 3 },
|
||||
|
||||
{ TYPE_INV, CH0, FLD_T, UNIT_C, 58, 2, 10, true, 1 },
|
||||
{ TYPE_INV, CH0, FLD_EVT_LOG, UNIT_NONE, 60, 2, 1, false, 0 },
|
||||
|
||||
{ TYPE_AC, CH0, FLD_YD, UNIT_WH, CALC_YD_CH0, 0, CMD_CALC, false, 0 },
|
||||
{ TYPE_AC, CH0, FLD_YT, UNIT_KWH, CALC_YT_CH0, 0, CMD_CALC, false, 3 },
|
||||
{ TYPE_AC, CH0, FLD_PDC, UNIT_W, CALC_PDC_CH0, 0, CMD_CALC, false, 1 },
|
||||
{ TYPE_AC, CH0, FLD_EFF, UNIT_PCT, CALC_EFF_CH0, 0, CMD_CALC, false, 3 }
|
||||
};
|
||||
};
|
||||
@ -40,14 +40,14 @@ bool HM_Abstract::sendAlarmLogRequest(HoymilesRadio* radio, bool force)
|
||||
}
|
||||
|
||||
if (!force) {
|
||||
if (Statistics()->hasChannelFieldValue(CH0, FLD_EVT_LOG)) {
|
||||
if ((uint8_t)Statistics()->getChannelFieldValue(CH0, FLD_EVT_LOG) == _lastAlarmLogCnt) {
|
||||
if (Statistics()->hasChannelFieldValue(TYPE_INV, CH0, FLD_EVT_LOG)) {
|
||||
if ((uint8_t)Statistics()->getChannelFieldValue(TYPE_INV, CH0, FLD_EVT_LOG) == _lastAlarmLogCnt) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_lastAlarmLogCnt = (uint8_t)Statistics()->getChannelFieldValue(CH0, FLD_EVT_LOG);
|
||||
_lastAlarmLogCnt = (uint8_t)Statistics()->getChannelFieldValue(TYPE_INV, CH0, FLD_EVT_LOG);
|
||||
|
||||
time_t now;
|
||||
time(&now);
|
||||
|
||||
@ -60,11 +60,14 @@ const char* InverterAbstract::name()
|
||||
|
||||
bool InverterAbstract::isProducing()
|
||||
{
|
||||
if (!Statistics()->hasChannelFieldValue(CH0, FLD_PAC)) {
|
||||
return false;
|
||||
float totalAc = 0;
|
||||
for (auto& c : Statistics()->getChannelsByType(TYPE_AC)) {
|
||||
if (Statistics()->hasChannelFieldValue(TYPE_AC, c, FLD_PAC)) {
|
||||
totalAc += Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_PAC);
|
||||
}
|
||||
}
|
||||
|
||||
return Statistics()->getChannelFieldValue(CH0, FLD_PAC) > 0;
|
||||
return totalAc > 0;
|
||||
}
|
||||
|
||||
bool InverterAbstract::isReachable()
|
||||
|
||||
@ -49,19 +49,19 @@ void StatisticsParser::appendFragment(uint8_t offset, uint8_t* payload, uint8_t
|
||||
_statisticLength += len;
|
||||
}
|
||||
|
||||
const byteAssign_t* StatisticsParser::getAssignmentByChannelField(uint8_t channel, uint8_t fieldId)
|
||||
const byteAssign_t* StatisticsParser::getAssignmentByChannelField(ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId)
|
||||
{
|
||||
for (auto const& i : *_byteAssignment) {
|
||||
if (i.ch == channel && i.fieldId == fieldId) {
|
||||
if (i.type == type && i.ch == channel && i.fieldId == fieldId) {
|
||||
return &i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
float StatisticsParser::getChannelFieldValue(uint8_t channel, uint8_t fieldId)
|
||||
float StatisticsParser::getChannelFieldValue(ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId)
|
||||
{
|
||||
const byteAssign_t* pos = getAssignmentByChannelField(channel, fieldId);
|
||||
const byteAssign_t* pos = getAssignmentByChannelField(type, channel, fieldId);
|
||||
if (pos == NULL) {
|
||||
return 0;
|
||||
}
|
||||
@ -97,40 +97,54 @@ float StatisticsParser::getChannelFieldValue(uint8_t channel, uint8_t fieldId)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool StatisticsParser::hasChannelFieldValue(uint8_t channel, uint8_t fieldId)
|
||||
bool StatisticsParser::hasChannelFieldValue(ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId)
|
||||
{
|
||||
const byteAssign_t* pos = getAssignmentByChannelField(channel, fieldId);
|
||||
const byteAssign_t* pos = getAssignmentByChannelField(type, channel, fieldId);
|
||||
return pos != NULL;
|
||||
}
|
||||
|
||||
const char* StatisticsParser::getChannelFieldUnit(uint8_t channel, uint8_t fieldId)
|
||||
const char* StatisticsParser::getChannelFieldUnit(ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId)
|
||||
{
|
||||
const byteAssign_t* pos = getAssignmentByChannelField(channel, fieldId);
|
||||
const byteAssign_t* pos = getAssignmentByChannelField(type, channel, fieldId);
|
||||
return units[pos->unitId];
|
||||
}
|
||||
|
||||
const char* StatisticsParser::getChannelFieldName(uint8_t channel, uint8_t fieldId)
|
||||
const char* StatisticsParser::getChannelFieldName(ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId)
|
||||
{
|
||||
const byteAssign_t* pos = getAssignmentByChannelField(channel, fieldId);
|
||||
const byteAssign_t* pos = getAssignmentByChannelField(type, channel, fieldId);
|
||||
return fields[pos->fieldId];
|
||||
}
|
||||
|
||||
uint8_t StatisticsParser::getChannelFieldDigits(uint8_t channel, uint8_t fieldId)
|
||||
uint8_t StatisticsParser::getChannelFieldDigits(ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId)
|
||||
{
|
||||
const byteAssign_t* pos = getAssignmentByChannelField(channel, fieldId);
|
||||
const byteAssign_t* pos = getAssignmentByChannelField(type, channel, fieldId);
|
||||
return pos->digits;
|
||||
}
|
||||
|
||||
uint8_t StatisticsParser::getChannelCount()
|
||||
std::list<ChannelType_t> StatisticsParser::getChannelTypes()
|
||||
{
|
||||
uint8_t cnt = 0;
|
||||
for (auto const &b: *_byteAssignment) {
|
||||
if (b.ch > cnt) {
|
||||
cnt = b.ch;
|
||||
}
|
||||
return {
|
||||
TYPE_AC,
|
||||
TYPE_DC,
|
||||
TYPE_INV
|
||||
};
|
||||
}
|
||||
|
||||
return cnt;
|
||||
const char* StatisticsParser::getChannelTypeName(ChannelType_t type)
|
||||
{
|
||||
return channelsTypes[type];
|
||||
}
|
||||
|
||||
std::list<ChannelNum_t> StatisticsParser::getChannelsByType(ChannelType_t type)
|
||||
{
|
||||
std::list<ChannelNum_t> l;
|
||||
for (auto const& b : *_byteAssignment) {
|
||||
if (b.type == type) {
|
||||
l.push_back(b.ch);
|
||||
}
|
||||
}
|
||||
l.unique();
|
||||
return l;
|
||||
}
|
||||
|
||||
uint16_t StatisticsParser::getChannelMaxPower(uint8_t channel)
|
||||
@ -140,7 +154,7 @@ uint16_t StatisticsParser::getChannelMaxPower(uint8_t channel)
|
||||
|
||||
void StatisticsParser::setChannelMaxPower(uint8_t channel, uint16_t power)
|
||||
{
|
||||
if (channel < CH4) {
|
||||
if (channel < sizeof(_chanMaxPower) / sizeof(_chanMaxPower[0])) {
|
||||
_chanMaxPower[channel] = power;
|
||||
}
|
||||
}
|
||||
@ -163,8 +177,8 @@ uint32_t StatisticsParser::getRxFailureCount()
|
||||
static float calcYieldTotalCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
float yield = 0;
|
||||
for (uint8_t i = 1; i <= iv->getChannelCount(); i++) {
|
||||
yield += iv->getChannelFieldValue(i, FLD_YT);
|
||||
for (auto& channel : iv->getChannelsByType(TYPE_DC)) {
|
||||
yield += iv->getChannelFieldValue(TYPE_DC, channel, FLD_YT);
|
||||
}
|
||||
return yield;
|
||||
}
|
||||
@ -172,8 +186,8 @@ static float calcYieldTotalCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
static float calcYieldDayCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
float yield = 0;
|
||||
for (uint8_t i = 1; i <= iv->getChannelCount(); i++) {
|
||||
yield += iv->getChannelFieldValue(i, FLD_YD);
|
||||
for (auto& channel : iv->getChannelsByType(TYPE_DC)) {
|
||||
yield += iv->getChannelFieldValue(TYPE_DC, channel, FLD_YD);
|
||||
}
|
||||
return yield;
|
||||
}
|
||||
@ -181,14 +195,14 @@ static float calcYieldDayCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
// arg0 = channel of source
|
||||
static float calcUdcCh(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
return iv->getChannelFieldValue(arg0, FLD_UDC);
|
||||
return iv->getChannelFieldValue(TYPE_DC, static_cast<ChannelNum_t>(arg0), FLD_UDC);
|
||||
}
|
||||
|
||||
static float calcPowerDcCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
float dcPower = 0;
|
||||
for (uint8_t i = 1; i <= iv->getChannelCount(); i++) {
|
||||
dcPower += iv->getChannelFieldValue(i, FLD_PDC);
|
||||
for (auto& channel : iv->getChannelsByType(TYPE_DC)) {
|
||||
dcPower += iv->getChannelFieldValue(TYPE_DC, channel, FLD_PDC);
|
||||
}
|
||||
return dcPower;
|
||||
}
|
||||
@ -196,15 +210,19 @@ static float calcPowerDcCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
// arg0 = channel
|
||||
static float calcEffiencyCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
float acPower = iv->getChannelFieldValue(CH0, FLD_PAC);
|
||||
float dcPower = 0;
|
||||
for (uint8_t i = 1; i <= iv->getChannelCount(); i++) {
|
||||
dcPower += iv->getChannelFieldValue(i, FLD_PDC);
|
||||
float acPower = 0;
|
||||
for (auto& channel : iv->getChannelsByType(TYPE_AC)) {
|
||||
acPower += iv->getChannelFieldValue(TYPE_AC, channel, FLD_PAC);
|
||||
}
|
||||
|
||||
float dcPower = 0;
|
||||
for (auto& channel : iv->getChannelsByType(TYPE_DC)) {
|
||||
dcPower += iv->getChannelFieldValue(TYPE_DC, channel, FLD_PDC);
|
||||
}
|
||||
|
||||
if (dcPower > 0) {
|
||||
return acPower / dcPower * 100.0f;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
@ -212,8 +230,8 @@ static float calcEffiencyCh0(StatisticsParser* iv, uint8_t arg0)
|
||||
static float calcIrradiation(StatisticsParser* iv, uint8_t arg0)
|
||||
{
|
||||
if (NULL != iv) {
|
||||
if (iv->getChannelMaxPower(arg0 - 1) > 0)
|
||||
return iv->getChannelFieldValue(arg0, FLD_PDC) / iv->getChannelMaxPower(arg0 - 1) * 100.0f;
|
||||
if (iv->getChannelMaxPower(arg0) > 0)
|
||||
return iv->getChannelFieldValue(TYPE_DC, static_cast<ChannelNum_t>(arg0), FLD_PDC) / iv->getChannelMaxPower(arg0) * 100.0f;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
#define STATISTIC_PACKET_SIZE (4 * 16)
|
||||
|
||||
// units
|
||||
enum {
|
||||
enum UnitId_t {
|
||||
UNIT_V = 0,
|
||||
UNIT_A,
|
||||
UNIT_W,
|
||||
@ -23,7 +23,7 @@ enum {
|
||||
const char* const units[] = { "V", "A", "W", "Wh", "kWh", "Hz", "°C", "%", "var", "" };
|
||||
|
||||
// field types
|
||||
enum {
|
||||
enum FieldId_t {
|
||||
FLD_UDC = 0,
|
||||
FLD_IDC,
|
||||
FLD_PDC,
|
||||
@ -55,7 +55,7 @@ enum {
|
||||
enum { CMD_CALC = 0xffff };
|
||||
|
||||
// CH0 is default channel (freq, ac, temp)
|
||||
enum {
|
||||
enum ChannelNum_t {
|
||||
CH0 = 0,
|
||||
CH1,
|
||||
CH2,
|
||||
@ -63,10 +63,18 @@ enum {
|
||||
CH4
|
||||
};
|
||||
|
||||
enum ChannelType_t {
|
||||
TYPE_AC = 0,
|
||||
TYPE_DC,
|
||||
TYPE_INV
|
||||
};
|
||||
const char* const channelsTypes[] = { "AC", "DC", "INV" };
|
||||
|
||||
typedef struct {
|
||||
uint8_t ch; // channel 0 - 4
|
||||
uint8_t fieldId; // field id
|
||||
uint8_t unitId; // uint id
|
||||
ChannelType_t type;
|
||||
ChannelNum_t ch; // channel 0 - 4
|
||||
FieldId_t fieldId; // field id
|
||||
UnitId_t unitId; // uint id
|
||||
uint8_t start; // pos of first byte in buffer
|
||||
uint8_t num; // number of bytes in buffer
|
||||
uint16_t div; // divisor / calc command
|
||||
@ -81,14 +89,16 @@ public:
|
||||
|
||||
void setByteAssignment(const std::list<byteAssign_t>* byteAssignment);
|
||||
|
||||
const byteAssign_t* getAssignmentByChannelField(uint8_t channel, uint8_t fieldId);
|
||||
float getChannelFieldValue(uint8_t channel, uint8_t fieldId);
|
||||
bool hasChannelFieldValue(uint8_t channel, uint8_t fieldId);
|
||||
const char* getChannelFieldUnit(uint8_t channel, uint8_t fieldId);
|
||||
const char* getChannelFieldName(uint8_t channel, uint8_t fieldId);
|
||||
uint8_t getChannelFieldDigits(uint8_t channel, uint8_t fieldId);
|
||||
const byteAssign_t* getAssignmentByChannelField(ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId);
|
||||
float getChannelFieldValue(ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId);
|
||||
bool hasChannelFieldValue(ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId);
|
||||
const char* getChannelFieldUnit(ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId);
|
||||
const char* getChannelFieldName(ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId);
|
||||
uint8_t getChannelFieldDigits(ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId);
|
||||
|
||||
uint8_t getChannelCount();
|
||||
std::list<ChannelType_t> getChannelTypes();
|
||||
const char* getChannelTypeName(ChannelType_t type);
|
||||
std::list<ChannelNum_t> getChannelsByType(ChannelType_t type);
|
||||
|
||||
uint16_t getChannelMaxPower(uint8_t channel);
|
||||
void setChannelMaxPower(uint8_t channel, uint16_t power);
|
||||
|
||||
@ -37,7 +37,8 @@ std::map<DisplayType_t, std::function<U8G2*(uint8_t, uint8_t, uint8_t, uint8_t)>
|
||||
};
|
||||
|
||||
DisplayGraphicClass::DisplayGraphicClass()
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
DisplayGraphicClass::~DisplayGraphicClass()
|
||||
{
|
||||
@ -126,9 +127,11 @@ void DisplayGraphicClass::loop()
|
||||
isprod++;
|
||||
}
|
||||
|
||||
totalPower += inv->Statistics()->getChannelFieldValue(CH0, FLD_PAC);
|
||||
totalYieldDay += inv->Statistics()->getChannelFieldValue(CH0, FLD_YD);
|
||||
totalYieldTotal += inv->Statistics()->getChannelFieldValue(CH0, FLD_YT);
|
||||
for (auto& c : inv->Statistics()->getChannelsByType(TYPE_AC)) {
|
||||
totalPower += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_PAC);
|
||||
totalYieldDay += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_YD);
|
||||
totalYieldTotal += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_YT);
|
||||
}
|
||||
}
|
||||
|
||||
_display->clearBuffer();
|
||||
|
||||
@ -65,13 +65,15 @@ void MqttHandleHassClass::publishConfig()
|
||||
publishInverterBinarySensor(inv, "Producing", "status/producing", "1", "0");
|
||||
|
||||
// Loop all channels
|
||||
for (uint8_t c = 0; c <= inv->Statistics()->getChannelCount(); c++) {
|
||||
for (auto& t : inv->Statistics()->getChannelTypes()) {
|
||||
for (auto& c : inv->Statistics()->getChannelsByType(t)) {
|
||||
for (uint8_t f = 0; f < DEVICE_CLS_ASSIGN_LIST_LEN; f++) {
|
||||
bool clear = false;
|
||||
if (c > 0 && !config.Mqtt_Hass_IndividualPanels) {
|
||||
if (t == TYPE_DC && !config.Mqtt_Hass_IndividualPanels) {
|
||||
clear = true;
|
||||
}
|
||||
publishField(inv, c, deviceFieldAssignment[f], clear);
|
||||
publishField(inv, t, c, deviceFieldAssignment[f], clear);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,32 +81,40 @@ void MqttHandleHassClass::publishConfig()
|
||||
}
|
||||
}
|
||||
|
||||
void MqttHandleHassClass::publishField(std::shared_ptr<InverterAbstract> inv, uint8_t channel, byteAssign_fieldDeviceClass_t fieldType, bool clear)
|
||||
void MqttHandleHassClass::publishField(std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, byteAssign_fieldDeviceClass_t fieldType, bool clear)
|
||||
{
|
||||
if (!inv->Statistics()->hasChannelFieldValue(channel, fieldType.fieldId)) {
|
||||
if (!inv->Statistics()->hasChannelFieldValue(type, channel, fieldType.fieldId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String serial = inv->serialString();
|
||||
|
||||
String fieldName;
|
||||
if (channel == CH0 && fieldType.fieldId == FLD_PDC) {
|
||||
if (type == TYPE_AC && fieldType.fieldId == FLD_PDC) {
|
||||
fieldName = "PowerDC";
|
||||
} else {
|
||||
fieldName = inv->Statistics()->getChannelFieldName(channel, fieldType.fieldId);
|
||||
fieldName = inv->Statistics()->getChannelFieldName(type, channel, fieldType.fieldId);
|
||||
}
|
||||
|
||||
String chanNum;
|
||||
if (type == TYPE_DC) {
|
||||
// TODO(tbnobody)
|
||||
chanNum = static_cast<uint8_t>(channel) + 1;
|
||||
} else {
|
||||
chanNum = channel;
|
||||
}
|
||||
|
||||
String configTopic = "sensor/dtu_" + serial
|
||||
+ "/" + "ch" + String(channel) + "_" + fieldName
|
||||
+ "/" + "ch" + chanNum + "_" + fieldName
|
||||
+ "/config";
|
||||
|
||||
if (!clear) {
|
||||
String stateTopic = MqttSettings.getPrefix() + MqttHandleInverter.getTopic(inv, channel, fieldType.fieldId);
|
||||
String stateTopic = MqttSettings.getPrefix() + MqttHandleInverter.getTopic(inv, type, channel, fieldType.fieldId);
|
||||
const char* devCls = deviceClasses[fieldType.deviceClsId];
|
||||
const char* stateCls = stateClasses[fieldType.stateClsId];
|
||||
|
||||
String name;
|
||||
if (channel == CH0) {
|
||||
if (type != TYPE_DC) {
|
||||
name = String(inv->name()) + " " + fieldName;
|
||||
} else {
|
||||
name = String(inv->name()) + " CH" + String(channel) + " " + fieldName;
|
||||
@ -115,7 +125,7 @@ void MqttHandleHassClass::publishField(std::shared_ptr<InverterAbstract> inv, ui
|
||||
root[F("stat_t")] = stateTopic;
|
||||
root[F("uniq_id")] = serial + "_ch" + String(channel) + "_" + fieldName;
|
||||
|
||||
String unit_of_measure = inv->Statistics()->getChannelFieldUnit(channel, fieldType.fieldId);
|
||||
String unit_of_measure = inv->Statistics()->getChannelFieldUnit(type, channel, fieldType.fieldId);
|
||||
if (unit_of_measure != "") {
|
||||
root[F("unit_of_meas")] = unit_of_measure;
|
||||
}
|
||||
|
||||
@ -96,15 +96,18 @@ void MqttHandleInverterClass::loop()
|
||||
_lastPublishStats[i] = lastUpdate;
|
||||
|
||||
// Loop all channels
|
||||
for (uint8_t c = 0; c <= inv->Statistics()->getChannelCount(); c++) {
|
||||
if (c > 0) {
|
||||
for (auto& t : inv->Statistics()->getChannelTypes()) {
|
||||
for (auto& c : inv->Statistics()->getChannelsByType(t)) {
|
||||
if (t == TYPE_DC) {
|
||||
INVERTER_CONFIG_T* inv_cfg = Configuration.getInverterConfig(inv->serial());
|
||||
if (inv_cfg != nullptr) {
|
||||
MqttSettings.publish(inv->serialString() + "/" + String(c) + "/name", inv_cfg->channel[c - 1].Name);
|
||||
// TODO(tbnobody)
|
||||
MqttSettings.publish(inv->serialString() + "/" + String(static_cast<uint8_t>(c) + 1) + "/name", inv_cfg->channel[c].Name);
|
||||
}
|
||||
}
|
||||
for (uint8_t f = 0; f < sizeof(_publishFields); f++) {
|
||||
publishField(inv, c, _publishFields[f]);
|
||||
for (uint8_t f = 0; f < sizeof(_publishFields) / sizeof(FieldId_t); f++) {
|
||||
publishField(inv, t, c, _publishFields[f]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -116,31 +119,39 @@ void MqttHandleInverterClass::loop()
|
||||
}
|
||||
}
|
||||
|
||||
void MqttHandleInverterClass::publishField(std::shared_ptr<InverterAbstract> inv, uint8_t channel, uint8_t fieldId)
|
||||
void MqttHandleInverterClass::publishField(std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId)
|
||||
{
|
||||
String topic = getTopic(inv, channel, fieldId);
|
||||
String topic = getTopic(inv, type, channel, fieldId);
|
||||
if (topic == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
MqttSettings.publish(topic, String(inv->Statistics()->getChannelFieldValue(channel, fieldId)));
|
||||
MqttSettings.publish(topic, String(inv->Statistics()->getChannelFieldValue(type, channel, fieldId)));
|
||||
}
|
||||
|
||||
String MqttHandleInverterClass::getTopic(std::shared_ptr<InverterAbstract> inv, uint8_t channel, uint8_t fieldId)
|
||||
String MqttHandleInverterClass::getTopic(std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId)
|
||||
{
|
||||
if (!inv->Statistics()->hasChannelFieldValue(channel, fieldId)) {
|
||||
if (!inv->Statistics()->hasChannelFieldValue(type, channel, fieldId)) {
|
||||
return String("");
|
||||
}
|
||||
|
||||
String chanName;
|
||||
if (channel == 0 && fieldId == FLD_PDC) {
|
||||
if (type == TYPE_AC && fieldId == FLD_PDC) {
|
||||
chanName = "powerdc";
|
||||
} else {
|
||||
chanName = inv->Statistics()->getChannelFieldName(channel, fieldId);
|
||||
chanName = inv->Statistics()->getChannelFieldName(type, channel, fieldId);
|
||||
chanName.toLowerCase();
|
||||
}
|
||||
|
||||
return inv->serialString() + "/" + String(channel) + "/" + chanName;
|
||||
String chanNum;
|
||||
if (type == TYPE_DC) {
|
||||
// TODO(tbnobody)
|
||||
chanNum = static_cast<uint8_t>(channel) + 1;
|
||||
} else {
|
||||
chanNum = channel;
|
||||
}
|
||||
|
||||
return inv->serialString() + "/" + chanNum + "/" + chanName;
|
||||
}
|
||||
|
||||
void MqttHandleInverterClass::onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total)
|
||||
|
||||
@ -59,7 +59,7 @@ void WebApiInverterClass::onInverterList(AsyncWebServerRequest* request)
|
||||
max_channels = INV_MAX_CHAN_COUNT;
|
||||
} else {
|
||||
obj[F("type")] = inv->typeName();
|
||||
max_channels = inv->Statistics()->getChannelCount();
|
||||
max_channels = inv->Statistics()->getChannelsByType(TYPE_DC).size();
|
||||
}
|
||||
|
||||
JsonArray channel = obj.createNestedArray("channel");
|
||||
|
||||
@ -63,39 +63,48 @@ void WebApiPrometheusClass::onPrometheusMetricsGet(AsyncWebServerRequest* reques
|
||||
serial.c_str(), i, name, inv->Statistics()->getLastUpdate() / 1000);
|
||||
|
||||
// Loop all channels
|
||||
for (uint8_t c = 0; c <= inv->Statistics()->getChannelCount(); c++) {
|
||||
addField(stream, serial, i, inv, c, FLD_PAC);
|
||||
addField(stream, serial, i, inv, c, FLD_UAC);
|
||||
addField(stream, serial, i, inv, c, FLD_IAC);
|
||||
if (c == 0) {
|
||||
addField(stream, serial, i, inv, c, FLD_PDC, "PowerDC");
|
||||
for (auto& t : inv->Statistics()->getChannelTypes()) {
|
||||
for (auto& c : inv->Statistics()->getChannelsByType(t)) {
|
||||
addField(stream, serial, i, inv, t, c, FLD_PAC);
|
||||
addField(stream, serial, i, inv, t, c, FLD_UAC);
|
||||
addField(stream, serial, i, inv, t, c, FLD_IAC);
|
||||
if (t == TYPE_AC) {
|
||||
addField(stream, serial, i, inv, t, c, FLD_PDC, "PowerDC");
|
||||
} else {
|
||||
addField(stream, serial, i, inv, c, FLD_PDC);
|
||||
addField(stream, serial, i, inv, t, c, FLD_PDC);
|
||||
}
|
||||
addField(stream, serial, i, inv, t, c, FLD_UDC);
|
||||
addField(stream, serial, i, inv, t, c, FLD_IDC);
|
||||
addField(stream, serial, i, inv, t, c, FLD_YD);
|
||||
addField(stream, serial, i, inv, t, c, FLD_YT);
|
||||
addField(stream, serial, i, inv, t, c, FLD_F);
|
||||
addField(stream, serial, i, inv, t, c, FLD_T);
|
||||
addField(stream, serial, i, inv, t, c, FLD_PF);
|
||||
addField(stream, serial, i, inv, t, c, FLD_PRA);
|
||||
addField(stream, serial, i, inv, t, c, FLD_EFF);
|
||||
addField(stream, serial, i, inv, t, c, FLD_IRR);
|
||||
}
|
||||
addField(stream, serial, i, inv, c, FLD_UDC);
|
||||
addField(stream, serial, i, inv, c, FLD_IDC);
|
||||
addField(stream, serial, i, inv, c, FLD_YD);
|
||||
addField(stream, serial, i, inv, c, FLD_YT);
|
||||
addField(stream, serial, i, inv, c, FLD_F);
|
||||
addField(stream, serial, i, inv, c, FLD_T);
|
||||
addField(stream, serial, i, inv, c, FLD_PF);
|
||||
addField(stream, serial, i, inv, c, FLD_PRA);
|
||||
addField(stream, serial, i, inv, c, FLD_EFF);
|
||||
addField(stream, serial, i, inv, c, FLD_IRR);
|
||||
}
|
||||
}
|
||||
stream->addHeader(F("Cache-Control"), F("no-cache"));
|
||||
request->send(stream);
|
||||
}
|
||||
|
||||
void WebApiPrometheusClass::addField(AsyncResponseStream* stream, String& serial, uint8_t idx, std::shared_ptr<InverterAbstract> inv, uint8_t channel, uint8_t fieldId, const char* channelName)
|
||||
void WebApiPrometheusClass::addField(AsyncResponseStream* stream, String& serial, uint8_t idx, std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId, const char* channelName)
|
||||
{
|
||||
if (inv->Statistics()->hasChannelFieldValue(channel, fieldId)) {
|
||||
const char* chanName = (channelName == NULL) ? inv->Statistics()->getChannelFieldName(channel, fieldId) : channelName;
|
||||
if (idx == 0 && channel == 0) {
|
||||
stream->printf("# HELP opendtu_%s in %s\n", chanName, inv->Statistics()->getChannelFieldUnit(channel, fieldId));
|
||||
if (inv->Statistics()->hasChannelFieldValue(type, channel, fieldId)) {
|
||||
const char* chanName = (channelName == NULL) ? inv->Statistics()->getChannelFieldName(type, channel, fieldId) : channelName;
|
||||
if (idx == 0 && type == TYPE_AC && channel == 0) {
|
||||
stream->printf("# HELP opendtu_%s in %s\n", chanName, inv->Statistics()->getChannelFieldUnit(type, channel, fieldId));
|
||||
stream->printf("# TYPE opendtu_%s gauge\n", chanName);
|
||||
}
|
||||
stream->printf("opendtu_%s{serial=\"%s\",unit=\"%d\",name=\"%s\",channel=\"%d\"} %f\n", chanName, serial.c_str(), idx, inv->name(), channel, inv->Statistics()->getChannelFieldValue(channel, fieldId));
|
||||
stream->printf("opendtu_%s{serial=\"%s\",unit=\"%d\",name=\"%s\",type=\"%s\",channel=\"%d\"} %f\n",
|
||||
chanName,
|
||||
serial.c_str(),
|
||||
idx,
|
||||
inv->name(),
|
||||
inv->Statistics()->getChannelTypeName(type),
|
||||
channel,
|
||||
inv->Statistics()->getChannelFieldValue(type, channel, fieldId));
|
||||
}
|
||||
}
|
||||
@ -111,36 +111,39 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
||||
}
|
||||
|
||||
// Loop all channels
|
||||
for (uint8_t c = 0; c <= inv->Statistics()->getChannelCount(); c++) {
|
||||
if (c > 0) {
|
||||
for (auto& t : inv->Statistics()->getChannelTypes()) {
|
||||
for (auto& c : inv->Statistics()->getChannelsByType(t)) {
|
||||
if (t == TYPE_DC) {
|
||||
INVERTER_CONFIG_T* inv_cfg = Configuration.getInverterConfig(inv->serial());
|
||||
if (inv_cfg != nullptr) {
|
||||
invObject[String(c)][F("name")]["u"] = inv_cfg->channel[c - 1].Name;
|
||||
// TODO(tbnobody)
|
||||
invObject[String(static_cast<uint8_t>(c) + 1)][F("name")]["u"] = inv_cfg->channel[c].Name;
|
||||
}
|
||||
}
|
||||
addField(invObject, i, inv, c, FLD_PAC);
|
||||
addField(invObject, i, inv, c, FLD_UAC);
|
||||
addField(invObject, i, inv, c, FLD_IAC);
|
||||
if (c == 0) {
|
||||
addField(invObject, i, inv, c, FLD_PDC, F("Power DC"));
|
||||
addField(invObject, i, inv, t, c, FLD_PAC);
|
||||
addField(invObject, i, inv, t, c, FLD_UAC);
|
||||
addField(invObject, i, inv, t, c, FLD_IAC);
|
||||
if (t == TYPE_AC) {
|
||||
addField(invObject, i, inv, t, c, FLD_PDC, F("Power DC"));
|
||||
} else {
|
||||
addField(invObject, i, inv, c, FLD_PDC);
|
||||
addField(invObject, i, inv, t, c, FLD_PDC);
|
||||
}
|
||||
addField(invObject, i, inv, t, c, FLD_UDC);
|
||||
addField(invObject, i, inv, t, c, FLD_IDC);
|
||||
addField(invObject, i, inv, t, c, FLD_YD);
|
||||
addField(invObject, i, inv, t, c, FLD_YT);
|
||||
addField(invObject, i, inv, t, c, FLD_F);
|
||||
addField(invObject, i, inv, t, c, FLD_T);
|
||||
addField(invObject, i, inv, t, c, FLD_PF);
|
||||
addField(invObject, i, inv, t, c, FLD_PRA);
|
||||
addField(invObject, i, inv, t, c, FLD_EFF);
|
||||
if (t == TYPE_DC && inv->Statistics()->getChannelMaxPower(c) > 0) {
|
||||
addField(invObject, i, inv, t, c, FLD_IRR);
|
||||
}
|
||||
addField(invObject, i, inv, c, FLD_UDC);
|
||||
addField(invObject, i, inv, c, FLD_IDC);
|
||||
addField(invObject, i, inv, c, FLD_YD);
|
||||
addField(invObject, i, inv, c, FLD_YT);
|
||||
addField(invObject, i, inv, c, FLD_F);
|
||||
addField(invObject, i, inv, c, FLD_T);
|
||||
addField(invObject, i, inv, c, FLD_PF);
|
||||
addField(invObject, i, inv, c, FLD_PRA);
|
||||
addField(invObject, i, inv, c, FLD_EFF);
|
||||
if (c > 0 && inv->Statistics()->getChannelMaxPower(c - 1) > 0) {
|
||||
addField(invObject, i, inv, c, FLD_IRR);
|
||||
}
|
||||
}
|
||||
|
||||
if (inv->Statistics()->hasChannelFieldValue(CH0, FLD_EVT_LOG)) {
|
||||
if (inv->Statistics()->hasChannelFieldValue(TYPE_INV, CH0, FLD_EVT_LOG)) {
|
||||
invObject[F("events")] = inv->EventLog()->getEntryCount();
|
||||
} else {
|
||||
invObject[F("events")] = -1;
|
||||
@ -150,9 +153,11 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
||||
_newestInverterTimestamp = inv->Statistics()->getLastUpdate();
|
||||
}
|
||||
|
||||
totalPower += inv->Statistics()->getChannelFieldValue(CH0, FLD_PAC);
|
||||
totalYieldDay += inv->Statistics()->getChannelFieldValue(CH0, FLD_YD);
|
||||
totalYieldTotal += inv->Statistics()->getChannelFieldValue(CH0, FLD_YT);
|
||||
for (auto& c : inv->Statistics()->getChannelsByType(TYPE_AC)) {
|
||||
totalPower += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_PAC);
|
||||
totalYieldDay += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_YD);
|
||||
totalYieldTotal += inv->Statistics()->getChannelFieldValue(TYPE_AC, c, FLD_YT);
|
||||
}
|
||||
}
|
||||
|
||||
JsonObject totalObj = root.createNestedObject("total");
|
||||
@ -172,18 +177,25 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
||||
}
|
||||
}
|
||||
|
||||
void WebApiWsLiveClass::addField(JsonObject& root, uint8_t idx, std::shared_ptr<InverterAbstract> inv, uint8_t channel, uint8_t fieldId, String topic)
|
||||
void WebApiWsLiveClass::addField(JsonObject& root, uint8_t idx, std::shared_ptr<InverterAbstract> inv, ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId, String topic)
|
||||
{
|
||||
if (inv->Statistics()->hasChannelFieldValue(channel, fieldId)) {
|
||||
if (inv->Statistics()->hasChannelFieldValue(type, channel, fieldId)) {
|
||||
String chanName;
|
||||
if (topic == "") {
|
||||
chanName = inv->Statistics()->getChannelFieldName(channel, fieldId);
|
||||
chanName = inv->Statistics()->getChannelFieldName(type, channel, fieldId);
|
||||
} else {
|
||||
chanName = topic;
|
||||
}
|
||||
root[String(channel)][chanName]["v"] = inv->Statistics()->getChannelFieldValue(channel, fieldId);
|
||||
root[String(channel)][chanName]["u"] = inv->Statistics()->getChannelFieldUnit(channel, fieldId);
|
||||
root[String(channel)][chanName]["d"] = inv->Statistics()->getChannelFieldDigits(channel, fieldId);
|
||||
String chanNum;
|
||||
if (type == TYPE_DC) {
|
||||
// TODO(tbnobody)
|
||||
chanNum = static_cast<uint8_t>(channel) + 1;
|
||||
} else {
|
||||
chanNum = channel;
|
||||
}
|
||||
root[chanNum][chanName]["v"] = inv->Statistics()->getChannelFieldValue(type, channel, fieldId);
|
||||
root[chanNum][chanName]["u"] = inv->Statistics()->getChannelFieldUnit(type, channel, fieldId);
|
||||
root[chanNum][chanName]["d"] = inv->Statistics()->getChannelFieldDigits(type, channel, fieldId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user