Files
Industrial_Emulator/lib/Core/ConfigParser.h

156 lines
6.5 KiB
C++

#ifndef CONFIG_PARSER_H
#define CONFIG_PARSER_H
#include <Arduino.h>
#include <WiFi.h>
#include <ArduinoJson.h>
#include <ModbusIP_ESP8266.h>
#include <ModbusRTU.h>
// Core inclusion
#include "Equipment/Equipment.h"
#include "ModbusPoints/Modbus_Point.h"
#include "ModbusPoints/Modbus_PointFactory.h"
#include "Storage.h"
// Current Strategies inclusions
#include "Strategies/Strategy_Behavior.h"
#include "Strategies/Strategy_Ramp.h"
#include "Strategies/Strategy_Random.h"
#include "Strategies/Strategy_Saw.h"
#include "Strategies/Strategy_Square.h"
#include "Strategies/Strategy_SingleValue.h"
class ConfigParser {
private:
// Create the Equipment generic instance using ModbusIP as default
// Note: The original Equipment code use templates, it is possible to instantiate with ModbusIP
static Equipment<ModbusIP>* _equipmentInstance;
static WiFiServer* _pythonServer;
static int _pythonPort;
static int _modeIsTCP;
public:
static Equipment<ModbusIP>* getEquipmentInstance() {
if (_equipmentInstance == nullptr) {
_equipmentInstance = new Equipment<ModbusIP>();
}
return _equipmentInstance;
}
/**
* @brief Start the TCP socket server to listen Python though WiFi
*/
static void initPythonTCPServer(int port = 8888){
_pythonPort = port;
_pythonServer = new WiFiServer(_pythonPort);
_pythonServer->begin();
Serial.print(F("[ConfigParser] Python server started on port: "));
Serial.println(_pythonPort);
}
/**
* @brief Check if Python send Json through Wi-Fi and apply
*/
static void checkPythonTCPClient(ModbusIP& mbIP, ModbusRTU& mbRTU, bool* modeIsTCP){
if (_pythonServer==nullptr) return;
WiFiClient client = _pythonServer->available();
if (client) {
Serial.println(F("[ConfigParser] Python connected over Wi-Fi..."));
String jsonConfig = client.readString();
// Apply configuration if it is a valid JSON
apply(jsonConfig, mbIP, mbRTU, modeIsTCP);
// Store backup configuration in LittleFS
Storage::saveConfigFile(jsonConfig);
client.println("OK");
client.stop();
}
}
/**
* @brief Main fucntion: Deserialize the Json and configure Modbus and strategies
*/
static void apply(const String& jsonConfig, ModbusIP& mbIP, ModbusRTU& mbRTU, bool* modeIsTCP) {
Serial.println(F("[ConfigParser] Apply new configuration..."));
JsonDocument doc;
DeserializationError error = deserializeJson(doc, jsonConfig);
if (error) {
Serial.print(F("[ConfigParser] Deserialize Json Error: "));
Serial.println(error.f_str());
return;
}
// 1. Clean Hardware and RAM: Clear all Modbus points and strategies in the Equipment instance
Equipment<ModbusIP>* eq = getEquipmentInstance();
eq->clearEquipment();
// 2. Network and Modbus protocol configuration.
if (doc.containsKey("connection")){
JsonObject connection = doc["connection"];
String type = connection["type"] | "TCP";
if (type.equalsIgnoreCase("TCP")){
*modeIsTCP = true;
int port = connection["port"] | 502;
mbIP.server(port);
Serial.print(F("[ConfigParser] Modbus TCP server started in port: "));
Serial.println(port);
} else {
*modeIsTCP = false;
int slaveId = connection["slave_id"] | 1;
mbRTU.server(slaveId);
Serial.print(F("[ConfigParser] Modbus RTU server started in slave ID: "));
Serial.println(slaveId);
}
}
// 2. Rebuild the tags and strategies.
if (doc.containsKey("points")){
JsonArray pointsArray = doc["points"];
Serial.print(F("[ConfigParser] Mapping requester registers: "));
Serial.println(pointsArray.size());
for(JsonObject p : pointsArray){
int address = p["address"];
int category = p["cateogry"];
int initVal = p["init_val"] | 0;
const char* desc = p["desc"] | "Empty_Desc";
Modbus_Point<ModbusIP>* newPoint = nullptr;
if (*modeIsTCP) {
newPoint = createModbus_Point(&mbIP, category, address, initVal, desc);
} else {
newPoint = createModbus_Point((ModbusIP*)&mbRTU, category, address, initVal, desc);
}
if (newPoint != nullptr) {
newPoint->addToModbusServer();
if (p.containsKey("strategy")){
const char* stratType = p["strategy"];
unsigned long interval = p["interval"] | 1000;
Strategy_Behavior* strategy = nullptr;
if (strcmp(stratType, "ramp") == 0) {
strategy = new RampStrategy((float)(p["target"] | 0.0f), (float)(p["step"] | 100.0f), (int)(p["interval"] | 1000));
}
else if (strcmp(stratType, "random") == 0) {
strategy = new RandomStrategy(interval);
}
else if (strcmp(stratType, "saw") == 0) {
strategy = new SawStrategy((float)(p["min"] | 0.0f), (float)(p["max"] | 100.0f), (float)(p["step"] | 5.0f), (int)(p["interval"] | 1000));
}
else if (strcmp(stratType, "square") == 0) {
strategy = new SquareStrategy((float)(p["lower"] | 0.0f), (float)(p["upper"] | 100.0f), (int)(p["interval"] | 1000));
}
else if (strcmp(stratType, "single") == 0 || strcmp(stratType, "none") == 0) {
strategy = new SingleValueStrategy((float)(p["setpoint"] | 50.0f), (float)(p["noise"] | 0.5f), (int)(p["interval"] | 1000));
}
}
eq->addModbus_Point(desc, newPoint);
}
}
Serial.println(F("[ConfigParser] Tag deployment completed successfully."));
}
}
};
inline Equipment<ModbusIP>* ConfigParser::_equipmentInstance = nullptr;
inline WiFiServer* ConfigParser::_pythonServer = nullptr;
inline int ConfigParser::_modeIsTCP = true;
inline int ConfigParser::_pythonPort = 8888;
#endif