mirror of
https://github.com/lumapu/ahoy.git
synced 2025-06-14 00:21:44 +02:00
Merge branch 'development03-prometheus-powerlimit' of https://github.com/fsck-block/ahoy into fsck-block-development03-prometheus-powerlimit
This commit is contained in:
commit
4f37f994b6
2 changed files with 98 additions and 88 deletions
|
@ -1,10 +1,10 @@
|
||||||
# Prometheus Endpoint
|
# Prometheus Endpoint
|
||||||
Metrics available for AhoyDTU device, inverters and channels.
|
Metrics available for AhoyDTU device, inverters and channels.
|
||||||
|
|
||||||
Prometheus metrics provided at `/metrics`.
|
Prometheus metrics provided at `/metrics`.
|
||||||
|
|
||||||
## Labels
|
## Labels
|
||||||
| Label name | Description |
|
| Label name | Description |
|
||||||
|:-------------|:--------------------------------------|
|
|:-------------|:--------------------------------------|
|
||||||
| version | current installed version of AhoyDTU |
|
| version | current installed version of AhoyDTU |
|
||||||
| image | currently not used |
|
| image | currently not used |
|
||||||
|
@ -19,11 +19,21 @@ Prometheus metrics provided at `/metrics`.
|
||||||
|----------------------------------------------|---------|----------------------------------------------------------|--------------|
|
|----------------------------------------------|---------|----------------------------------------------------------|--------------|
|
||||||
| `ahoy_solar_info` | Gauge | Information about the AhoyDTU device | version, image, devicename |
|
| `ahoy_solar_info` | Gauge | Information about the AhoyDTU device | version, image, devicename |
|
||||||
| `ahoy_solar_uptime` | Counter | Seconds since boot of the AhoyDTU device | devicename |
|
| `ahoy_solar_uptime` | Counter | Seconds since boot of the AhoyDTU device | devicename |
|
||||||
| `ahoy_solar_rssi_db` | Gauge | Quality of the Wifi STA connection | devicename |
|
| `ahoy_solar_freeheap` | Gauge | free heap memory of the AhoyDTU device | devicename |
|
||||||
|
| `ahoy_solar_wifi_rssi_db` | Gauge | Quality of the Wifi STA connection | devicename |
|
||||||
| `ahoy_solar_inverter_info` | Gauge | Information about the configured inverter(s) | name, serial |
|
| `ahoy_solar_inverter_info` | Gauge | Information about the configured inverter(s) | name, serial |
|
||||||
| `ahoy_solar_inverter_enabled` | Gauge | Is the inverter enabled? | inverter |
|
| `ahoy_solar_inverter_enabled` | Gauge | Is the inverter enabled? | inverter |
|
||||||
| `ahoy_solar_inverter_is_available` | Gauge | is the inverter available? | inverter |
|
| `ahoy_solar_inverter_is_available` | Gauge | is the inverter available? | inverter |
|
||||||
| `ahoy_solar_inverter_is_producing` | Gauge | Is the inverter producing? | inverter |
|
| `ahoy_solar_inverter_is_producing` | Gauge | Is the inverter producing? | inverter |
|
||||||
|
| `ahoy_solar_inverter_power_limit_read` | Gauge | Power Limit read from inverter | inverter |
|
||||||
|
| `ahoy_solar_inverter_power_limit_ack` | Gauge | Power Limit acknowledged by inverter | inverter |
|
||||||
|
| `ahoy_solar_inverter_max_power` | Gauge | Max Power of inverter | inverter |
|
||||||
|
| `ahoy_solar_inverter_radio_rx_success` | Counter | NRF24 statistic of inverter | inverter |
|
||||||
|
| `ahoy_solar_inverter_radio_rx_fail` | Counter | NRF24 statistic of inverter | inverter |
|
||||||
|
| `ahoy_solar_inverter_radio_rx_fail_answer` | Counter | NRF24 statistic of inverter | inverter |
|
||||||
|
| `ahoy_solar_inverter_radio_frame_cnt` | Counter | NRF24 statistic of inverter | inverter |
|
||||||
|
| `ahoy_solar_inverter_radio_tx_cnt` | Counter | NRF24 statistic of inverter | inverter |
|
||||||
|
| `ahoy_solar_inverter_radio_retransmits` | Counter | NRF24 statistic of inverter | inverter |
|
||||||
| `ahoy_solar_U_AC_volt` | Gauge | AC voltage of inverter [V] | inverter |
|
| `ahoy_solar_U_AC_volt` | Gauge | AC voltage of inverter [V] | inverter |
|
||||||
| `ahoy_solar_I_AC_ampere` | Gauge | AC current of inverter [A] | inverter |
|
| `ahoy_solar_I_AC_ampere` | Gauge | AC current of inverter [A] | inverter |
|
||||||
| `ahoy_solar_P_AC_watt` | Gauge | AC power of inverter [W] | inverter |
|
| `ahoy_solar_P_AC_watt` | Gauge | AC power of inverter [W] | inverter |
|
||||||
|
@ -46,9 +56,4 @@ Prometheus metrics provided at `/metrics`.
|
||||||
| `ahoy_solar_YieldDay_wattHours` | Counter | Energy converted to AC per day [Wh] | inverter, channel |
|
| `ahoy_solar_YieldDay_wattHours` | Counter | Energy converted to AC per day [Wh] | inverter, channel |
|
||||||
| `ahoy_solar_YieldTotal_kilowattHours` | Counter | Energy converted to AC since reset [kWh] | inverter, channel |
|
| `ahoy_solar_YieldTotal_kilowattHours` | Counter | Energy converted to AC since reset [kWh] | inverter, channel |
|
||||||
| `ahoy_solar_Irradiation_ratio` | Gauge | ratio DC Power over set maximum power per channel [%] | inverter, channel |
|
| `ahoy_solar_Irradiation_ratio` | Gauge | ratio DC Power over set maximum power per channel [%] | inverter, channel |
|
||||||
| `ahoy_solar_radio_rx_success` | Gauge | NRF24 statistic | |
|
|
||||||
| `ahoy_solar_radio_rx_fail` | Gauge | NRF24 statistic | |
|
|
||||||
| `ahoy_solar_radio_rx_fail_answer` | Gauge | NRF24 statistic | |
|
|
||||||
| `ahoy_solar_radio_frame_cnt` | Gauge | NRF24 statistic | |
|
|
||||||
| `ahoy_solar_radio_tx_cnt` | Gauge | NRF24 statistic | |
|
|
||||||
|
|
||||||
|
|
165
src/web/web.h
165
src/web/web.h
|
@ -625,17 +625,45 @@ class Web {
|
||||||
#ifdef ENABLE_PROMETHEUS_EP
|
#ifdef ENABLE_PROMETHEUS_EP
|
||||||
// Note
|
// Note
|
||||||
// Prometheus exposition format is defined here: https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md
|
// Prometheus exposition format is defined here: https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md
|
||||||
// TODO: Check packetsize for MAX_NUM_INVERTERS. Successfully Tested with 4 Inverters (each with 4 channels)
|
// NOTE: Grouping for fields with channels and totals is currently not working
|
||||||
enum {
|
// TODO: Handle grouping and sorting for independant from channel number
|
||||||
metricsStateStart,
|
// NOTE: Check packetsize for MAX_NUM_INVERTERS. Successfully Tested with 4 Inverters (each with 4 channels)
|
||||||
metricsStateInverter1, metricsStateInverter2, metricsStateInverter3, metricsStateInverter4,
|
const char * metricPrefix = "ahoy_solar_";
|
||||||
metricStateRealtimeFieldId, metricStateRealtimeInverterId,
|
typedef enum {
|
||||||
|
metricsStateInverterInfo=0, metricsStateInverterEnabled=1, metricsStateInverterAvailable=2, metricsStateInverterProducing=3,
|
||||||
|
metricsStateInverterPowerLimitRead=4, metricsStateInverterPowerLimitAck=5, metricsStateInverterMaxPower=6,
|
||||||
|
metricsStateInverterRxSuccess=7, metricsStateInverterRxFail=8, metricsStateInverterRxFailAnswer=9,
|
||||||
|
metricsStateInverterFrameCnt=10, metricsStateInverterTxCnt=11, metricsStateInverterRetransmits=12,
|
||||||
|
metricStateRealtimeFieldId=metricsStateInverterRetransmits+1, // ensure that this state follows the last per_inverter state
|
||||||
|
metricStateRealtimeInverterId,
|
||||||
metricsStateAlarmData,
|
metricsStateAlarmData,
|
||||||
|
metricsStateStart,
|
||||||
metricsStateEnd
|
metricsStateEnd
|
||||||
} metricsStep;
|
} MetricStep_t;
|
||||||
|
MetricStep_t metricsStep;
|
||||||
|
typedef struct {
|
||||||
|
const char *type;
|
||||||
|
const char *format;
|
||||||
|
const std::function<uint64_t(Inverter<> *iv)> valueFunc;
|
||||||
|
} InverterMetric_t;
|
||||||
|
InverterMetric_t inverterMetrics[13] = {
|
||||||
|
{ "info", "info{name=\"%s\",serial=\"%12llx\"} 1\n", [](Inverter<> *iv)-> uint64_t {return iv->config->serial.u64;} },
|
||||||
|
{ "is_enabled", "is_enabled {inverter=\"%s\"} %d\n", [](Inverter<> *iv)-> uint64_t {return iv->config->enabled;} },
|
||||||
|
{ "is_available", "is_available {inverter=\"%s\"} %d\n", [](Inverter<> *iv)-> uint64_t {return iv->isAvailable();} },
|
||||||
|
{ "is_producing", "is_producing {inverter=\"%s\"} %d\n", [](Inverter<> *iv)-> uint64_t {return iv->isProducing();} },
|
||||||
|
{ "power_limit_read", "power_limit_read {inverter=\"%s\"} %d\n", [](Inverter<> *iv)-> uint64_t {return (int64_t)ah::round3(iv->actPowerLimit);} },
|
||||||
|
{ "power_limit_ack", "power_limit_ack {inverter=\"%s\"} %d\n", [](Inverter<> *iv)-> uint64_t {return (iv->powerLimitAck)?1:0;} },
|
||||||
|
{ "max_power", "max_power {inverter=\"%s\"} %d\n", [](Inverter<> *iv)-> uint64_t {return iv->getMaxPower();} },
|
||||||
|
{ "radio_rx_success", "radio_rx_success {inverter=\"%s\"} %d\n", [](Inverter<> *iv)-> uint64_t {return iv->radioStatistics.rxSuccess;} },
|
||||||
|
{ "radio_rx_fail", "radio_rx_fail {inverter=\"%s\"} %d\n", [](Inverter<> *iv)-> uint64_t {return iv->radioStatistics.rxFail;} },
|
||||||
|
{ "radio_rx_fail_answer", "radio_rx_fail_answer {inverter=\"%s\"} %d\n", [](Inverter<> *iv)-> uint64_t {return iv->radioStatistics.rxFailNoAnser;} },
|
||||||
|
{ "radio_frame_cnt", "radio_frame_cnt {inverter=\"%s\"} %d\n", [](Inverter<> *iv)-> uint64_t {return iv->radioStatistics.frmCnt;} },
|
||||||
|
{ "radio_tx_cnt", "radio_tx_cnt {inverter=\"%s\"} %d\n", [](Inverter<> *iv)-> uint64_t {return iv->radioStatistics.txCnt;} },
|
||||||
|
{ "radio_retransmits", "radio_retransmits {inverter=\"%s\"} %d\n", [](Inverter<> *iv)-> uint64_t {return iv->radioStatistics.retransmits;} }
|
||||||
|
};
|
||||||
int metricsInverterId;
|
int metricsInverterId;
|
||||||
uint8_t metricsFieldId;
|
uint8_t metricsFieldId;
|
||||||
bool metricDeclared;
|
bool metricDeclared, metricTotalDeclard;
|
||||||
|
|
||||||
void showMetrics(AsyncWebServerRequest *request) {
|
void showMetrics(AsyncWebServerRequest *request) {
|
||||||
DPRINTLN(DBG_VERBOSE, F("web::showMetrics"));
|
DPRINTLN(DBG_VERBOSE, F("web::showMetrics"));
|
||||||
|
@ -656,79 +684,58 @@ class Web {
|
||||||
// Each step must return at least one character. Otherwise the processing of AsyncWebServerResponse stops.
|
// Each step must return at least one character. Otherwise the processing of AsyncWebServerResponse stops.
|
||||||
// So several "Info:" blocks are used to keep the transmission going
|
// So several "Info:" blocks are used to keep the transmission going
|
||||||
switch (metricsStep) {
|
switch (metricsStep) {
|
||||||
case metricsStateStart: // System Info & NRF Statistics : fit to one packet
|
case metricsStateStart: // System Info : fit to one packet
|
||||||
snprintf(type,sizeof(type),"# TYPE ahoy_solar_info gauge\n");
|
snprintf(type,sizeof(type),"# TYPE %sinfo gauge\n",metricPrefix);
|
||||||
snprintf(topic,sizeof(topic),"ahoy_solar_info{version=\"%s\",image=\"\",devicename=\"%s\"} 1\n",
|
snprintf(topic,sizeof(topic),"%sinfo{version=\"%s\",image=\"\",devicename=\"%s\"} 1\n",metricPrefix,
|
||||||
mApp->getVersion(), mConfig->sys.deviceName);
|
mApp->getVersion(), mConfig->sys.deviceName);
|
||||||
metrics = String(type) + String(topic);
|
metrics = String(type) + String(topic);
|
||||||
|
|
||||||
snprintf(type,sizeof(type),"# TYPE ahoy_solar_freeheap gauge\n");
|
snprintf(type,sizeof(type),"# TYPE %sfreeheap gauge\n",metricPrefix);
|
||||||
snprintf(topic,sizeof(topic),"ahoy_solar_freeheap{devicename=\"%s\"} %u\n",mConfig->sys.deviceName,ESP.getFreeHeap());
|
snprintf(topic,sizeof(topic),"%sfreeheap{devicename=\"%s\"} %u\n",metricPrefix,mConfig->sys.deviceName,ESP.getFreeHeap());
|
||||||
metrics += String(type) + String(topic);
|
metrics += String(type) + String(topic);
|
||||||
|
|
||||||
snprintf(type,sizeof(type),"# TYPE ahoy_solar_uptime counter\n");
|
snprintf(type,sizeof(type),"# TYPE %suptime counter\n",metricPrefix);
|
||||||
snprintf(topic,sizeof(topic),"ahoy_solar_uptime{devicename=\"%s\"} %u\n", mConfig->sys.deviceName, mApp->getUptime());
|
snprintf(topic,sizeof(topic),"%suptime{devicename=\"%s\"} %u\n",metricPrefix, mConfig->sys.deviceName, mApp->getUptime());
|
||||||
metrics += String(type) + String(topic);
|
metrics += String(type) + String(topic);
|
||||||
|
|
||||||
snprintf(type,sizeof(type),"# TYPE ahoy_solar_wifi_rssi_db gauge\n");
|
snprintf(type,sizeof(type),"# TYPE %swifi_rssi_db gauge\n",metricPrefix);
|
||||||
snprintf(topic,sizeof(topic),"ahoy_solar_wifi_rssi_db{devicename=\"%s\"} %d\n", mConfig->sys.deviceName, WiFi.RSSI());
|
snprintf(topic,sizeof(topic),"%swifi_rssi_db{devicename=\"%s\"} %d\n",metricPrefix, mConfig->sys.deviceName, WiFi.RSSI());
|
||||||
metrics += String(type) + String(topic);
|
metrics += String(type) + String(topic);
|
||||||
|
|
||||||
// NRF Statistics
|
|
||||||
// @TODO 2023-10-01: the statistic data is now available per inverter
|
|
||||||
/*stat = mApp->getNrfStatistics();
|
|
||||||
metrics += radioStatistic(F("rx_success"), stat->rxSuccess);
|
|
||||||
metrics += radioStatistic(F("rx_fail"), stat->rxFail);
|
|
||||||
metrics += radioStatistic(F("rx_fail_answer"), stat->rxFailNoAnser);
|
|
||||||
metrics += radioStatistic(F("frame_cnt"), stat->frmCnt);
|
|
||||||
metrics += radioStatistic(F("tx_cnt"), stat->txCnt);
|
|
||||||
metrics += radioStatistic(F("retrans_cnt"), stat->retransmits);*/
|
|
||||||
|
|
||||||
len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str());
|
len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str());
|
||||||
// Next is Inverter information
|
// Next is Inverter information
|
||||||
metricsInverterId = 0;
|
metricsStep = metricsStateInverterInfo;
|
||||||
metricsStep = metricsStateInverter1;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case metricsStateInverter1: // Information about all inverters configured : fit to one packet
|
// Information about all inverters configured : each metric for all inverters must fit to one network packet
|
||||||
metrics = "# TYPE ahoy_solar_inverter_info gauge\n";
|
case metricsStateInverterInfo:
|
||||||
metrics += inverterMetric(topic, sizeof(topic),"ahoy_solar_inverter_info{name=\"%s\",serial=\"%12llx\"} 1\n",
|
case metricsStateInverterEnabled:
|
||||||
[](Inverter<> *iv,IApp *mApp)-> uint64_t {return iv->config->serial.u64;});
|
case metricsStateInverterAvailable:
|
||||||
|
case metricsStateInverterProducing:
|
||||||
|
case metricsStateInverterPowerLimitRead:
|
||||||
|
case metricsStateInverterPowerLimitAck:
|
||||||
|
case metricsStateInverterMaxPower:
|
||||||
|
case metricsStateInverterRxSuccess:
|
||||||
|
case metricsStateInverterRxFail:
|
||||||
|
case metricsStateInverterRxFailAnswer:
|
||||||
|
case metricsStateInverterFrameCnt:
|
||||||
|
case metricsStateInverterTxCnt:
|
||||||
|
case metricsStateInverterRetransmits:
|
||||||
|
metrics = "# TYPE ahoy_solar_inverter_" + String(inverterMetrics[metricsStep].type) + " gauge\n";
|
||||||
|
metrics += inverterMetric(topic, sizeof(topic),(String("ahoy_solar_inverter_") + inverterMetrics[metricsStep].format).c_str(), inverterMetrics[metricsStep].valueFunc);
|
||||||
len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str());
|
len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str());
|
||||||
metricsStep = metricsStateInverter2;
|
// ugly hack to increment the enum
|
||||||
break;
|
metricsStep = static_cast<MetricStep_t>( static_cast<int>(metricsStep) + 1);
|
||||||
|
// Prepare Realtime Field loop, which may be startet next
|
||||||
case metricsStateInverter2: // Information about all inverters configured : fit to one packet
|
|
||||||
metrics += "# TYPE ahoy_solar_inverter_is_enabled gauge\n";
|
|
||||||
metrics += inverterMetric(topic, sizeof(topic),"ahoy_solar_inverter_is_enabled {inverter=\"%s\"} %d\n",
|
|
||||||
[](Inverter<> *iv,IApp *mApp)-> uint64_t {return iv->config->enabled;});
|
|
||||||
|
|
||||||
len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str());
|
|
||||||
metricsStep = metricsStateInverter3;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case metricsStateInverter3: // Information about all inverters configured : fit to one packet
|
|
||||||
metrics += "# TYPE ahoy_solar_inverter_is_available gauge\n";
|
|
||||||
metrics += inverterMetric(topic, sizeof(topic),"ahoy_solar_inverter_is_available {inverter=\"%s\"} %d\n",
|
|
||||||
[](Inverter<> *iv,IApp *mApp)-> uint64_t {return iv->isAvailable();});
|
|
||||||
len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str());
|
|
||||||
metricsStep = metricsStateInverter4;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case metricsStateInverter4: // Information about all inverters configured : fit to one packet
|
|
||||||
metrics += "# TYPE ahoy_solar_inverter_is_producing gauge\n";
|
|
||||||
metrics += inverterMetric(topic, sizeof(topic),"ahoy_solar_inverter_is_producing {inverter=\"%s\"} %d\n",
|
|
||||||
[](Inverter<> *iv,IApp *mApp)-> uint64_t {return iv->isProducing();});
|
|
||||||
len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str());
|
|
||||||
// Start Realtime Field loop
|
|
||||||
metricsFieldId = FLD_UDC;
|
metricsFieldId = FLD_UDC;
|
||||||
metricsStep = metricStateRealtimeFieldId;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case metricStateRealtimeFieldId: // Iterate over all defined fields
|
case metricStateRealtimeFieldId: // Iterate over all defined fields
|
||||||
if (metricsFieldId < FLD_LAST_ALARM_CODE) {
|
if (metricsFieldId < FLD_LAST_ALARM_CODE) {
|
||||||
metrics = "# Info: processing realtime field #"+String(metricsFieldId)+"\n";
|
metrics = "# Info: processing realtime field #"+String(metricsFieldId)+"\n";
|
||||||
metricDeclared = false;
|
metricDeclared = false;
|
||||||
|
metricTotalDeclard = false;
|
||||||
|
|
||||||
metricsInverterId = 0;
|
metricsInverterId = 0;
|
||||||
metricsStep = metricStateRealtimeInverterId;
|
metricsStep = metricStateRealtimeInverterId;
|
||||||
|
@ -743,7 +750,6 @@ class Web {
|
||||||
metrics = "";
|
metrics = "";
|
||||||
if (metricsInverterId < mSys->getNumInverters()) {
|
if (metricsInverterId < mSys->getNumInverters()) {
|
||||||
// process all channels of this inverter
|
// process all channels of this inverter
|
||||||
|
|
||||||
iv = mSys->getInverterByPos(metricsInverterId);
|
iv = mSys->getInverterByPos(metricsInverterId);
|
||||||
if (NULL != iv) {
|
if (NULL != iv) {
|
||||||
rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||||
|
@ -757,22 +763,27 @@ class Web {
|
||||||
std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(metricsChannelId, rec));
|
std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(metricsChannelId, rec));
|
||||||
// Declare metric only once
|
// Declare metric only once
|
||||||
if (channel != 0 && !metricDeclared) {
|
if (channel != 0 && !metricDeclared) {
|
||||||
snprintf(type, sizeof(type), "# TYPE ahoy_solar_%s%s %s\n", iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), promType.c_str());
|
snprintf(type, sizeof(type), "# TYPE %s%s%s %s\n",metricPrefix, iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), promType.c_str());
|
||||||
metrics += type;
|
metrics += type;
|
||||||
metricDeclared = true;
|
metricDeclared = true;
|
||||||
}
|
}
|
||||||
// report value
|
// report value
|
||||||
if (0 == channel) {
|
if (0 == channel) {
|
||||||
|
// Report a _total value if also channel values were reported. Otherwise report without _total
|
||||||
char total[7];
|
char total[7];
|
||||||
total[0] = 0;
|
total[0] = 0;
|
||||||
if (metricDeclared) {
|
if (metricDeclared) {
|
||||||
// A declaration and value for channels has been delivered. So declare and deliver a _total metric
|
// A declaration and value for channels have been delivered. So declare and deliver a _total metric
|
||||||
strncpy(total,"_total",sizeof(total));
|
strncpy(total,"_total",sizeof(total));
|
||||||
}
|
}
|
||||||
snprintf(type, sizeof(type), "# TYPE ahoy_solar_%s%s%s %s\n", iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), total, promType.c_str());
|
if (!metricTotalDeclard) {
|
||||||
metrics += type;
|
snprintf(type, sizeof(type), "# TYPE %s%s%s%s %s\n",metricPrefix, iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), total, promType.c_str());
|
||||||
snprintf(topic, sizeof(topic), "ahoy_solar_%s%s%s{inverter=\"%s\"}", iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), total,iv->config->name);
|
metrics += type;
|
||||||
|
metricTotalDeclard = true;
|
||||||
|
}
|
||||||
|
snprintf(topic, sizeof(topic), "%s%s%s%s{inverter=\"%s\"}",metricPrefix, iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), total,iv->config->name);
|
||||||
} else {
|
} else {
|
||||||
|
// Report (non zero) channel value
|
||||||
// Use a fallback channel name (ch0, ch1, ...)if non is given by user
|
// Use a fallback channel name (ch0, ch1, ...)if non is given by user
|
||||||
char chName[MAX_NAME_LENGTH];
|
char chName[MAX_NAME_LENGTH];
|
||||||
if (iv->config->chName[channel-1][0] != 0) {
|
if (iv->config->chName[channel-1][0] != 0) {
|
||||||
|
@ -780,7 +791,7 @@ class Web {
|
||||||
} else {
|
} else {
|
||||||
snprintf(chName,sizeof(chName),"ch%1d",channel);
|
snprintf(chName,sizeof(chName),"ch%1d",channel);
|
||||||
}
|
}
|
||||||
snprintf(topic, sizeof(topic), "ahoy_solar_%s%s{inverter=\"%s\",channel=\"%s\"}", iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), iv->config->name,chName);
|
snprintf(topic, sizeof(topic), "%s%s%s{inverter=\"%s\",channel=\"%s\"}",metricPrefix, iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), iv->config->name,chName);
|
||||||
}
|
}
|
||||||
snprintf(val, sizeof(val), " %.3f\n", iv->getValue(metricsChannelId, rec));
|
snprintf(val, sizeof(val), " %.3f\n", iv->getValue(metricsChannelId, rec));
|
||||||
metrics += topic;
|
metrics += topic;
|
||||||
|
@ -810,7 +821,7 @@ class Web {
|
||||||
|
|
||||||
case metricsStateAlarmData: // Alarm Info loop : fit to one packet
|
case metricsStateAlarmData: // Alarm Info loop : fit to one packet
|
||||||
// Perform grouping on metrics according to Prometheus exposition format specification
|
// Perform grouping on metrics according to Prometheus exposition format specification
|
||||||
snprintf(type, sizeof(type),"# TYPE ahoy_solar_%s gauge\n",fields[FLD_LAST_ALARM_CODE]);
|
snprintf(type, sizeof(type),"# TYPE %s%s gauge\n",metricPrefix,fields[FLD_LAST_ALARM_CODE]);
|
||||||
metrics = type;
|
metrics = type;
|
||||||
|
|
||||||
for (metricsInverterId = 0; metricsInverterId < mSys->getNumInverters();metricsInverterId++) {
|
for (metricsInverterId = 0; metricsInverterId < mSys->getNumInverters();metricsInverterId++) {
|
||||||
|
@ -822,7 +833,7 @@ class Web {
|
||||||
alarmChannelId = 0;
|
alarmChannelId = 0;
|
||||||
if (alarmChannelId < rec->length) {
|
if (alarmChannelId < rec->length) {
|
||||||
std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(alarmChannelId, rec));
|
std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(alarmChannelId, rec));
|
||||||
snprintf(topic, sizeof(topic), "ahoy_solar_%s%s{inverter=\"%s\"}", iv->getFieldName(alarmChannelId, rec), promUnit.c_str(), iv->config->name);
|
snprintf(topic, sizeof(topic), "%s%s%s{inverter=\"%s\"}",metricPrefix, iv->getFieldName(alarmChannelId, rec), promUnit.c_str(), iv->config->name);
|
||||||
snprintf(val, sizeof(val), " %.3f\n", iv->getValue(alarmChannelId, rec));
|
snprintf(val, sizeof(val), " %.3f\n", iv->getValue(alarmChannelId, rec));
|
||||||
metrics += topic;
|
metrics += topic;
|
||||||
metrics += val;
|
metrics += val;
|
||||||
|
@ -833,11 +844,13 @@ class Web {
|
||||||
metricsStep = metricsStateEnd;
|
metricsStep = metricsStateEnd;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case metricsStateEnd:
|
|
||||||
default: // end of transmission
|
default: // end of transmission
|
||||||
|
DBGPRINT("E: Prometheus: Bad metricsStep=");
|
||||||
|
DBGPRINTLN(String(metricsStep));
|
||||||
|
case metricsStateEnd:
|
||||||
len = 0;
|
len = 0;
|
||||||
break;
|
break;
|
||||||
}
|
} // switch
|
||||||
return len;
|
return len;
|
||||||
});
|
});
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
@ -845,27 +858,19 @@ class Web {
|
||||||
|
|
||||||
|
|
||||||
// Traverse all inverters and collect the metric via valueFunc
|
// Traverse all inverters and collect the metric via valueFunc
|
||||||
String inverterMetric(char *buffer, size_t len, const char *format, std::function<uint64_t(Inverter<> *iv, IApp *mApp)> valueFunc) {
|
String inverterMetric(char *buffer, size_t len, const char *format, std::function<uint64_t(Inverter<> *iv)> valueFunc) {
|
||||||
Inverter<> *iv;
|
Inverter<> *iv;
|
||||||
String metric = "";
|
String metric = "";
|
||||||
for (int metricsInverterId = 0; metricsInverterId < mSys->getNumInverters();metricsInverterId++) {
|
for (int metricsInverterId = 0; metricsInverterId < mSys->getNumInverters();metricsInverterId++) {
|
||||||
iv = mSys->getInverterByPos(metricsInverterId);
|
iv = mSys->getInverterByPos(metricsInverterId);
|
||||||
if (NULL != iv) {
|
if (NULL != iv) {
|
||||||
snprintf(buffer,len,format,iv->config->name, valueFunc(iv,mApp));
|
snprintf(buffer,len,format,iv->config->name, valueFunc(iv));
|
||||||
metric += String(buffer);
|
metric += String(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return metric;
|
return metric;
|
||||||
}
|
}
|
||||||
|
|
||||||
String radioStatistic(String statistic, uint32_t value) {
|
|
||||||
char type[60], topic[80], val[25];
|
|
||||||
snprintf(type, sizeof(type), "# TYPE ahoy_solar_radio_%s counter",statistic.c_str());
|
|
||||||
snprintf(topic, sizeof(topic), "ahoy_solar_radio_%s",statistic.c_str());
|
|
||||||
snprintf(val, sizeof(val), "%d", value);
|
|
||||||
return ( String(type) + "\n" + String(topic) + " " + String(val) + "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<String, String> convertToPromUnits(String shortUnit) {
|
std::pair<String, String> convertToPromUnits(String shortUnit) {
|
||||||
if(shortUnit == "A") return {"_ampere", "gauge"};
|
if(shortUnit == "A") return {"_ampere", "gauge"};
|
||||||
if(shortUnit == "V") return {"_volt", "gauge"};
|
if(shortUnit == "V") return {"_volt", "gauge"};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue