Skip to content

Commit

Permalink
Expose config and config updates through MQTT
Browse files Browse the repository at this point in the history
  • Loading branch information
Carbou, Mathieu authored and Carbou, Mathieu committed May 13, 2023
1 parent acbd1fc commit 6dba4ed
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 154 deletions.
171 changes: 170 additions & 1 deletion src/app_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#define FACTORY_OFFSET CONFIG_SIZE
#define FACTORY_SIZE 1024

uint32_t config_ver = 1;

// Wifi Network Strings
String esid;
String epass;
Expand Down Expand Up @@ -232,6 +234,26 @@ ConfigOpt *opts[] =
ConfigJson user_config(opts, sizeof(opts) / sizeof(opts[0]), EEPROM_SIZE, CONFIG_OFFSET);
ConfigJson factory_config(opts, sizeof(opts) / sizeof(opts[0]), EEPROM_SIZE, FACTORY_OFFSET);

// -------------------------------------------------------------------
// config version handling
// -------------------------------------------------------------------
uint32_t
config_version() {
return config_ver;
}

void
increment_config() {
config_ver++;
DBUGVAR(config_ver);

#if ENABLE_CONFIG_CHANGE_NOTIFICATION
StaticJsonDocument<128> event;
event["config_version"] = config_ver;
event_send(event);
#endif
}

// -------------------------------------------------------------------
// Reset EEPROM, wipes all settings
// -------------------------------------------------------------------
Expand Down Expand Up @@ -349,7 +371,117 @@ bool config_deserialize(const char *json)

bool config_deserialize(DynamicJsonDocument &doc)
{
return user_config.deserialize(doc);
bool config_modified = user_config.deserialize(doc);

#if ENABLE_CONFIG_CHANGE_NOTIFICATION
// Update EVSE config
// Update the EVSE setting flags, a little low level, may move later
if(doc.containsKey("diode_check"))
{
bool enable = doc["diode_check"];
if(enable != evse.isDiodeCheckEnabled()) {
evse.enableDiodeCheck(enable);
config_modified = true;
DBUGLN("diode_check changed");
}
}

if(doc.containsKey("gfci_check"))
{
bool enable = doc["gfci_check"];
if(enable != evse.isGfiTestEnabled()) {
evse.enableGfiTestCheck(enable);
config_modified = true;
DBUGLN("gfci_check changed");
}
}

if(doc.containsKey("ground_check"))
{
bool enable = doc["ground_check"];
if(enable != evse.isGroundCheckEnabled()) {
evse.enableGroundCheck(enable);
config_modified = true;
DBUGLN("ground_check changed");
}
}

if(doc.containsKey("relay_check"))
{
bool enable = doc["relay_check"];
if(enable != evse.isStuckRelayCheckEnabled()) {
evse.enableStuckRelayCheck(enable);
config_modified = true;
DBUGLN("relay_check changed");
}
}

if(doc.containsKey("vent_check"))
{
bool enable = doc["vent_check"];
if(enable != evse.isVentRequiredEnabled()) {
evse.enableVentRequired(enable);
config_modified = true;
DBUGLN("vent_check changed");
}
}

if(doc.containsKey("temp_check"))
{
bool enable = doc["temp_check"];
if(enable != evse.isTemperatureCheckEnabled()) {
evse.enableTemperatureCheck(enable);
config_modified = true;
DBUGLN("temp_check changed");
}
}

if(doc.containsKey("service"))
{
EvseMonitor::ServiceLevel service = static_cast<EvseMonitor::ServiceLevel>(doc["service"].as<uint8_t>());
if(service != evse.getServiceLevel()) {
evse.setServiceLevel(service);
config_modified = true;
DBUGLN("service changed");
}
}

if(doc.containsKey("max_current_soft"))
{
long current = doc["max_current_soft"];
if(current != evse.getMaxConfiguredCurrent()) {
evse.setMaxConfiguredCurrent(current);
config_modified = true;
DBUGLN("max_current_soft changed");
}
}

if(doc.containsKey("scale") && doc.containsKey("offset"))
{
long scale = doc["scale"];
long offset = doc["offset"];
if(scale != evse.getCurrentSensorScale() || offset != evse.getCurrentSensorOffset()) {
evse.configureCurrentSensorScale(doc["scale"], doc["offset"]);
config_modified = true;
DBUGLN("scale changed");
}
}
#endif

if(config_modified)
{
#if ENABLE_CONFIG_CHANGE_NOTIFICATION
// HACK: force a flush of the RAPI command queue to make sure the config
// is updated before we send the response
DBUG("Flushing RAPI command queue ...");
rapiSender.flush();
DBUGLN(" Done");
#endif

increment_config();
}

return config_modified;
}

