arduino-sketches/esp32/ServerConnector.h

294 lines
7.8 KiB
C++

#include "freertos/portable.h"
#include "alarm.h"
#include "Times.h"
#include <HTTPClient.h>
#include <iostream>
#include <ArduinoJson.h>
class ServerConnector
{
private:
AlarmStatus *status;
long lastUpdate;
// WiFiClient wifiClient;
CardReader *_cardReader;
const String AUTHORIZED_ENTRANCE = "AUTHORIZE_ENTRANCE";
const String ServerAddress = "alarm.int.francelsoft.com";
// const String ServerAddress = "10.88.88.169:9003";
const String EVEN_TYPE_FIRED = "Fired";
const String EVENT_TYPE_EVENT_UPDATE = "EventUpdate";
const String EVENT_TYPE_UPDATE = "Update";
const String FIELD_DISARM = "disarm";
const String FIELD_ALLOWED_CARDS = "cards";
int failedAttempts;
bool running;
// long lastHeapSize=0;
// long initHeapSize=0;
void HandTask()
{
// if(initHeapSize == 0)
// {
// initHeapSize=xPortGetFreeHeapSize();
// }
// long currentHeapSize=0;
running = true;
for (;;)
{
// every 15 seconds ask for update: DISSARM & CARDS
unsigned long currentMillis = millis();
if (lastUpdate + FromSeconds(15) < currentMillis)
{
lastUpdate = currentMillis;
// currentHeapSize= xPortGetFreeHeapSize();
// if(abs(currentHeapSize - lastHeapSize) > 32)
// {
// Serial.print("[MEMORY] xPortGetFreeHeapSize: "); Serial.print(currentHeapSize);
// Serial.print( "| Total Variation: "); Serial.print(currentHeapSize - initHeapSize);
// Serial.print(" | Variation: "); Serial.println(currentHeapSize - lastHeapSize);
// lastHeapSize=currentHeapSize;
// }
if(failedAttempts == 5)
{
Serial.println("[HTTP] 5 fail connections, restarting thread.");
failedAttempts=6;
running=false;
vTaskDelete(NULL);
return;
}
if(!CheckWifiConnection()){
Serial.println("[HTTP] could not recconect, trying later");
continue;
}
RequestUpdate();
}
if (!status->sendNotif && !status->isFired)
{
vTaskDelay(100 / portTICK_PERIOD_MS);
continue;
}
if (status->sendNotif)
{
status->eventId = currentMillis;
}
SendAlarm();
status->sendNotif = false;
vTaskDelay(FromSeconds(3) / portTICK_PERIOD_MS);
}
}
bool CheckWifiConnection()
{
if(failedAttempts >= 10)
{
Serial.println("[HTTP] Too many faliures, restarting system");
ESP.restart();
}
if(WiFi.status() == WL_CONNECTED){
return true;
}
Serial.println("[HTTP] Reconnecting to WiFi...");
WiFi.disconnect();
WiFi.reconnect();
return (WiFi.status() == WL_CONNECTED);
}
void SendAlarm()
{
String eventtype = status->sendNotif ? EVEN_TYPE_FIRED : EVENT_TYPE_EVENT_UPDATE;
String url = "http://" + ServerAddress + "/?eventId=" + String(status->eventId) + "&eventType=" + eventtype + "&eventData=t";
Serial.println("[HTTP] Contacting Alarm Server: " + url);
String response = MakeHttpCall(url);
if (response == "")
{
Serial.println("[HTTP] Alarm Server not recheable");
return;
}
if (response == AUTHORIZED_ENTRANCE)
{
// Todo Extract to Disarm method
Serial.println("[HTTP] Entrace authorized by server.");
status->isFired = false;
status->isArmed = status->doorStatus == DOOR_CLOSED;
}
}
void RequestUpdate()
{
StaticJsonDocument<200> docStatus;
docStatus["doorStatus"] = status->doorStatus;
docStatus["armed"] = status->isArmed;
docStatus["fireing"] = status->isFired;
docStatus["lastUser"] = status->userAllowed;
docStatus["lastEntrance"] = status->lastEntrance;
docStatus["millis"] = millis();
String jsonString;
serializeJson(docStatus, jsonString);
String encodedJson = standardUrlEncode(jsonString);
String url = "http://" + ServerAddress + "/?eventId=0&eventType=" + EVENT_TYPE_UPDATE + "&eventData=" + encodedJson;
// Serial.println(url);
String response = MakeHttpCall(url);
if (response == "")
{
Serial.println("[HTTP] Update Server not recheable");
return;
}
JsonDocument doc;
deserializeJson(doc, response);
DeserializationError error = deserializeJson(doc, response);
if (error)
{
Serial.print("[HTTP] Serialize error: ");
Serial.println(error.c_str());
return;
}
if (doc[FIELD_DISARM].is<bool>() && doc[FIELD_DISARM])
{
// disarm requested
// Todo Extract to Disarm method, and add to alarm.h
// same in card reader
Serial.println("[HTTP] Disarm request by server");
status->isArmed = false;
status->isFired = false;
status->lastEntrance = millis();
}
// Serial.print(FIELD_ALLOWED_CARDS);
int cardsNo = doc[FIELD_ALLOWED_CARDS].size();
for (int i = 0; i < cardsNo; i++)
{
_cardReader->AddUser(doc[FIELD_ALLOWED_CARDS][i]["id"], doc[FIELD_ALLOWED_CARDS][i]["name"]);
}
}
String MakeHttpCall(String url)
{
HTTPClient http;
http.setReuse(false);
// if (!http.begin(wifiClient, url))
if (!http.begin(url))
{
failedAttempts= failedAttempts + 1;
Serial.println("[HTTP] not able to start http call");
http.end();
return "";
}
int httpCode = http.GET();
// httpCode will be negative on error
// Serial.printf("[HTTP] wifi.available: %d, connected: %d \r\n", wifiClient.available(), wifiClient.connected());
// Serial.printf("[HTTP] http.connected: %d \r\n", http.connected());
if (httpCode <= 0)
{
failedAttempts= failedAttempts + 1;
Serial.printf("[HTTP] Failed connetion - code: %d , error: %s\r\n", httpCode, http.errorToString(httpCode).c_str());
http.end();
return "";
}
// HTTP header has been send and Server response header has been handled
// Serial.printf("[HTTPS] GET Finished... code: %d\n", httpCode);
// file found at server
if (httpCode != HTTP_CODE_OK)
{
failedAttempts= failedAttempts + 1;
Serial.println("[HTTP] Server responded non 200 code");
http.end();
return "";
}
// print server response payload
failedAttempts=0;
String payload = http.getString();
http.end();
return payload;
}
String standardUrlEncode(const String &str) {
String encoded = "";
char c;
char code0;
char code1;
for (size_t i = 0; i < str.length(); i++) {
c = str.charAt(i);
// Check if character is unreserved per RFC 3986
if ((c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
c == '-' || c == '_' || c == '.' || c == '~') {
encoded += c;
} else {
encoded += '%';
code0 = (c >> 4) & 0xF;
code1 = c & 0xF;
encoded += (code0 < 10) ? char(code0 + '0') : char(code0 - 10 + 'A');
encoded += (code1 < 10) ? char(code1 + '0') : char(code1 - 10 + 'A');
}
}
return encoded;
}
public:
ServerConnector(AlarmStatus *statusObj, CardReader *cardReader)
{
status = statusObj;
running = false;
// wifiClient = new WiFiClient();
_cardReader = cardReader;
failedAttempts=0;
}
bool IsRunning()
{
return running;
}
void StartNotifierAsync()
{
running = true;
BaseType_t xReturned;
TaskHandle_t xHandle = NULL;
xReturned = xTaskCreate(this->asynTask, "sendNotif", 3000, (void *)this, 2, &xHandle);
failedAttempts=0;
Serial.print("Start: "); Serial.println(xReturned == pdPASS ? "Pass" : "Not pass");
Serial.print("Status: "); Serial.println(eTaskGetState(xHandle));
}
static void asynTask(void *pvParameter)
{
ServerConnector *serverInstance = (ServerConnector *)pvParameter;
serverInstance->HandTask();
}
};