diff --git a/doc/prometheus_ep_description.md b/doc/prometheus_ep_description.md index bce0525f..9d274f1e 100644 --- a/doc/prometheus_ep_description.md +++ b/doc/prometheus_ep_description.md @@ -4,23 +4,24 @@ Metrics available for AhoyDTU device, inverters and channels. Prometheus metrics provided at `/metrics`. ## Labels -| Label name | Description | -|:-----------|:--------------------------------------| -| version | current installed version of AhoyDTU | -| image | currently not used | -| devicename | Device name from setup | -| name | Inverter name from setup | -| serial | Serial number of inverter | -| enabled | Communication enable for inverter | -| inverter | Inverter name from setup | -| channel | Channel name from setup | - +| Label name | Description | +|:-------------|:--------------------------------------| +| version | current installed version of AhoyDTU | +| image | currently not used | +| devicename | Device name from setup | +| name | Inverter name from setup | +| serial | Serial number of inverter | +| inverter | Inverter name from setup | +| channel | Channel name from setup | ## Exported Metrics | Metric name | Type | Description | Labels | |----------------------------------------|---------|--------------------------------------------------------|--------------| | `ahoy_solar_info` | Gauge | Information about the AhoyDTU device | version, image, devicename | -| `ahoy_solar_inverter_info` | Gauge | Information about the configured inverter(s) | name, serial, enabled | +| `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_is_available` | Gauge | is the inverter available? | inverter | +| `ahoy_solar_inverter_is_producing` | Gauge | Is the inverter producing? | 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_P_AC_watt` | Gauge | AC power of inverter [W] | inverter | @@ -28,7 +29,8 @@ Prometheus metrics provided at `/metrics`. | `ahoy_solar_F_AC_hertz` | Gauge | AC frequency [Hz] | inverter | | `ahoy_solar_PF_AC` | Gauge | AC Power factor | inverter | | `ahoy_solar_Temp_celsius` | Gauge | Temperature of inverter | inverter | -| `ahoy_solar_ALARM_MES_ID` | Gauge | Last alarm message id of inverter | inverter | +| `ahoy_solar_ALARM_MES_ID` | Gauge | Alarm message index of inverter | inverter | +| `ahoy_solar_LastAlarmCode` | Gauge | Last alarm code from inverter | inverter | | `ahoy_solar_YieldDay_wattHours` | Counter | Energy converted to AC per day [Wh] | inverter | | `ahoy_solar_YieldTotal_kilowattHours` | Counter | Energy converted to AC since reset [kWh] | inverter | | `ahoy_solar_P_DC_watt` | Gauge | DC power of inverter [W] | inverter | diff --git a/src/web/web.h b/src/web/web.h index be4df73b..887f65aa 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -132,7 +132,7 @@ class Web { void showUpdate2(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { mApp->setOnUpdate(); - + if(!index) { Serial.printf("Update Start: %s\n", filename.c_str()); #ifndef ESP32 @@ -735,7 +735,7 @@ class Web { #ifdef ENABLE_PROMETHEUS_EP enum { - metricsStateStart, metricsStateInverter, metricStateChannel,metricsStateEnd + metricsStateStart, metricsStateInverter, metricStateRealtimeData,metricsStateAlarmData,metricsStateEnd } metricsStep; int metricsInverterId,metricsChannelId; @@ -749,15 +749,22 @@ class Web { Inverter<> *iv; record_t<> *rec; statistics_t *stat; + String promUnit, promType; String metrics; char type[60], topic[100], val[25]; size_t len = 0; + int alarmChannelId; switch (metricsStep) { case metricsStateStart: // System Info & NRF Statistics : fit to one packet - snprintf(topic,sizeof(topic),"# TYPE ahoy_solar_info gauge\nahoy_solar_info{version=\"%s\",image=\"\",devicename=\"%s\"} 1\n", + snprintf(type,sizeof(type),"# TYPE ahoy_solar_info gauge\n"); + snprintf(topic,sizeof(topic),"ahoy_solar_info{version=\"%s\",image=\"\",devicename=\"%s\"} 1\n", mApp->getVersion(), mConfig->sys.deviceName); - metrics = topic; + metrics = String(type) + String(topic); + + snprintf(topic,sizeof(topic),"# TYPE ahoy_solar_freeheap gauge\nahoy_solar_freeheap{devicename=\"%s\"} %u\n",mConfig->sys.deviceName,ESP.getFreeHeap()); + metrics += String(topic); + // NRF Statistics stat = mApp->getStatistics(); metrics += radioStatistic(F("rx_success"), stat->rxSuccess); @@ -776,24 +783,40 @@ class Web { if (metricsInverterId < mSys->getNumInverters()) { iv = mSys->getInverterByPos(metricsInverterId); if(NULL != iv) { - // Inverter info - len = snprintf((char *)buffer, maxLen, "ahoy_solar_inverter_info{name=\"%s\",serial=\"%12llx\",enabled=\"%d\"} 1\n", - iv->config->name, iv->config->serial.u64,iv->config->enabled); - // Start Channel loop for this inverter + // Inverter info : fit to one packet + snprintf(type,sizeof(type),"# TYPE ahoy_solar_inverter_info gauge\n"); + snprintf(topic,sizeof(topic),"ahoy_solar_inverter_info{name=\"%s\",serial=\"%12llx\"} 1\n", + iv->config->name, iv->config->serial.u64); + metrics = String(type) + String(topic); + + snprintf(type,sizeof(type),"# TYPE ahoy_solar_inverter_is_enabled gauge\n"); + snprintf(topic,sizeof(topic),"ahoy_solar_inverter_is_enabled {inverter=\"%s\"} %d\n",iv->config->name,iv->config->enabled); + metrics += String(type) + String(topic); + + snprintf(type,sizeof(type),"# TYPE ahoy_solar_inverter_is_available gauge\n"); + snprintf(topic,sizeof(topic),"ahoy_solar_inverter_is_available {inverter=\"%s\"} %d\n",iv->config->name,iv->isAvailable(mApp->getTimestamp())); + metrics += String(type) + String(topic); + + snprintf(type,sizeof(type),"# TYPE ahoy_solar_inverter_is_producing gauge\n"); + snprintf(topic,sizeof(topic),"ahoy_solar_inverter_is_producing {inverter=\"%s\"} %d\n",iv->config->name,iv->isProducing(mApp->getTimestamp())); + metrics += String(type) + String(topic); + + len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str()); + + // Start Realtime Data Channel loop for this inverter metricsChannelId = 0; - metricsStep = metricStateChannel; + metricsStep = metricStateRealtimeData; } } else { metricsStep = metricsStateEnd; } break; - case metricStateChannel: // Channel loop + case metricStateRealtimeData: // Realtime Data Channel loop iv = mSys->getInverterByPos(metricsInverterId); rec = iv->getRecordStruct(RealTimeRunData_Debug); if (metricsChannelId < rec->length) { uint8_t channel = rec->assign[metricsChannelId].ch; - String promUnit, promType; std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(metricsChannelId, rec)); snprintf(type, sizeof(type), "# TYPE ahoy_solar_%s%s %s", iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), promType.c_str()); if (0 == channel) { @@ -808,12 +831,34 @@ class Web { } else { len = snprintf((char*)buffer,maxLen,"#\n"); // At least one char to send otherwise the transmission ends. - // All channels processed --> try next inverter - metricsInverterId++; - metricsStep = metricsStateInverter; + // All realtime data channels processed --> try alarm data + metricsStep = metricsStateAlarmData; } break; + case metricsStateAlarmData: // Alarm Info loop + iv = mSys->getInverterByPos(metricsInverterId); + rec = iv->getRecordStruct(AlarmData); + // simple hack : there is only one channel with alarm data + // TODO: find the right one channel with the alarm id + alarmChannelId = 0; + // printf("AlarmData Length %d\n",rec->length); + if (alarmChannelId < rec->length) + { + //uint8_t channel = rec->assign[alarmChannelId].ch; + std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(alarmChannelId, rec)); + snprintf(type, sizeof(type), "# TYPE ahoy_solar_%s%s %s", iv->getFieldName(alarmChannelId, rec), promUnit.c_str(), promType.c_str()); + snprintf(topic, sizeof(topic), "ahoy_solar_%s%s{inverter=\"%s\"}", iv->getFieldName(alarmChannelId, rec), promUnit.c_str(), iv->config->name); + snprintf(val, sizeof(val), "%.3f", iv->getValue(alarmChannelId, rec)); + len = snprintf((char*)buffer,maxLen,"%s\n%s %s\n",type,topic,val); + } else { + len = snprintf((char*)buffer,maxLen,"#\n"); // At least one char to send otherwise the transmission ends. + } + // alarm channel processed --> try next inverter + metricsInverterId++; + metricsStep = metricsStateInverter; + break; + case metricsStateEnd: default: // end of transmission len = 0;