Digitum/src/app/routes.cpp
2023-12-22 21:53:13 +03:00

349 lines
10 KiB
C++

#include "app/routes.h"
#include "config/config.h"
#include "utils/print.h"
#include "utils/settings.h"
#include "utils/utils.h"
#include "infra/eth.h"
#include "infra/httpServer.h"
#include "infra/mqtt.h"
#include "infra/relay.h"
#include "infra/fs.h"
#include "infra/intercom.h"
#include "domain/intercomJournal.h"
void handleDoorOpen(AsyncWebServerRequest *request) {
relayTurnOn();
delay(2000);
relayTurnOff();
println("Door is open by ", request->client()->remoteIP().toString());
request->send(200, "text/plain", "OK");
}
void getFeatures(AsyncWebServerRequest *request) {
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_FEATURES_SIZE);
JsonObject root = response->getRoot();
root["project"] = false;
root["security"] = false;
root["mqtt"] = true;
root["ntp"] = false;
root["ota"] = false;
root["upload_firmware"] = true;
response->setLength();
request->send(response);
}
void intercomStatus(AsyncWebServerRequest* request) {
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_INTERCOM_STATUS_SIZE);
JsonObject root = response->getRoot();
root["status"] = (int) getIntercomStatus();
root["lastCalledNumber"] = getLastCalledNumber();
root["doorStatus"] = false;
response->setLength();
request->send(response);
}
static void intercomSettingsRead(AsyncWebServerRequest* request) {
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_INTERCOM_SETTINGS_SIZE);
JsonObject root = response->getRoot();
const size_t CAPACITY = JSON_ARRAY_SIZE(3);
StaticJsonDocument<CAPACITY> modelsDoc;
JsonArray models = modelsDoc.to<JsonArray>();
models.add("Vizit");
models.add("Cyfral");
root["kmnModel"] = "Vizit";
root["firstAppartment"] = 1;
root["kmnModelList"] = models;
response->setLength();
request->send(response);
}
static void intercomJournalRead(AsyncWebServerRequest* request) {
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_INTERCOM_JOURNAL_SIZE);
JsonObject root = response->getRoot();
const size_t CAPACITY = JSON_ARRAY_SIZE(5*INTERCOM_JOURNAL_FLATS_NUMBER);
StaticJsonDocument<CAPACITY> flatsDoc;
JsonArray flats = flatsDoc.to<JsonArray>();
getIntercomJournalAsJson(flats);
root["notes"] = flats;
response->setLength();
request->send(response);
}
static void intercomSettingsUpdate(AsyncWebServerRequest *request,
uint8_t *data, size_t len, size_t index, size_t total) {
DynamicJsonDocument jsonDoc(MAX_INTERCOM_SETTINGS_SIZE);
String jsonStr = requestDataToStr(data, len);
DeserializationError error = deserializeJson(jsonDoc, jsonStr);
if (!jsonDoc.is<JsonVariant>()) {
request->send(400);
return;
}
JsonVariant root = jsonDoc.as<JsonVariant>();
bool success = writeJsonVariantToFile(INTERCOM_SETTINGS_PATH, root);
if (success) {
String jsonString;
serializeJson(root, jsonString);
request->send(200, "application/json", jsonString.c_str());
}
else
request->send(500, "text/plain", "Intercom settings not updated");
configureIntercom(
root["kmnModel"].as<String>(),
root["firstAppartment"].as<int>()
);
}
static void switchDoor(AsyncWebServerRequest *request,
uint8_t *data, size_t len, size_t index, size_t total) {
DynamicJsonDocument jsonDoc(MAX_INTERCOM_SWITCH_DOOR_SIZE);
String jsonStr = requestDataToStr(data, len);
DeserializationError error = deserializeJson(jsonDoc, jsonStr);
if (!jsonDoc.is<JsonVariant>()) {
request->send(400);
return;
}
JsonVariant root = jsonDoc.as<JsonVariant>();
SwitchDoorType switchDoorType = static_cast<SwitchDoorType>(root["type"].as<int>());
DoorStatus doorStatus = static_cast<DoorStatus>(root["status"].as<int>());
switchRelay(
switchDoorType,
doorStatus,
root["time"]
);
request->send(200, "application/json");
}
void networkStatus(AsyncWebServerRequest* request) {
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_NETWORK_STATUS_SIZE);
JsonObject root = response->getRoot();
getEthStatus(root);
response->setLength();
request->send(response);
}
void scanNetworks(AsyncWebServerRequest* request) {
if (WiFi.scanComplete() != -1) {
WiFi.scanDelete();
WiFi.scanNetworks(true);
}
request->send(202);
}
static void networkSettingsRead(AsyncWebServerRequest* request) {
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_NETWORK_SETTINGS_SIZE);
DynamicJsonDocument doc(1024);
bool success = readJsonVariantFromFile(NETWORK_SETTINGS_PATH, doc);
JsonVariant root = doc.as<JsonVariant>();
if (!success)
getDefaultEthConf(root);
response->setLength();
String jsonString;
serializeJson(root, jsonString);
request->send(200, "application/json", jsonString.c_str());
}
static void networkSettingsUpdate(AsyncWebServerRequest *request,
uint8_t *data, size_t len, size_t index, size_t total) {
DynamicJsonDocument jsonDoc(MAX_NETWORK_SETTINGS_SIZE);
String jsonStr = requestDataToStr(data, len);
DeserializationError error = deserializeJson(jsonDoc, jsonStr);
if (!jsonDoc.is<JsonVariant>()) {
request->send(400);
return;
}
JsonVariant root = jsonDoc.as<JsonVariant>();
bool success = writeJsonVariantToFile(NETWORK_SETTINGS_PATH, root);
if (success) {
String jsonString;
serializeJson(root, jsonString);
request->send(200, "application/json", jsonString.c_str());
}
else
request->send(500, "text/plain", "Network settings not updated");
configureEth(
root["static_ip_config"].as<bool>(),
root["local_ip"].as<String>(),
root["gateway_ip"].as<String>(),
root["subnet_mask"].as<String>(),
root["dns_ip"].as<String>()
);
}
static void mqttStatus(AsyncWebServerRequest* request) {
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_MQTT_STATUS_SIZE);
JsonObject root = response->getRoot();
root["enabled"] = getMqttEnabled();
root["connected"] = getMqttClient().connected();
root["client_id"] = getMqttClient().getClientId();
root["disconnect_reason"] = (uint8_t)getMqttDisconnectReason();
response->setLength();
request->send(response);
}
static void mqttSettingsRead(AsyncWebServerRequest* request) {
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_MQTT_SETTINGS_SIZE);
DynamicJsonDocument doc(1024);
bool success = readJsonVariantFromFile(MQTT_SETTINGS_PATH, doc);
JsonVariant root = doc.as<JsonVariant>();
if (!success)
getDefaultMqttConf(root);
response->setLength();
String jsonString;
serializeJson(root, jsonString);
request->send(200, "application/json", jsonString.c_str());
}
static void mqttSettingsUpdate(AsyncWebServerRequest *request,
uint8_t *data, size_t len, size_t index, size_t total) {
DynamicJsonDocument jsonDoc(MAX_MQTT_SETTINGS_SIZE);
String jsonStr = requestDataToStr(data, len);
DeserializationError error = deserializeJson(jsonDoc, jsonStr);
if (!jsonDoc.is<JsonVariant>() || error) {
request->send(400);
return;
}
JsonVariant root = jsonDoc.as<JsonVariant>();
bool fileLoaded = writeJsonVariantToFile(MQTT_SETTINGS_PATH, root);
bool enabled = root["enabled"].as<bool>();
if (!loadMqttConfig())
println("Cannot load MQTT config");
bool mqttConfigured = configureMqtt(
root["enabled"].as<bool>(),
root["host"].as<String>(),
root["port"].as<uint16_t>(),
root["username"].as<String>(),
root["password"].as<String>(),
root["client_id"].as<String>(),
root["keep_alive"].as<uint16_t>(),
root["clean_session"].as<bool>(),
root["max_topic_length"].as<uint16_t>()
);
if (!fileLoaded) {
request->send(500, "text/plain", "MQTT settings not updated");
} else if (!mqttConfigured && enabled) {
request->send(404, "text/plain", "MQTT settings not configured");
} else {
String jsonString;
serializeJson(root, jsonString);
request->send(200, "application/json", jsonString.c_str());
}
}
void systemStatus(AsyncWebServerRequest* request) {
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_ESP_STATUS_SIZE);
JsonObject root = response->getRoot();
root["esp_platform"] = "esp32";
root["max_alloc_heap"] = ESP.getMaxAllocHeap();
root["psram_size"] = ESP.getPsramSize();
root["free_psram"] = ESP.getFreePsram();
root["cpu_freq_mhz"] = ESP.getCpuFreqMHz();
root["free_heap"] = ESP.getFreeHeap();
root["sketch_size"] = ESP.getSketchSize();
root["free_sketch_space"] = ESP.getFreeSketchSpace();
root["sdk_version"] = ESP.getSdkVersion();
root["flash_chip_size"] = ESP.getFlashChipSize();
root["flash_chip_speed"] = ESP.getFlashChipSpeed();
root["fs_total"] = LittleFS.totalBytes();
root["fs_used"] = LittleFS.usedBytes();
response->setLength();
request->send(response);
}
void handleDoorStatus(AsyncWebServerRequest *request) {
request->send(200, "text/plain", "OK");
}
void handleBodyRequest(AsyncWebServer& server, const char* uri, WebRequestMethodComposite method,
ArJsonRequestHandlerFunction onRequest) {
AsyncCallbackJsonWebHandler* handler = \
new AsyncCallbackJsonWebHandler(uri, onRequest);
handler->setMethod(method);
server.addHandler(handler);
}
void restartNow(AsyncWebServerRequest *request) {
request->send(200, "text/plain", "OK");
ESP.restart();
}
void factoryReset(AsyncWebServerRequest *request) {
deleteFilesInDir(FS_CONFIG_DIRECTORY);
restartNow(request);
}
void initRoutes() {
AsyncWebServer& server = getServer();
server.on("/api/v1/door/open", handleDoorOpen);
server.on("/api/v1/door/status", handleDoorStatus);
server.on("/api/v1/features", getFeatures);
server.on("/api/v1/networkStatus", networkStatus);
server.on("/api/v1/networkSettings", HTTP_GET, networkSettingsRead);
server.on("/api/v1/networkSettings", HTTP_POST, [](AsyncWebServerRequest *request) {}, NULL, networkSettingsUpdate);
server.on("/api/v1/intercomStatus", intercomStatus);
server.on("/api/v1/intercomJournal", intercomJournalRead);
server.on("/api/v1/intercomSettings", HTTP_GET, intercomSettingsRead);
server.on("/api/v1/intercomSettings", HTTP_POST, [](AsyncWebServerRequest *request) {}, NULL, intercomSettingsUpdate);
server.on("/api/v1/switchDoor", HTTP_POST, [](AsyncWebServerRequest *request) {}, NULL, switchDoor);
server.on("/api/v1/mqttStatus", mqttStatus);
server.on("/api/v1/mqttSettings", HTTP_GET, mqttSettingsRead);
server.on("/api/v1/mqttSettings", HTTP_POST, [](AsyncWebServerRequest *request) {}, NULL, mqttSettingsUpdate);
server.on("/api/v1/systemStatus", systemStatus);
server.on("/api/v1/restart", restartNow);
server.on("/api/v1/factoryReset", factoryReset);
}