Log errors if too less memory for webapi is available
This commit is contained in:
parent
97bc964b6c
commit
759f8b7208
@ -31,6 +31,8 @@ public:
|
|||||||
static bool checkCredentials(AsyncWebServerRequest* request);
|
static bool checkCredentials(AsyncWebServerRequest* request);
|
||||||
static bool checkCredentialsReadonly(AsyncWebServerRequest* request);
|
static bool checkCredentialsReadonly(AsyncWebServerRequest* request);
|
||||||
|
|
||||||
|
static void sendTooManyRequests(AsyncWebServerRequest* request);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AsyncWebServer _server;
|
AsyncWebServer _server;
|
||||||
AsyncEventSource _events;
|
AsyncEventSource _events;
|
||||||
|
|||||||
@ -90,4 +90,11 @@ bool WebApiClass::checkCredentialsReadonly(AsyncWebServerRequest* request)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebApiClass::sendTooManyRequests(AsyncWebServerRequest* request)
|
||||||
|
{
|
||||||
|
auto response = request->beginResponse(429, "text/plain", "Too Many Requests");
|
||||||
|
response->addHeader("Retry-After", "60");
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
|
|
||||||
WebApiClass WebApi;
|
WebApiClass WebApi;
|
||||||
@ -5,7 +5,9 @@
|
|||||||
*/
|
*/
|
||||||
#include "WebApi_prometheus.h"
|
#include "WebApi_prometheus.h"
|
||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
|
#include "MessageOutput.h"
|
||||||
#include "NetworkSettings.h"
|
#include "NetworkSettings.h"
|
||||||
|
#include "WebApi.h"
|
||||||
#include <Hoymiles.h>
|
#include <Hoymiles.h>
|
||||||
|
|
||||||
void WebApiPrometheusClass::init(AsyncWebServer* server)
|
void WebApiPrometheusClass::init(AsyncWebServer* server)
|
||||||
@ -23,71 +25,78 @@ void WebApiPrometheusClass::loop()
|
|||||||
|
|
||||||
void WebApiPrometheusClass::onPrometheusMetricsGet(AsyncWebServerRequest* request)
|
void WebApiPrometheusClass::onPrometheusMetricsGet(AsyncWebServerRequest* request)
|
||||||
{
|
{
|
||||||
auto stream = request->beginResponseStream("text/plain; charset=utf-8", 40960);
|
try {
|
||||||
|
auto stream = request->beginResponseStream("text/plain; charset=utf-8", 40960);
|
||||||
|
|
||||||
stream->print(F("# HELP opendtu_build Build info\n"));
|
stream->print(F("# HELP opendtu_build Build info\n"));
|
||||||
stream->print(F("# TYPE opendtu_build gauge\n"));
|
stream->print(F("# TYPE opendtu_build gauge\n"));
|
||||||
stream->printf("opendtu_build{name=\"%s\",id=\"%s\",version=\"%d.%d.%d\"} 1\n",
|
stream->printf("opendtu_build{name=\"%s\",id=\"%s\",version=\"%d.%d.%d\"} 1\n",
|
||||||
NetworkSettings.getHostname().c_str(), AUTO_GIT_HASH, CONFIG_VERSION >> 24 & 0xff, CONFIG_VERSION >> 16 & 0xff, CONFIG_VERSION >> 8 & 0xff);
|
NetworkSettings.getHostname().c_str(), AUTO_GIT_HASH, CONFIG_VERSION >> 24 & 0xff, CONFIG_VERSION >> 16 & 0xff, CONFIG_VERSION >> 8 & 0xff);
|
||||||
|
|
||||||
stream->print(F("# HELP opendtu_platform Platform info\n"));
|
stream->print(F("# HELP opendtu_platform Platform info\n"));
|
||||||
stream->print(F("# TYPE opendtu_platform gauge\n"));
|
stream->print(F("# TYPE opendtu_platform gauge\n"));
|
||||||
stream->printf("opendtu_platform{arch=\"%s\",mac=\"%s\"} 1\n", ESP.getChipModel(), NetworkSettings.macAddress().c_str());
|
stream->printf("opendtu_platform{arch=\"%s\",mac=\"%s\"} 1\n", ESP.getChipModel(), NetworkSettings.macAddress().c_str());
|
||||||
|
|
||||||
stream->print(F("# HELP opendtu_uptime Uptime in seconds\n"));
|
stream->print(F("# HELP opendtu_uptime Uptime in seconds\n"));
|
||||||
stream->print(F("# TYPE opendtu_uptime counter\n"));
|
stream->print(F("# TYPE opendtu_uptime counter\n"));
|
||||||
stream->printf("opendtu_uptime %lld\n", esp_timer_get_time() / 1000000);
|
stream->printf("opendtu_uptime %lld\n", esp_timer_get_time() / 1000000);
|
||||||
|
|
||||||
stream->print(F("# HELP opendtu_heap_size System memory size\n"));
|
stream->print(F("# HELP opendtu_heap_size System memory size\n"));
|
||||||
stream->print(F("# TYPE opendtu_heap_size gauge\n"));
|
stream->print(F("# TYPE opendtu_heap_size gauge\n"));
|
||||||
stream->printf("opendtu_heap_size %zu\n", ESP.getHeapSize());
|
stream->printf("opendtu_heap_size %zu\n", ESP.getHeapSize());
|
||||||
|
|
||||||
stream->print(F("# HELP opendtu_free_heap_size System free memory\n"));
|
stream->print(F("# HELP opendtu_free_heap_size System free memory\n"));
|
||||||
stream->print(F("# TYPE opendtu_free_heap_size gauge\n"));
|
stream->print(F("# TYPE opendtu_free_heap_size gauge\n"));
|
||||||
stream->printf("opendtu_free_heap_size %zu\n", ESP.getFreeHeap());
|
stream->printf("opendtu_free_heap_size %zu\n", ESP.getFreeHeap());
|
||||||
|
|
||||||
stream->print(F("# HELP wifi_rssi WiFi RSSI\n"));
|
stream->print(F("# HELP wifi_rssi WiFi RSSI\n"));
|
||||||
stream->print(F("# TYPE wifi_rssi gauge\n"));
|
stream->print(F("# TYPE wifi_rssi gauge\n"));
|
||||||
stream->printf("wifi_rssi %d\n", WiFi.RSSI());
|
stream->printf("wifi_rssi %d\n", WiFi.RSSI());
|
||||||
|
|
||||||
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
||||||
auto inv = Hoymiles.getInverterByPos(i);
|
auto inv = Hoymiles.getInverterByPos(i);
|
||||||
|
|
||||||
String serial = inv->serialString();
|
String serial = inv->serialString();
|
||||||
const char* name = inv->name();
|
const char* name = inv->name();
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
stream->print(F("# HELP opendtu_last_update last update from inverter in s\n"));
|
stream->print(F("# HELP opendtu_last_update last update from inverter in s\n"));
|
||||||
stream->print(F("# TYPE opendtu_last_update gauge\n"));
|
stream->print(F("# TYPE opendtu_last_update gauge\n"));
|
||||||
}
|
}
|
||||||
stream->printf("opendtu_last_update{serial=\"%s\",unit=\"%d\",name=\"%s\"} %d\n",
|
stream->printf("opendtu_last_update{serial=\"%s\",unit=\"%d\",name=\"%s\"} %d\n",
|
||||||
serial.c_str(), i, name, inv->Statistics()->getLastUpdate() / 1000);
|
serial.c_str(), i, name, inv->Statistics()->getLastUpdate() / 1000);
|
||||||
|
|
||||||
// Loop all channels
|
// Loop all channels
|
||||||
for (auto& t : inv->Statistics()->getChannelTypes()) {
|
for (auto& t : inv->Statistics()->getChannelTypes()) {
|
||||||
for (auto& c : inv->Statistics()->getChannelsByType(t)) {
|
for (auto& c : inv->Statistics()->getChannelsByType(t)) {
|
||||||
addField(stream, serial, i, inv, t, c, FLD_PAC);
|
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_UAC);
|
||||||
addField(stream, serial, i, inv, t, c, FLD_IAC);
|
addField(stream, serial, i, inv, t, c, FLD_IAC);
|
||||||
if (t == TYPE_AC) {
|
if (t == TYPE_AC) {
|
||||||
addField(stream, serial, i, inv, t, c, FLD_PDC, "PowerDC");
|
addField(stream, serial, i, inv, t, c, FLD_PDC, "PowerDC");
|
||||||
} else {
|
} else {
|
||||||
addField(stream, serial, i, inv, t, 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, 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stream->addHeader(F("Cache-Control"), F("no-cache"));
|
||||||
|
request->send(stream);
|
||||||
|
|
||||||
|
} catch (std::bad_alloc& bad_alloc) {
|
||||||
|
MessageOutput.printf("Call to /api/prometheus/metrics temporarely out of resources. Reason: \"%s\".\r\n", bad_alloc.what());
|
||||||
|
|
||||||
|
WebApi.sendTooManyRequests(request);
|
||||||
}
|
}
|
||||||
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, ChannelType_t type, ChannelNum_t channel, FieldId_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)
|
||||||
|
|||||||
@ -60,21 +60,26 @@ void WebApiWsLiveClass::loop()
|
|||||||
// Update on every inverter change or at least after 10 seconds
|
// Update on every inverter change or at least after 10 seconds
|
||||||
if (millis() - _lastWsPublish > (10 * 1000) || (maxTimeStamp != _newestInverterTimestamp)) {
|
if (millis() - _lastWsPublish > (10 * 1000) || (maxTimeStamp != _newestInverterTimestamp)) {
|
||||||
|
|
||||||
DynamicJsonDocument root(40960);
|
try {
|
||||||
JsonVariant var = root;
|
DynamicJsonDocument root(40960);
|
||||||
generateJsonResponse(var);
|
JsonVariant var = root;
|
||||||
|
generateJsonResponse(var);
|
||||||
|
|
||||||
String buffer;
|
String buffer;
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
serializeJson(root, buffer);
|
serializeJson(root, buffer);
|
||||||
|
|
||||||
if (Configuration.get().Security_AllowReadonly) {
|
if (Configuration.get().Security_AllowReadonly) {
|
||||||
_ws.setAuthentication("", "");
|
_ws.setAuthentication("", "");
|
||||||
} else {
|
} else {
|
||||||
_ws.setAuthentication(AUTH_USERNAME, Configuration.get().Security_Password);
|
_ws.setAuthentication(AUTH_USERNAME, Configuration.get().Security_Password);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ws.textAll(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ws.textAll(buffer);
|
} catch (std::bad_alloc& bad_alloc) {
|
||||||
|
MessageOutput.printf("Call to /api/livedata/status temporarely out of resources. Reason: \"%s\".\r\n", bad_alloc.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastWsPublish = millis();
|
_lastWsPublish = millis();
|
||||||
@ -220,11 +225,18 @@ void WebApiWsLiveClass::onLivedataStatus(AsyncWebServerRequest* request)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse(false, 40960U);
|
try {
|
||||||
JsonVariant root = response->getRoot();
|
AsyncJsonResponse* response = new AsyncJsonResponse(false, 40960U);
|
||||||
|
JsonVariant root = response->getRoot();
|
||||||
|
|
||||||
generateJsonResponse(root);
|
generateJsonResponse(root);
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
|
||||||
|
} catch (std::bad_alloc& bad_alloc) {
|
||||||
|
MessageOutput.printf("Call to /api/livedata/status temporarely out of resources. Reason: \"%s\".\r\n", bad_alloc.what());
|
||||||
|
|
||||||
|
WebApi.sendTooManyRequests(request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user