ve.direct rest api
This commit is contained in:
parent
2ff8f84387
commit
72c0e8579a
@ -12,6 +12,7 @@
|
|||||||
#include "WebApi_sysstatus.h"
|
#include "WebApi_sysstatus.h"
|
||||||
#include "WebApi_webapp.h"
|
#include "WebApi_webapp.h"
|
||||||
#include "WebApi_ws_live.h"
|
#include "WebApi_ws_live.h"
|
||||||
|
#include "WebApi_ws_vedirect_live.h"
|
||||||
#include "WebApi_vedirect.h"
|
#include "WebApi_vedirect.h"
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
@ -36,6 +37,7 @@ private:
|
|||||||
WebApiSysstatusClass _webApiSysstatus;
|
WebApiSysstatusClass _webApiSysstatus;
|
||||||
WebApiWebappClass _webApiWebapp;
|
WebApiWebappClass _webApiWebapp;
|
||||||
WebApiWsLiveClass _webApiWsLive;
|
WebApiWsLiveClass _webApiWsLive;
|
||||||
|
WebApiWsVedirectLiveClass _webApiWsVedirectLive;
|
||||||
WebApiVedirectClass _webApiVedirect;
|
WebApiVedirectClass _webApiVedirect;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
26
include/WebApi_ws_vedirect_live.h
Normal file
26
include/WebApi_ws_vedirect_live.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ArduinoJson.h"
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
#include <VeDirectFrameHandler.h>
|
||||||
|
|
||||||
|
class WebApiWsVedirectLiveClass {
|
||||||
|
public:
|
||||||
|
WebApiWsVedirectLiveClass();
|
||||||
|
void init(AsyncWebServer* server);
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void generateJsonResponse(JsonVariant& root);
|
||||||
|
void onLivedataStatus(AsyncWebServerRequest* request);
|
||||||
|
void onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);
|
||||||
|
|
||||||
|
AsyncWebServer* _server;
|
||||||
|
AsyncWebSocket _ws;
|
||||||
|
|
||||||
|
uint32_t _lastWsPublish = 0;
|
||||||
|
uint32_t _lastVedirectUpdateCheck = 0;
|
||||||
|
unsigned long _lastWsCleanup = 0;
|
||||||
|
uint32_t _newestVedirectTimestamp = 0;
|
||||||
|
};
|
||||||
@ -206,6 +206,7 @@ void VeDirectFrameHandler::frameEndEvent(bool valid) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setLastUpdate();
|
||||||
}
|
}
|
||||||
frameIndex = 0; // reset frame
|
frameIndex = 0; // reset frame
|
||||||
}
|
}
|
||||||
@ -223,9 +224,436 @@ void VeDirectFrameHandler::logE(const char * module, const char * error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hexRxEvent
|
* getLastUpdate
|
||||||
* This function included for continuity and possible future use.
|
* This function returns the timestamp of the last succesful read of a ve.direct frame.
|
||||||
*/
|
*/
|
||||||
bool VeDirectFrameHandler::hexRxEvent(uint8_t inbyte) {
|
bool VeDirectFrameHandler::hexRxEvent(uint8_t inbyte) {
|
||||||
return true; // stubbed out for future
|
return true; // stubbed out for future
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t VeDirectFrameHandler::getLastUpdate()
|
||||||
|
{
|
||||||
|
return _lastUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* setLastUpdate
|
||||||
|
* This function is called every time a new ve.direct frame was read.
|
||||||
|
*/
|
||||||
|
void VeDirectFrameHandler::setLastUpdate()
|
||||||
|
{
|
||||||
|
_lastUpdate = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getPidAsString
|
||||||
|
* This function returns the product id (PID) as readable text.
|
||||||
|
*/
|
||||||
|
String VeDirectFrameHandler::getPidAsString(const char* pid)
|
||||||
|
{
|
||||||
|
String strPID ="";
|
||||||
|
|
||||||
|
long lPID = strtol(pid, nullptr, 0);
|
||||||
|
switch(lPID) {
|
||||||
|
case 0x0300:
|
||||||
|
strPID = "BlueSolar MPPT 70|15";
|
||||||
|
break;
|
||||||
|
case 0xA040:
|
||||||
|
strPID = "BlueSolar MPPT 75|50";
|
||||||
|
break;
|
||||||
|
case 0xA041:
|
||||||
|
strPID = "BlueSolar MPPT 150|35";
|
||||||
|
break;
|
||||||
|
case 0xA042:
|
||||||
|
strPID = "BlueSolar MPPT 75|15";
|
||||||
|
break;
|
||||||
|
case 0xA043:
|
||||||
|
strPID = "BlueSolar MPPT 100|15";
|
||||||
|
break;
|
||||||
|
case 0xA044:
|
||||||
|
strPID = "BlueSolar MPPT 100|30";
|
||||||
|
break;
|
||||||
|
case 0xA045:
|
||||||
|
strPID = "BlueSolar MPPT 100|50";
|
||||||
|
break;
|
||||||
|
case 0xA046:
|
||||||
|
strPID = "BlueSolar MPPT 100|70";
|
||||||
|
break;
|
||||||
|
case 0xA047:
|
||||||
|
strPID = "BlueSolar MPPT 150|100";
|
||||||
|
break;
|
||||||
|
case 0xA049:
|
||||||
|
strPID = "BlueSolar MPPT 100|50 rev2";
|
||||||
|
break;
|
||||||
|
case 0xA04A:
|
||||||
|
strPID = "BlueSolar MPPT 100|30 rev2";
|
||||||
|
break;
|
||||||
|
case 0xA04B:
|
||||||
|
strPID = "BlueSolar MPPT 150|35 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA04C:
|
||||||
|
strPID = "BlueSolar MPPT 75|10";
|
||||||
|
break;
|
||||||
|
case 0XA04D:
|
||||||
|
strPID = "BlueSolar MPPT 150|45";
|
||||||
|
break;
|
||||||
|
case 0XA04E:
|
||||||
|
strPID = "BlueSolar MPPT 150|60";
|
||||||
|
break;
|
||||||
|
case 0XA04F:
|
||||||
|
strPID = "BlueSolar MPPT 150|85";
|
||||||
|
break;
|
||||||
|
case 0XA050:
|
||||||
|
strPID = "SmartSolar MPPT 250|100";
|
||||||
|
break;
|
||||||
|
case 0XA051:
|
||||||
|
strPID = "SmartSolar MPPT 150|100";
|
||||||
|
break;
|
||||||
|
case 0XA052:
|
||||||
|
strPID = "SmartSolar MPPT 150|85";
|
||||||
|
break;
|
||||||
|
case 0XA053:
|
||||||
|
strPID = "SmartSolar MPPT 75|15";
|
||||||
|
break;
|
||||||
|
case 0XA054:
|
||||||
|
strPID = "SmartSolar MPPT 75|10";
|
||||||
|
break;
|
||||||
|
case 0XA055:
|
||||||
|
strPID = "SmartSolar MPPT 100|15";
|
||||||
|
break;
|
||||||
|
case 0XA056:
|
||||||
|
strPID = "SmartSolar MPPT 100|30";
|
||||||
|
break;
|
||||||
|
case 0XA057:
|
||||||
|
strPID = "SmartSolar MPPT 100|50";
|
||||||
|
break;
|
||||||
|
case 0XA058:
|
||||||
|
strPID = "SmartSolar MPPT 100|35";
|
||||||
|
break;
|
||||||
|
case 0XA059:
|
||||||
|
strPID = "SmartSolar MPPT 150|10 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA05A:
|
||||||
|
strPID = "SmartSolar MPPT 150|85 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA05B:
|
||||||
|
strPID = "SmartSolar MPPT 250|70";
|
||||||
|
break;
|
||||||
|
case 0XA05C:
|
||||||
|
strPID = "SmartSolar MPPT 250|85";
|
||||||
|
break;
|
||||||
|
case 0XA05D:
|
||||||
|
strPID = "SmartSolar MPPT 250|60";
|
||||||
|
break;
|
||||||
|
case 0XA05E:
|
||||||
|
strPID = "SmartSolar MPPT 250|45";
|
||||||
|
break;
|
||||||
|
case 0XA05F:
|
||||||
|
strPID = "SmartSolar MPPT 100|20";
|
||||||
|
break;
|
||||||
|
case 0XA060:
|
||||||
|
strPID = "SmartSolar MPPT 100|20 48V";
|
||||||
|
break;
|
||||||
|
case 0XA061:
|
||||||
|
strPID = "SmartSolar MPPT 150|45";
|
||||||
|
break;
|
||||||
|
case 0XA062:
|
||||||
|
strPID = "SmartSolar MPPT 150|60";
|
||||||
|
break;
|
||||||
|
case 0XA063:
|
||||||
|
strPID = "SmartSolar MPPT 150|70";
|
||||||
|
break;
|
||||||
|
case 0XA064:
|
||||||
|
strPID = "SmartSolar MPPT 250|85 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA065:
|
||||||
|
strPID = "SmartSolar MPPT 250|100 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA066:
|
||||||
|
strPID = "BlueSolar MPPT 100|20";
|
||||||
|
break;
|
||||||
|
case 0XA067:
|
||||||
|
strPID = "BlueSolar MPPT 100|20 48V";
|
||||||
|
break;
|
||||||
|
case 0XA068:
|
||||||
|
strPID = "SmartSolar MPPT 250|60 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA069:
|
||||||
|
strPID = "SmartSolar MPPT 250|70 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA06A:
|
||||||
|
strPID = "SmartSolar MPPT 150|45 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA06B:
|
||||||
|
strPID = "SmartSolar MPPT 150|60 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA06C:
|
||||||
|
strPID = "SmartSolar MPPT 150|70 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA06D:
|
||||||
|
strPID = "SmartSolar MPPT 150|85 rev3";
|
||||||
|
break;
|
||||||
|
case 0XA06E:
|
||||||
|
strPID = "SmartSolar MPPT 150|100 rev3";
|
||||||
|
break;
|
||||||
|
case 0XA06F:
|
||||||
|
strPID = "BlueSolar MPPT 150|45 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA070:
|
||||||
|
strPID = "BlueSolar MPPT 150|60 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA071:
|
||||||
|
strPID = "BlueSolar MPPT 150|70 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA102:
|
||||||
|
strPID = "SmartSolar MPPT VE.Can 150|70";
|
||||||
|
break;
|
||||||
|
case 0XA103:
|
||||||
|
strPID = "SmartSolar MPPT VE.Can 150|45";
|
||||||
|
break;
|
||||||
|
case 0XA104:
|
||||||
|
strPID = "SmartSolar MPPT VE.Can 150|60";
|
||||||
|
break;
|
||||||
|
case 0XA105:
|
||||||
|
strPID = "SmartSolar MPPT VE.Can 150|85";
|
||||||
|
break;
|
||||||
|
case 0XA106:
|
||||||
|
strPID = "SmartSolar MPPT VE.Can 150|100";
|
||||||
|
break;
|
||||||
|
case 0XA107:
|
||||||
|
strPID = "SmartSolar MPPT VE.Can 250|45";
|
||||||
|
break;
|
||||||
|
case 0XA108:
|
||||||
|
strPID = "SmartSolar MPPT VE.Can 250|60";
|
||||||
|
break;
|
||||||
|
case 0XA109:
|
||||||
|
strPID = "SmartSolar MPPT VE.Can 250|80";
|
||||||
|
break;
|
||||||
|
case 0XA10A:
|
||||||
|
strPID = "SmartSolar MPPT VE.Can 250|85";
|
||||||
|
break;
|
||||||
|
case 0XA10B:
|
||||||
|
strPID = "SmartSolar MPPT VE.Can 250|100";
|
||||||
|
break;
|
||||||
|
case 0XA10C:
|
||||||
|
strPID = "SmartSolar MPPT VE.Can 150|70 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA10D:
|
||||||
|
strPID = "SmartSolar MPPT VE.Can 150|85 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA10E:
|
||||||
|
strPID = "SmartSolar MPPT VE.Can 150|100 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA10F:
|
||||||
|
strPID = "BlueSolar MPPT VE.Can 150|100";
|
||||||
|
break;
|
||||||
|
case 0XA112:
|
||||||
|
strPID = "BlueSolar MPPT VE.Can 250|70";
|
||||||
|
break;
|
||||||
|
case 0XA113:
|
||||||
|
strPID = "BlueSolar MPPT VE.Can 250|100";
|
||||||
|
break;
|
||||||
|
case 0XA114:
|
||||||
|
strPID = "SmartSolar MPPT VE.Can 250|70 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA115:
|
||||||
|
strPID = "SmartSolar MPPT VE.Can 250|100 rev2";
|
||||||
|
break;
|
||||||
|
case 0XA116:
|
||||||
|
strPID = "SmartSolar MPPT VE.Can 250|85 rev2";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strPID = pid;
|
||||||
|
}
|
||||||
|
return strPID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getCsAsString
|
||||||
|
* This function returns the state of operations (CS) as readable text.
|
||||||
|
*/
|
||||||
|
String VeDirectFrameHandler::getCsAsString(const char* cs)
|
||||||
|
{
|
||||||
|
String strCS ="";
|
||||||
|
|
||||||
|
int iCS = atoi(cs);
|
||||||
|
switch(iCS) {
|
||||||
|
case 0:
|
||||||
|
strCS = "OFF";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
strCS = "Fault";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
strCS = "Bulk";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
strCS = "Absorbtion";
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
strCS = "Float";
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
strCS = "Equalize (manual)";
|
||||||
|
break;
|
||||||
|
case 245:
|
||||||
|
strCS = "Starting-up";
|
||||||
|
break;
|
||||||
|
case 247:
|
||||||
|
strCS = "Auto equalize / Recondition";
|
||||||
|
break;
|
||||||
|
case 252:
|
||||||
|
strCS = "External Control";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strCS = cs;
|
||||||
|
}
|
||||||
|
return strCS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getErrAsString
|
||||||
|
* This function returns error state (ERR) as readable text.
|
||||||
|
*/
|
||||||
|
String VeDirectFrameHandler::getErrAsString(const char* err)
|
||||||
|
{
|
||||||
|
String strERR ="";
|
||||||
|
|
||||||
|
int iERR = atoi(err);
|
||||||
|
switch(iERR) {
|
||||||
|
case 0:
|
||||||
|
strERR = "No error";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
strERR = "Battery voltage too high";
|
||||||
|
break;
|
||||||
|
case 17:
|
||||||
|
strERR = "Charger temperature too high";
|
||||||
|
break;
|
||||||
|
case 18:
|
||||||
|
strERR = "Charger over current";
|
||||||
|
break;
|
||||||
|
case 19:
|
||||||
|
strERR = "Charger current reversed";
|
||||||
|
break;
|
||||||
|
case 20:
|
||||||
|
strERR = "Bulk time limit exceeded";
|
||||||
|
break;
|
||||||
|
case 21:
|
||||||
|
strERR = "Current sensor issue(sensor bias/sensor broken)";
|
||||||
|
break;
|
||||||
|
case 26:
|
||||||
|
strERR = "Terminals overheated";
|
||||||
|
break;
|
||||||
|
case 28:
|
||||||
|
strERR = "Converter issue (dual converter models only)";
|
||||||
|
break;
|
||||||
|
case 33:
|
||||||
|
strERR = "Input voltage too high (solar panel)";
|
||||||
|
break;
|
||||||
|
case 34:
|
||||||
|
strERR = "Input current too high (solar panel)";
|
||||||
|
break;
|
||||||
|
case 38:
|
||||||
|
strERR = "Input shutdown (due to excessive battery voltage)";
|
||||||
|
break;
|
||||||
|
case 39:
|
||||||
|
strERR = "Input shutdown (due to current flow during off mode)";
|
||||||
|
break;
|
||||||
|
case 40:
|
||||||
|
strERR = "Input";
|
||||||
|
break;
|
||||||
|
case 65:
|
||||||
|
strERR = "39Lost communication with one of devices";
|
||||||
|
break;
|
||||||
|
case 67:
|
||||||
|
strERR = "Synchronisedcharging device configuration issue";
|
||||||
|
break;
|
||||||
|
case 68:
|
||||||
|
strERR = "BMS connection lost";
|
||||||
|
break;
|
||||||
|
case 116:
|
||||||
|
strERR = "Factory calibration data lost";
|
||||||
|
break;
|
||||||
|
case 117:
|
||||||
|
strERR = "Invalid/incompatible firmware";
|
||||||
|
break;
|
||||||
|
case 118:
|
||||||
|
strERR = "User settings invalid";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strERR = err;
|
||||||
|
}
|
||||||
|
return strERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getOrAsString
|
||||||
|
* This function returns the off reason (OR) as readable text.
|
||||||
|
*/
|
||||||
|
String VeDirectFrameHandler::getOrAsString(const char* offReason)
|
||||||
|
{
|
||||||
|
String strOR ="";
|
||||||
|
|
||||||
|
long lOR = strtol(offReason, nullptr, 0);
|
||||||
|
switch(lOR) {
|
||||||
|
case 0x00000000:
|
||||||
|
strOR = "Not off";
|
||||||
|
break;
|
||||||
|
case 0x00000001:
|
||||||
|
strOR = "No input power";
|
||||||
|
break;
|
||||||
|
case 0x00000002:
|
||||||
|
strOR = "Switched off (power switch)";
|
||||||
|
break;
|
||||||
|
case 0x00000004:
|
||||||
|
strOR = "Switched off (device moderegister)";
|
||||||
|
break;
|
||||||
|
case 0x00000008:
|
||||||
|
strOR = "Remote input";
|
||||||
|
break;
|
||||||
|
case 0x00000010:
|
||||||
|
strOR = "Protection active";
|
||||||
|
break;
|
||||||
|
case 0x00000020:
|
||||||
|
strOR = "Paygo";
|
||||||
|
break;
|
||||||
|
case 0x00000040:
|
||||||
|
strOR = "BMS";
|
||||||
|
break;
|
||||||
|
case 0x00000080:
|
||||||
|
strOR = "Engine shutdown detection";
|
||||||
|
break;
|
||||||
|
case 0x00000100:
|
||||||
|
strOR = "Analysing input voltage";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strOR = offReason;
|
||||||
|
}
|
||||||
|
return strOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getMpptAsString
|
||||||
|
* This function returns the state of MPPT (MPPT) as readable text.
|
||||||
|
*/
|
||||||
|
String VeDirectFrameHandler::getMpptAsString(const char* mppt)
|
||||||
|
{
|
||||||
|
String strMPPT ="";
|
||||||
|
|
||||||
|
int iMPPT = atoi(mppt);
|
||||||
|
switch(iMPPT) {
|
||||||
|
case 0:
|
||||||
|
strMPPT = "Off";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
strMPPT = "Voltage or current limited";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
strMPPT = "MPP Tracker active";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strMPPT = mppt;
|
||||||
|
}
|
||||||
|
return strMPPT;
|
||||||
}
|
}
|
||||||
@ -31,6 +31,13 @@ public:
|
|||||||
VeDirectFrameHandler();
|
VeDirectFrameHandler();
|
||||||
void init();
|
void init();
|
||||||
void loop();
|
void loop();
|
||||||
|
uint32_t getLastUpdate();
|
||||||
|
void setLastUpdate();
|
||||||
|
String getPidAsString(const char* pid);
|
||||||
|
String getCsAsString(const char* pid);
|
||||||
|
String getErrAsString(const char* err);
|
||||||
|
String getOrAsString(const char* offReason);
|
||||||
|
String getMpptAsString(const char* mppt);
|
||||||
|
|
||||||
char veName[buffLen][nameLen] = { }; // public buffer for received names
|
char veName[buffLen][nameLen] = { }; // public buffer for received names
|
||||||
char veValue[buffLen][valueLen] = { }; // public buffer for received values
|
char veValue[buffLen][valueLen] = { }; // public buffer for received values
|
||||||
@ -66,6 +73,7 @@ private:
|
|||||||
void frameEndEvent(bool);
|
void frameEndEvent(bool);
|
||||||
void logE(const char *, const char *);
|
void logE(const char *, const char *);
|
||||||
bool hexRxEvent(uint8_t);
|
bool hexRxEvent(uint8_t);
|
||||||
|
uint32_t _lastUpdate = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern VeDirectFrameHandler VeDirect;
|
extern VeDirectFrameHandler VeDirect;
|
||||||
|
|||||||
@ -30,6 +30,7 @@ void WebApiClass::init()
|
|||||||
_webApiSysstatus.init(&_server);
|
_webApiSysstatus.init(&_server);
|
||||||
_webApiWebapp.init(&_server);
|
_webApiWebapp.init(&_server);
|
||||||
_webApiWsLive.init(&_server);
|
_webApiWsLive.init(&_server);
|
||||||
|
_webApiWsVedirectLive.init(&_server);
|
||||||
_webApiVedirect.init(&_server);
|
_webApiVedirect.init(&_server);
|
||||||
|
|
||||||
_server.begin();
|
_server.begin();
|
||||||
@ -48,6 +49,7 @@ void WebApiClass::loop()
|
|||||||
_webApiSysstatus.loop();
|
_webApiSysstatus.loop();
|
||||||
_webApiWebapp.loop();
|
_webApiWebapp.loop();
|
||||||
_webApiWsLive.loop();
|
_webApiWsLive.loop();
|
||||||
|
_webApiWsVedirectLive.loop();
|
||||||
_webApiVedirect.loop();
|
_webApiVedirect.loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
135
src/WebApi_ws_vedirect_live.cpp
Normal file
135
src/WebApi_ws_vedirect_live.cpp
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Thomas Basler and others
|
||||||
|
*/
|
||||||
|
#include "WebApi_ws_vedirect_live.h"
|
||||||
|
#include "AsyncJson.h"
|
||||||
|
#include "Configuration.h"
|
||||||
|
|
||||||
|
WebApiWsVedirectLiveClass::WebApiWsVedirectLiveClass()
|
||||||
|
: _ws("/vedirectlivedata")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebApiWsVedirectLiveClass::init(AsyncWebServer* server)
|
||||||
|
{
|
||||||
|
using namespace std::placeholders;
|
||||||
|
|
||||||
|
_server = server;
|
||||||
|
_server->on("/api/vedirectlivedata/status", HTTP_GET, std::bind(&WebApiWsVedirectLiveClass::onLivedataStatus, this, _1));
|
||||||
|
|
||||||
|
_server->addHandler(&_ws);
|
||||||
|
_ws.onEvent(std::bind(&WebApiWsVedirectLiveClass::onWebsocketEvent, this, _1, _2, _3, _4, _5, _6));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebApiWsVedirectLiveClass::loop()
|
||||||
|
{
|
||||||
|
// see: https://github.com/me-no-dev/ESPAsyncWebServer#limiting-the-number-of-web-socket-clients
|
||||||
|
if (millis() - _lastWsCleanup > 1000) {
|
||||||
|
_ws.cleanupClients();
|
||||||
|
_lastWsCleanup = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
// do nothing if no WS client is connected
|
||||||
|
if (_ws.count() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (millis() - _lastVedirectUpdateCheck < 1000) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_lastVedirectUpdateCheck = millis();
|
||||||
|
|
||||||
|
uint32_t maxTimeStamp = 0;
|
||||||
|
if (VeDirect.getLastUpdate() > maxTimeStamp) {
|
||||||
|
maxTimeStamp = VeDirect.getLastUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update on ve.direct change or at least after 10 seconds
|
||||||
|
if (millis() - _lastWsPublish > (10 * 1000) || (maxTimeStamp != _newestVedirectTimestamp)) {
|
||||||
|
|
||||||
|
DynamicJsonDocument root(40960);
|
||||||
|
JsonVariant var = root;
|
||||||
|
generateJsonResponse(var);
|
||||||
|
|
||||||
|
size_t len = measureJson(root);
|
||||||
|
AsyncWebSocketMessageBuffer* buffer = _ws.makeBuffer(len); // creates a buffer (len + 1) for you.
|
||||||
|
if (buffer) {
|
||||||
|
serializeJson(root, (char*)buffer->get(), len + 1);
|
||||||
|
_ws.textAll(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
_lastWsPublish = millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebApiWsVedirectLiveClass::generateJsonResponse(JsonVariant& root)
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < VeDirect.veEnd; i++ ) {
|
||||||
|
if(strcmp(VeDirect.veName[i], "PID") == 0) {
|
||||||
|
root[F(VeDirect.veName[i])] = VeDirect.getPidAsString(VeDirect.veValue[i]);
|
||||||
|
}
|
||||||
|
else if(strcmp(VeDirect.veName[i], "CS") == 0) {
|
||||||
|
root[F(VeDirect.veName[i])] = VeDirect.getCsAsString(VeDirect.veValue[i]);
|
||||||
|
}
|
||||||
|
else if(strcmp(VeDirect.veName[i], "ERR") == 0) {
|
||||||
|
root[F(VeDirect.veName[i])] = VeDirect.getErrAsString(VeDirect.veValue[i]);
|
||||||
|
}
|
||||||
|
else if(strcmp(VeDirect.veName[i], "OR") == 0) {
|
||||||
|
root[F(VeDirect.veName[i])] = VeDirect.getOrAsString(VeDirect.veValue[i]);
|
||||||
|
}
|
||||||
|
else if(strcmp(VeDirect.veName[i], "MPPT") == 0) {
|
||||||
|
root[F(VeDirect.veName[i])] = VeDirect.getMpptAsString(VeDirect.veValue[i]);
|
||||||
|
}
|
||||||
|
else if((strcmp(VeDirect.veName[i], "V") == 0) || (strcmp(VeDirect.veName[i], "VPV") == 0)) {
|
||||||
|
root[F(VeDirect.veName[i])]["v"] = round(std::stod(VeDirect.veValue[i]) / 10.0) / 100.0;
|
||||||
|
root[F(VeDirect.veName[i])]["u"] = "V";
|
||||||
|
}
|
||||||
|
else if(strcmp(VeDirect.veName[i], "I") == 0) {
|
||||||
|
root[F(VeDirect.veName[i])]["v"] = round(std::stod(VeDirect.veValue[i]) / 10.0) / 100.0;
|
||||||
|
root[F(VeDirect.veName[i])]["u"] = "A";
|
||||||
|
}
|
||||||
|
else if((strcmp(VeDirect.veName[i], "PPV") == 0) || (strcmp(VeDirect.veName[i], "H21") == 0) || (strcmp(VeDirect.veName[i], "H23") == 0)){
|
||||||
|
root[F(VeDirect.veName[i])]["v"] = std::stoi(VeDirect.veValue[i]);
|
||||||
|
root[F(VeDirect.veName[i])]["u"] = "W";
|
||||||
|
}
|
||||||
|
else if((strcmp(VeDirect.veName[i], "H19") == 0) || (strcmp(VeDirect.veName[i], "H20") == 0) || (strcmp(VeDirect.veName[i], "H22") == 0)){
|
||||||
|
root[F(VeDirect.veName[i])]["v"] = std::stod(VeDirect.veValue[i]) / 100.0;
|
||||||
|
root[F(VeDirect.veName[i])]["u"] = "kWh";
|
||||||
|
}
|
||||||
|
else if(strcmp(VeDirect.veName[i], "HSDS") == 0){
|
||||||
|
root[F(VeDirect.veName[i])]["v"] = std::stoi(VeDirect.veValue[i]);
|
||||||
|
root[F(VeDirect.veName[i])]["u"] = "Days";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
root[F(VeDirect.veName[i])] = VeDirect.veValue[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VeDirect.getLastUpdate() > _newestVedirectTimestamp) {
|
||||||
|
_newestVedirectTimestamp = VeDirect.getLastUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebApiWsVedirectLiveClass::onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len)
|
||||||
|
{
|
||||||
|
if (type == WS_EVT_CONNECT) {
|
||||||
|
char str[64];
|
||||||
|
sprintf(str, "Websocket: [%s][%u] connect", server->url(), client->id());
|
||||||
|
Serial.println(str);
|
||||||
|
} else if (type == WS_EVT_DISCONNECT) {
|
||||||
|
char str[64];
|
||||||
|
sprintf(str, "Websocket: [%s][%u] disconnect", server->url(), client->id());
|
||||||
|
Serial.println(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebApiWsVedirectLiveClass::onLivedataStatus(AsyncWebServerRequest* request)
|
||||||
|
{
|
||||||
|
AsyncJsonResponse* response = new AsyncJsonResponse(false, 40960U);
|
||||||
|
JsonVariant root = response->getRoot().as<JsonVariant>();
|
||||||
|
generateJsonResponse(root);
|
||||||
|
|
||||||
|
response->setLength();
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user