296 lines
9.4 KiB
C++
296 lines
9.4 KiB
C++
#pragma once
|
|
|
|
#define DEBUGLOG_DEFAULT_LOG_LEVEL_DEBUG
|
|
|
|
#include <DebugLog.h>
|
|
#include <Arduino.h>
|
|
#include <ArduinoJson.h>
|
|
#include <fsmount.h>
|
|
|
|
class Config
|
|
{
|
|
|
|
public:
|
|
static Config &getInstance()
|
|
{
|
|
static Config instance;
|
|
return instance;
|
|
}
|
|
|
|
private:
|
|
Config() = default;
|
|
Config(const Config &) = delete;
|
|
Config &operator=(const Config &) = delete;
|
|
|
|
public:
|
|
void init()
|
|
{
|
|
FSmount mount; // scoped mount of the filesystem
|
|
|
|
// Initialize and mount filesystem
|
|
LOG_INFO("Initializing Config");
|
|
|
|
if (!FFat.exists("/config.json"))
|
|
{
|
|
LOG_WARN("Initializing default config");
|
|
saveConfig();
|
|
}
|
|
|
|
File file = FFat.open("/config.json", FILE_READ, false);
|
|
if (!file)
|
|
{
|
|
LOG_ERROR("Unable to open config.json");
|
|
return;
|
|
}
|
|
|
|
if (ArduinoJson::deserializeJson(m_configJson, file) != ArduinoJson::DeserializationError::Ok)
|
|
{
|
|
LOG_ERROR("Unable to load config.json");
|
|
}
|
|
|
|
std::string loadedConf;
|
|
ArduinoJson::serializeJsonPretty(m_configJson, loadedConf);
|
|
LOG_INFO("Loaded Configuration\n", loadedConf.c_str());
|
|
|
|
deserialize(); // convert from json format to class members
|
|
file.close(); // close config file before unmounting filesystem
|
|
};
|
|
|
|
ArduinoJson::JsonDocument& getConfig()
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
serialize();
|
|
return m_configJson;
|
|
}
|
|
|
|
void setConfig(const ArduinoJson::JsonDocument &json)
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
{
|
|
FSmount mount;
|
|
m_configJson = json;
|
|
deserialize();
|
|
saveConfig();
|
|
}; // filesystem is unmounted here
|
|
}
|
|
|
|
void resetConfig()
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
{
|
|
FSmount mount;
|
|
LOG_WARN("Removing config.json");
|
|
if (!FFat.remove("/config.json"))
|
|
{
|
|
LOG_ERROR("Unable to remove config.json");
|
|
}
|
|
LOG_WARN("Configuration reset, Restarting");
|
|
}; // filesystem is unmounted here
|
|
delay(500);
|
|
esp_restart();
|
|
}
|
|
|
|
private:
|
|
void saveConfig() // write configuration to flash memory
|
|
{
|
|
File file = FFat.open("/config.json", FILE_WRITE, true);
|
|
if (!file)
|
|
{
|
|
LOG_ERROR("Unable to open config.json for writing");
|
|
return;
|
|
}
|
|
serialize(); // serialize default configuration
|
|
if (ArduinoJson::serializeJson(m_configJson, file) == 0)
|
|
{
|
|
LOG_ERROR("Serialization Failed");
|
|
}
|
|
file.close();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
////////////// SERIALIZATION + DESERIALIZATION ///////////////
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
void serialize()
|
|
{
|
|
// form class members to json document
|
|
{
|
|
auto globals = m_configJson["globals"].to<ArduinoJson::JsonObject>();
|
|
globals["loopDelay"] = m_globalLoopDelay;
|
|
};
|
|
|
|
{
|
|
auto ethernet = m_configJson["ethernet"].to<ArduinoJson::JsonObject>();
|
|
ethernet["hostname"] = m_ethHostname;
|
|
ethernet["ipAddr"] = m_ethIpAddr;
|
|
ethernet["netmask"] = m_ethNetmask;
|
|
ethernet["gateway"] = m_ethGateway;
|
|
};
|
|
|
|
{
|
|
auto modbus = m_configJson["modbus"].to<ArduinoJson::JsonObject>();
|
|
modbus["relayAddr"] = m_modbusRelayAddr;
|
|
modbus["temperatureAddr"] = m_modbusTemperatureAddr;
|
|
modbus["senecaAddr"] = m_modbusSenecaAddr;
|
|
modbus["flowmeterAddr"] = m_modbusFlowmeterAddr;
|
|
modbus["tankLevelAddr"] = m_modbusTankLevelAddr;
|
|
};
|
|
|
|
{
|
|
auto temperature = m_configJson["temperature"].to<ArduinoJson::JsonObject>();
|
|
temperature["expectedSensors"] = m_tempExpectedSensors;
|
|
auto values = temperature["correctionValues"].to<ArduinoJson::JsonArray>();
|
|
for (auto v : m_tempCorrectionValues)
|
|
{
|
|
values.add(v);
|
|
}
|
|
};
|
|
|
|
{
|
|
auto ntp = m_configJson["ntp"].to<ArduinoJson::JsonObject>();
|
|
ntp["pool"] = m_ntpPool;
|
|
ntp["timezone"] = m_ntpTimezone;
|
|
ntp["updateInterval"] = m_ntpUpdateInterval;
|
|
ntp["retries"] = m_ntpRetries;
|
|
};
|
|
|
|
{
|
|
auto mqtt = m_configJson["mqtt"].to<ArduinoJson::JsonObject>();
|
|
mqtt["host"] = m_mqttHost;
|
|
mqtt["port"] = m_mqttPort;
|
|
mqtt["loopTime"] = m_mqttLoopTime;
|
|
mqtt["clientName"] = m_mqttClientName;
|
|
mqtt["retries"] = m_mqttRetries;
|
|
mqtt["keepalive"] = m_mqttKeepalive;
|
|
auto publish = mqtt["publish"].to<ArduinoJson::JsonObject>();
|
|
for (auto v : m_mqttPublish)
|
|
{
|
|
publish[v.first] = v.second;
|
|
}
|
|
auto subscribe = mqtt["subscribe"].to<ArduinoJson::JsonObject>();
|
|
for (auto v : m_mqttSubscribe)
|
|
{
|
|
subscribe[v.first] = v.second;
|
|
}
|
|
};
|
|
};
|
|
|
|
void deserialize()
|
|
{ // from json document to class members
|
|
if (m_configJson.isNull())
|
|
{
|
|
LOG_ERROR("NUll config document");
|
|
return;
|
|
}
|
|
|
|
{
|
|
auto globals = m_configJson["globals"];
|
|
m_globalLoopDelay = globals["loopDelay"].as<uint16_t>();
|
|
};
|
|
|
|
{
|
|
auto ethernet = m_configJson["ethernet"];
|
|
m_ethHostname = ethernet["hostname"].as<std::string>();
|
|
m_ethIpAddr = ethernet["ipAddr"].as<std::string>();
|
|
m_ethNetmask = ethernet["netmask"].as<std::string>();
|
|
m_ethGateway = ethernet["gateway"].as<std::string>();
|
|
};
|
|
|
|
{
|
|
auto modbus = m_configJson["modbus"];
|
|
m_modbusRelayAddr = modbus["relayAddr"].as<uint8_t>();
|
|
m_modbusTemperatureAddr = modbus["temperatureAddr"].as<uint8_t>();
|
|
m_modbusSenecaAddr = modbus["senecaAddr"].as<uint8_t>();
|
|
m_modbusFlowmeterAddr = modbus["flowmeterAddr"].as<uint8_t>();
|
|
m_modbusTankLevelAddr = modbus["tankLevelAddr"].as<uint8_t>();
|
|
};
|
|
|
|
{
|
|
auto temperature = m_configJson["temperature"];
|
|
m_tempExpectedSensors = temperature["expectedSensors"].as<uint8_t>();
|
|
auto values = temperature["correctionValues"].as<JsonArray>();
|
|
m_tempCorrectionValues.clear();
|
|
m_tempCorrectionValues.reserve(values.size());
|
|
for (auto v : values)
|
|
{
|
|
m_tempCorrectionValues.emplace_back(v.as<float>());
|
|
}
|
|
};
|
|
|
|
{
|
|
auto ntp = m_configJson["ntp"];
|
|
m_ntpPool = ntp["pool"].as<std::string>();
|
|
m_ntpTimezone = ntp["timezone"].as<uint16_t>();
|
|
m_ntpUpdateInterval = ntp["updateInterval"].as<uint16_t>();
|
|
m_ntpRetries = ntp["retries"].as<uint8_t>();
|
|
};
|
|
|
|
{
|
|
auto mqtt = m_configJson["mqtt"];
|
|
m_mqttHost = mqtt["host"].as<std::string>();
|
|
m_mqttPort = mqtt["port"].as<uint16_t>();
|
|
m_mqttLoopTime = mqtt["loopTime"].as<uint16_t>();
|
|
m_mqttKeepalive = mqtt["keepalive"].as<uint8_t>();
|
|
m_mqttRetries = mqtt["retries"].as<uint8_t>();
|
|
auto subscribe = mqtt["subscribe"].as<ArduinoJson::JsonObject>();
|
|
for (auto v : subscribe)
|
|
{
|
|
m_mqttSubscribe[v.key().c_str()] = v.value().as<std::string>();
|
|
}
|
|
auto publish = mqtt["publish"].as<ArduinoJson::JsonObject>();
|
|
for (auto v : publish)
|
|
{
|
|
m_mqttPublish[v.key().c_str()] = v.value().as<std::string>();
|
|
}
|
|
};
|
|
};
|
|
|
|
private:
|
|
ArduinoJson::JsonDocument m_configJson;
|
|
std::mutex m_mutex;
|
|
|
|
public:
|
|
// Globals
|
|
std::uint16_t m_globalLoopDelay = 5000; // in milliseconds
|
|
|
|
// Ethernet
|
|
std::string m_ethHostname = "ETcontroller_PRO";
|
|
std::string m_ethIpAddr = "10.0.2.251";
|
|
std::string m_ethNetmask = "255.255.255.0";
|
|
std::string m_ethGateway = "10.0.2.1";
|
|
|
|
// MODBUS
|
|
uint8_t m_modbusRelayAddr = 0x01;
|
|
uint8_t m_modbusTemperatureAddr = 0xAA;
|
|
uint8_t m_modbusSenecaAddr = 0xBB;
|
|
uint8_t m_modbusFlowmeterAddr = 0xCC;
|
|
uint8_t m_modbusTankLevelAddr = 0xDD;
|
|
|
|
// Temperature Board
|
|
uint8_t m_tempExpectedSensors = 1;
|
|
std::vector<float> m_tempCorrectionValues = std::vector<float>(8, 0.0f);
|
|
|
|
// NTP
|
|
std::string m_ntpPool = "pool.ntp.org";
|
|
uint16_t m_ntpTimezone = 3600; // GTM +1
|
|
uint16_t m_ntpUpdateInterval = 3600; // every hour
|
|
uint8_t m_ntpRetries = 5;
|
|
|
|
// MQTT
|
|
std::string m_mqttHost = "10.0.2.249";
|
|
uint16_t m_mqttPort = 1883;
|
|
uint16_t m_mqttLoopTime = 100; // in milliseconds
|
|
uint8_t m_mqttKeepalive = 15;
|
|
uint8_t m_mqttRetries = 5;
|
|
std::string m_mqttClientName = "etcontrollerPRO";
|
|
|
|
std::map<const std::string, std::string> m_mqttSubscribe = {
|
|
{"commands", "etcontroller/hw/commands"}};
|
|
std::map<const std::string, std::string> m_mqttPublish = {
|
|
{"cronjobs", "etcontroller/hw/cronjobs"},
|
|
{"answers", "etcontroller/hw/answers"},
|
|
{"heatpump", "etcontroller/hw/heatpump"},
|
|
{"temperatures", "etcontroller/hw/temperatures"},
|
|
{"irrigation", "etcontroller/hw/irrigation"}};
|
|
};
|