Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose config and config updates through MQTT #634

Merged
merged 2 commits into from
May 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/mqtt.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ Main settings:
`<base-topic>/shaper/set [0 | 1]` : temporary enable (1)/ disable (0) current shaper ( doesn't survive reboot )
`<base-topic>/restart {"device": "gateway|evse"}` : restart the gateway or openevse module

Config:

`<base-topic>/config_version` : a volatile counter incremented for each config change
`<base-topic>/config` : expose the configuration as a json object


MQTT setup is pre-populated with OpenEnergyMonitor [emonPi default MQTT server credentials](https://guide.openenergymonitor.org/technical/credentials/#mqtt).
Expand Down
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 = INITIAL_CONFIG_VERSION;

// Wifi Network Strings
String esid;
String epass;
Expand Down Expand Up @@ -251,6 +253,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 @@ -368,7 +390,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
jeremypoulter marked this conversation as resolved.
Show resolved Hide resolved
// 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"))
jeremypoulter marked this conversation as resolved.
Show resolved Hide resolved
{
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)
mathieucarbou marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -378,6 +510,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
4 changes: 4 additions & 0 deletions src/app_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ extern uint32_t flags;
#define CONFIG_WIZARD (1 << 25)
#define CONFIG_DEFAULT_STATE (1 << 26)

#define INITIAL_CONFIG_VERSION 1

inline bool config_emoncms_enabled() {
return CONFIG_SERVICE_EMONCMS == (flags & CONFIG_SERVICE_EMONCMS);
}
Expand Down Expand Up @@ -221,6 +223,8 @@ inline EvseState config_default_state()
// Ohm Connect Settings
extern String ohm;

extern uint32_t config_version();

// -------------------------------------------------------------------
// Load saved settings
// -------------------------------------------------------------------
Expand Down
26 changes: 26 additions & 0 deletions src/mqtt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ uint8_t claimsVersion = 0;
uint8_t overrideVersion = 0;
uint8_t scheduleVersion = 0;
uint8_t limitVersion = 0;
uint32_t configVersion = 0;

String lastWill = "";

Expand Down Expand Up @@ -300,6 +301,7 @@ mqtt_connect()
event_send(doc);

// Publish MQTT override/claim
mqtt_publish_config();
mathieucarbou marked this conversation as resolved.
Show resolved Hide resolved
mqtt_publish_override();
mqtt_publish_claim();
mqtt_publish_schedule();
Expand Down Expand Up @@ -507,6 +509,25 @@ 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");

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

return true;
}

void
mqtt_set_limit(LimitProperties &limitProps) {
Profile_Start(mqtt_set_limit);
Expand Down Expand Up @@ -614,6 +635,11 @@ mqtt_loop() {
DBUGF("Limit has changed, publishing to MQTT");
limitVersion = limit.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 @@ -33,6 +33,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