bool config_serialize(String& json, bool longNames, bool compactOutput, bool hideSecrets)
Expand All @@ -359,6 +491,43 @@ bool config_serialize(String& json, bool longNames, bool compactOutput, bool hid

bool config_serialize(DynamicJsonDocument &doc, bool longNames, bool compactOutput, bool hideSecrets)
{
// Static supported protocols
JsonArray mqtt_supported_protocols = doc.createNestedArray("mqtt_supported_protocols");
mqtt_supported_protocols.add("mqtt");
mqtt_supported_protocols.add("mqtts");
JsonArray http_supported_protocols = doc.createNestedArray("http_supported_protocols");
http_supported_protocols.add("http");

#if ENABLE_CONFIG_CHANGE_NOTIFICATION
doc["buildenv"] = buildenv;
doc["version"] = currentfirmware;
doc["wifi_serial"] = serial;
doc["protocol"] = "-";
doc["espinfo"] = ESPAL.getChipInfo();
doc["espflash"] = ESPAL.getFlashChipSize();

// EVSE information are only evailable when config_version is incremented
if(config_ver > 0) {
// Read only information
doc["firmware"] = evse.getFirmwareVersion();
doc["evse_serial"] = evse.getSerial();
// OpenEVSE module config
doc["diode_check"] = evse.isDiodeCheckEnabled();
doc["gfci_check"] = evse.isGfiTestEnabled();
doc["ground_check"] = evse.isGroundCheckEnabled();
doc["relay_check"] = evse.isStuckRelayCheckEnabled();
doc["vent_check"] = evse.isVentRequiredEnabled();
doc["temp_check"] = evse.isTemperatureCheckEnabled();
doc["max_current_soft"] = evse.getMaxConfiguredCurrent();
// OpenEVSE Read only information
doc["service"] = static_cast<uint8_t>(evse.getServiceLevel());
doc["scale"] = evse.getCurrentSensorScale();
doc["offset"] = evse.getCurrentSensorOffset();
doc["min_current_hard"] = evse.getMinCurrent();
doc["max_current_hard"] = evse.getMaxHardwareCurrent();
}
#endif

return user_config.serialize(doc, longNames, compactOutput, hideSecrets);
}

Expand Down
2 changes: 2 additions & 0 deletions src/app_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ inline bool config_threephase_enabled() {
// Ohm Connect Settings
extern String ohm;

extern uint32_t config_version();

// -------------------------------------------------------------------
// Load saved settings
// -------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions src/evse_monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "evse_monitor.h"
#include "event.h"
#include "debug.h"
#include "app_config.h"

#ifdef ENABLE_MCP9808
#ifndef I2C_SDA
Expand Down
24 changes: 24 additions & 0 deletions src/mqtt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ static bool connecting = false;
uint8_t claimsVersion = 0;
uint8_t overrideVersion = 0;
uint8_t scheduleVersion = 0;
uint32_t configVersion = 0;

String lastWill = "";

Expand Down Expand Up @@ -289,6 +290,7 @@ mqtt_connect()
event_send(doc);

// Publish MQTT override/claim
mqtt_publish_config();
mqtt_publish_override();
mqtt_publish_claim();
mqtt_publish_schedule();
Expand Down Expand Up @@ -489,6 +491,23 @@ mqtt_publish_schedule() {
}
}

bool
mqtt_publish_config() {
if(!config_mqtt_enabled() || !mqttclient.connected() || evse.getEvseState() == OPENEVSE_STATE_STARTING) {
return false;
}
const size_t capacity = JSON_OBJECT_SIZE(128) + 1024;
DynamicJsonDocument doc(capacity);
config_serialize(doc, true, false, true);
mqtt_publish_json(doc, "/config");

String fulltopic = mqtt_topic + "/config_version";
String payload = String(config_version());
mqttclient.publish(fulltopic, payload, true);

return true;
}

void
mqtt_publish_json(JsonDocument &data, const char* topic) {
Profile_Start(mqtt_publish_json);
Expand Down Expand Up @@ -555,6 +574,11 @@ mqtt_loop() {
DBUGF("Schedule has changed, publishing to MQTT");
scheduleVersion = scheduler.getVersion();
}

if(configVersion != config_version() && mqtt_publish_config()) {
DBUGF("Config has changed, publishing to MQTT");
configVersion = config_version();
}
}
Profile_End(mqtt_loop, 5);
}
Expand Down
1 change: 1 addition & 0 deletions src/mqtt.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ extern void mqtt_loop();
// data: a comma seperated list of name:value pairs to send
// -------------------------------------------------------------------
extern void mqtt_publish(JsonDocument &data);
extern bool mqtt_publish_config();
extern void mqtt_publish_claim();
extern void mqtt_set_claim(bool override, EvseProperties &props);
extern void mqtt_publish_override();
Expand Down
4 changes: 1 addition & 3 deletions src/web_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,6 @@ void handleUpdateClose(MongooseHttpServerRequest *request);
void handleTime(MongooseHttpServerRequest *request);
void handleTimePost(MongooseHttpServerRequest *request, MongooseHttpServerResponseStream *response);

extern uint32_t config_version;

void dumpRequest(MongooseHttpServerRequest *request)
{
#ifdef ENABLE_DEBUG_WEB_REQUEST
Expand Down Expand Up @@ -253,7 +251,7 @@ void buildStatus(DynamicJsonDocument &doc) {

doc["ota_update"] = (int)Update.isRunning();

doc["config_version"] = config_version;
doc["config_version"] = config_version();
doc["claims_version"] = evse.getClaimsVersion();
doc["override_version"] = manual.getVersion();
doc["schedule_version"] = scheduler.getVersion();
Expand Down
Loading

0 comments on commit 6dba4ed

Please sign in to comment.