TKK_E32230348/upsSvr.h

432 lines
13 KiB
C

//todo:
// - more accurate TX/RX indication (for security concern), e.g. favicon is served static, thus not display TX/RX arrow.
// - Login and apikey access for next version
#include "wifi.h"
#include "upsCfg.h"
#ifndef UPSIO_H
#include "upsIo.h"
#endif
//#include <AsyncTCP.h> //for esp32
#include <ESPAsyncTCP.h> //for esp8266
#include <ESPAsyncWebServer.h>
int8_t wifiStatePrev = 99;
bool configChanged = false;
AsyncWebServer server(80);
void applyConfigs(){
autoPowerOn = (cfgAutoOn >= AUTO_POWER_ON); //auto power on
//cfgChargeMode: charge mode:
switch (cfgChargeMode){
case CHARGE_MODE_ALWAYS:{
chargeAlwaysActive = true;
}
break;
case CHARGE_MODE_RANGE_90_100:{
chargeAlwaysActive = false;
chargeToFull = true;
chargePercentageForStop = 100;
chargePercentageForResume = 90;
}
break;
case CHARGE_MODE_RANGE_85_100:{
chargeAlwaysActive = false;
chargeToFull = true;
chargePercentageForStop = 100;
chargePercentageForResume = 85;
}
break;
case CHARGE_MODE_RANGE_80_100:{
chargeAlwaysActive = false;
chargeToFull = true;
chargePercentageForStop = 100;
chargePercentageForResume = 80;
}
break;
case CHARGE_MODE_RANGE_90_95:{
chargeAlwaysActive = false;
chargeToFull = false;
chargePercentageForStop = 95;
chargePercentageForResume = 90;
}
break;
case CHARGE_MODE_RANGE_85_95:{
chargeAlwaysActive = false;
chargeToFull = true;
chargePercentageForStop = 95;
chargePercentageForResume = 85;
}
break;
case CHARGE_MODE_RANGE_80_95:{
chargeAlwaysActive = false;
chargeToFull = true;
chargePercentageForStop = 95;
chargePercentageForResume = 80;
}
break;
case CHARGE_MODE_RANGE_85_90:{
chargeAlwaysActive = false;
chargeToFull = true;
chargePercentageForStop = 90;
chargePercentageForResume = 85;
}
break;
case CHARGE_MODE_RANGE_80_90:{
chargeAlwaysActive = false;
chargeToFull = true;
chargePercentageForStop = 90;
chargePercentageForResume = 80;
}
break;
case CHARGE_MODE_RANGE_80_85:{
chargeAlwaysActive = false;
chargeToFull = true;
chargePercentageForStop = 85;
chargePercentageForResume = 80;
}
break;
}
//cfgInputLostTriggerChargeMode:
switch (cfgInputLostTriggerChargeMode){
case INPUT_LOST_TRIGGER_CHARGE_NONE:{
chargeAfterInputLost = false;
}
break;
case INPUT_LOST_TRIGGER_CHARGE_ACTIVE_FULL_ALWAYS:{
chargeAfterInputLost = true;
fullChargeAfterInputLost = true;
}
break;
case INPUT_LOST_TRIGGER_CHARGE_ACTIVE_FULL_95:{
chargeAfterInputLost = true;
fullChargeAfterInputLost = false;
triggerFullChargeAfterInputLostAtPercentage = 95;
}
break;
case INPUT_LOST_TRIGGER_CHARGE_ACTIVE_FULL_90:{
chargeAfterInputLost = true;
fullChargeAfterInputLost = false;
triggerFullChargeAfterInputLostAtPercentage = 90;
}
break;
case INPUT_LOST_TRIGGER_CHARGE_ACTIVE_FULL_85:{
chargeAfterInputLost = true;
fullChargeAfterInputLost = false;
triggerFullChargeAfterInputLostAtPercentage = 85;
}
break;
case INPUT_LOST_TRIGGER_CHARGE_ACTIVE_FULL_80:{
chargeAfterInputLost = true;
fullChargeAfterInputLost = false;
triggerFullChargeAfterInputLostAtPercentage = 80;
}
break;
}
//cfgChargeOvervoltageProtection:
chargeOvervoltageProtection = (cfgChargeOvervoltageProtection > 0);
//cfgChargeAutomaticReducer:
chargeReduceAtBatteryFull = (cfgChargeAutomaticReducer > 0);
}
bool getShutdownSuggestionFlag(){
if (cfgShutdownSuggestion==SHUTDOWN_SUGGESTION_DISABLED) return false;
if (!startupReady) return false;
switch(cfgShutdownSuggestion){
case SHUTDOWN_SUGGESTION_ON_BATT:{
return powerOutputActive && !inputVoltageKeepup;
}
break;
case SHUTDOWN_SUGGESTION_ON_BATT_75:{
return powerOutputActive && !inputVoltageKeepup && (batteryLevel<=3);
}
break;
case SHUTDOWN_SUGGESTION_ON_BATT_50:{
return powerOutputActive && !inputVoltageKeepup && (batteryLevel<=2);
}
break;
case SHUTDOWN_SUGGESTION_ON_BATT_25:{
return powerOutputActive && !inputVoltageKeepup && (batteryLevel<=1);
}
break;
case SHUTDOWN_SUGGESTION_ON_BATT_CRITICAL:{
return powerOutputActive && !inputVoltageKeepup && (batteryLevel<=1) && isUpsBatteryCritical();
}
break;
default:{
return false;
}
}
return false;
}
void handleGetState(AsyncWebServerRequest *request) {
setNetworkIndicatorInTransmission(true, false);
bool isRefresh = true;
String v = "";
uint8_t i = 0;
if (request->hasParam("on")) {
isRefresh = false;
v = request->getParam("on")->value();
bool tgtState = v != "0";
Serial.print("Switch request: ");
Serial.println(tgtState);
if (tgtState != powerOutputActive) {
setOutputPowerState(tgtState);
Serial.println("Switching...");
}
}
if (request->hasParam("auto")) {
isRefresh = false;
v = request->getParam("auto")->value();
uint8_t tmpAutoOnMode = v.toInt();
if ((tmpAutoOnMode != cfgAutoOn) && (tmpAutoOnMode <= AUTO_POWER_PERSIST) ) {
cfgAutoOn = tmpAutoOnMode;
configChanged = true;
}
}
if (request->hasParam("shutdown")) {
isRefresh = false;
v = request->getParam("shutdown")->value();
uint16_t tSec = v.toInt();
if (tSec > 999) tSec = 999;
uint32_t nanoT = ((uint32_t)tSec) * 1000000UL;
if (nanoT < 999999) nanoT = 999999;
bool ok = setPersistentShutdown(nanoT);
if ((cfgShutdownInSeconds != tSec && ok)){
cfgShutdownInSeconds = tSec;
configChanged = true;
}
Serial.print("Timed Shutdown request: "); Serial.println(tSec);
//Serial.println(ok);
}
if (request->hasParam("shutlv")) {
isRefresh = false;
v = request->getParam("shutlv")->value();
int16_t lv = v.toInt();
if (lv >= SHUTDOWN_SUGGESTION_DISABLED && lv <= SHUTDOWN_SUGGESTION_ON_BATT_CRITICAL) {
if (lv != cfgShutdownSuggestion) {
cfgShutdownSuggestion = lv;
configChanged = true;
Serial.print("Shutdown level changed: ");
Serial.println(lv);
}
} else {
Serial.print("Invalid shutdown level: ");
Serial.println(v);
}
}
//battery management params:
//cfgChargeMode (charge mode):
if (request->hasParam("cm")) {
isRefresh = false;
v = request->getParam("cm")->value();
i = v.toInt();
if (i<=CHARGE_MODE_RANGE_80_85){
cfgChargeMode = i;
configChanged = true;
Serial.print("CM: "); Serial.println(i);
}
}
//cfgInputLostTriggerChargeMode (charge on input lost):
if (request->hasParam("coil")) {
isRefresh = false;
v = request->getParam("coil")->value();
i = v.toInt();
if (i<=INPUT_LOST_TRIGGER_CHARGE_ACTIVE_FULL_80){
cfgInputLostTriggerChargeMode = i;
configChanged = true;
Serial.print("COIL: "); Serial.println(i);
}
}
//cfgChargeOvervoltageProtection (charge overvoltage protection):
if (request->hasParam("covp")) {
isRefresh = false;
v = request->getParam("covp")->value();
i = v.toInt();
if (i>1) i = 1;
if (i!=cfgChargeOvervoltageProtection){
cfgChargeOvervoltageProtection = i;
configChanged = true;
Serial.print("COVP: "); Serial.println(i);
}
}
//reset "On-Going Full Charge" triggered after input lost (reset ongoing full charge):
if (request->hasParam("rofc")) {
isRefresh = false;
v = request->getParam("rofc")->value();
i = v.toInt();
if (i>0 && needFullChargeOnce) {
resetOnGoingFullChargeAfterLineLost();
Serial.print("ROFC: "); Serial.println(i);
}
}
//cfgChargeAutomaticReducer (charge automatic reducer)
if (request->hasParam("car")) {
isRefresh = false;
v = request->getParam("car")->value();
i = v.toInt();
if (i>1) i = 1;
if (i!=cfgChargeAutomaticReducer){
cfgChargeAutomaticReducer = i;
configChanged = true;
Serial.print("CAR: "); Serial.println(i);
}
}
DynamicJsonDocument jsonDoc(1024);
String jsonResponse;
//String stateOn = isUpsOn()?"1":"0";
//String autoOn = String(cfgAutoOn);
//String voltageValue = String(batteryVoltage, 2);
//2 battery, 1 Input line or AC, 0 OFF
//String lineActive = isUpsPoweredFromBattery()?"2":isInputLinePowered()?"1":isUpsOn()?"2":"0";
uint8_t lineActiveState = isUpsPoweredFromBattery()?2:isInputLinePowered()?1:isUpsOn()?2:0;
//String batt = String(batteryLevel);
//String battMax = "4";
// String battBlink = IsUpsChargingOrBlink()?"1":"0";
// String chargeLv = IsUpsChargingOrBlink()?(String(UpsBattMinimalLevelUnderChargingOrBlink())):(String(UpsBatteryLevel()));
// String battCritical = IsUpsBatteryCritical()?"1":"0";
// String isTimedShut = timedShutdownFlag?"1":"0";
// String onShutRemaining = String(GetShutdownCountdown());
// String shutdownSuggest = GetShutdownSuggestionFlag()?"1":"0";
// String shutdownSuggestMode = String(cfgShutdownSuggestion);
// String shutdownLastPeriod = String(timeShutdownLastPeriod);
//json vars:
jsonDoc["success"] = isRefresh ? 2 : 1;
jsonDoc["on"] = powerOutputActive?1:0;;
jsonDoc["state"] = isUpsOn()?1:0;
jsonDoc["v"] = String(batteryVoltage, 2);
jsonDoc["batt"] = batteryLevel;
jsonDoc["battP"] = batteryPercentage;
jsonDoc["line"] = lineActiveState;
jsonDoc["auto"] = cfgAutoOn;
jsonDoc["battBlink"] = isUpsBatteryIndicatorChargingOrBlink()?1:0;
jsonDoc["battCritical"] = isUpsBatteryCritical()?1:0;
jsonDoc["chargeLv"] = getRawBatteryLevelFromPercentage(batteryPercentage); //real level
jsonDoc["batt"] = batteryLevel; //staged level
jsonDoc["battMax"] = 4;
jsonDoc["timedShutdown"] = (persistentShutdown && powerOutputActive)?1:0;
jsonDoc["shutdownRemain"] = getPersistentShutdownTick()/1000000;
jsonDoc["shutdownSuggestMode"] = cfgShutdownSuggestion;
jsonDoc["shutdownSuggest"] = getShutdownSuggestionFlag()?1:0; //internal flag raised if cfgShutdownSuggestion fullfill the condition
jsonDoc["shutLastTimer"] = cfgShutdownInSeconds;
//charge configuration:
jsonDoc["chgError"] = chargeError; //error state
jsonDoc["charging"] = getChargingState(); //on charging state
jsonDoc["chgMode"] = cfgChargeMode;
jsonDoc["chgOVP"] = cfgChargeOvervoltageProtection; //over voltage protection
jsonDoc["chgReducer"] = cfgChargeAutomaticReducer;
jsonDoc["chgFullTrig"] = cfgInputLostTriggerChargeMode;
jsonDoc["chgOFC"] = needFullChargeOnce?1:0; //when input lost and "Ongoing Full Charge" flag triggered
serializeJson(jsonDoc, jsonResponse);
request->send(200, "application/json", jsonResponse);
setNetworkIndicatorInTransmission(true, true);
}
void onRootRequest(AsyncWebServerRequest *request) {
setNetworkIndicatorInTransmission(true, false);
Serial.println("onRootRequest");
bool isOK = false;
if (spiffsOk) {
if (SPIFFS.exists("/index.html")) {
isOK = true;
request->send(SPIFFS, "/index.html", "text/html");
setNetworkIndicatorInTransmission(true, true);
}
}
if (!isOK) {
request->send(404, "text/text", "404: Not Found");
setNetworkIndicatorInTransmission(true, true);
}
}
void upsServerInit() {
bool b = initConfigs();
if (b){
loadCfg();
applyConfigs();
}
//transfer configuration to ups library:
if (cfgAutoOn >= AUTO_POWER_ON) {
autoPowerOn = true;
restartAutoPowerOn();
} else {
autoPowerOn = false;
}
//for favicon
server.serveStatic("/favicon.ico", SPIFFS, "/favicon.ico");
server.serveStatic("*/favicon.ico", SPIFFS, "/favicon.ico");
//for RESTapi
server.on("/state", HTTP_GET, handleGetState);
//root
server.on("/", onRootRequest);
server.on("/*", onRootRequest);
//Redirect all not-found requests to the root
server.onNotFound(onRootRequest);
server.begin();
Serial.println("Server is running!");
}
void upsServerRoutine() {
WiFiManagerRoutine();
//updating wifi state:
if (wifiCurrentState != wifiStatePrev) {
wifiStatePrev = wifiCurrentState;
setNetworkState(wifiStatePrev);
}
//update signal:
indicatorNetworkSignalLevel = wifiSignalLevel;
//manage auto on mode:
if (cfgAutoOn == AUTO_POWER_PERSIST) {
if (inputVoltageKeepup && inputVoltageOK) {
if (restartAutoPowerOn()) Serial.println("Automatic ON restarted");
}
}
//if button long pressed -------------------------------------------
if (buttonLongPressIgnore && buttonLongPress){
buttonLongPressIgnore = true;
Serial.println("Long Pressed Button Action is Reserved!");
//(not used)
}
//------------------------------------------------------------------
//saving configuration:
if (configChanged) {
configChanged = false;
saveCfg();
applyConfigs();
}
}