Skip to content

Commit

Permalink
Add "basic reporting" cell functionality for MQTT messages
Browse files Browse the repository at this point in the history
  • Loading branch information
stuartpittaway committed Nov 8, 2023
1 parent bd7afba commit 58ff871
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 33 deletions.
2 changes: 2 additions & 0 deletions ESPController/include/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ struct diybms_eeprom_settings

// NOTE this array is subject to buffer overflow vulnerabilities!
bool mqtt_enabled;
// Only report basic cell data (voltage and temperture) over MQTT
bool mqtt_basic_cell_reporting;
char mqtt_uri[128 + 1];
char mqtt_topic[32 + 1];
char mqtt_username[32 + 1];
Expand Down
52 changes: 30 additions & 22 deletions ESPController/src/mqtt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,12 @@ void connectToMqtt()
.password = mysettings.mqtt_password,
// Reconnect if there server has a problem (or wrong IP/password etc.)
.disable_auto_reconnect = false,
.buffer_size = 512,
// 30 seconds
.reconnect_timeout_ms = 30000,
// 3 seconds
.network_timeout_ms = 3000};
.out_buffer_size = 2048,
// 4 seconds
.network_timeout_ms = 4000};

mqtt_client = esp_mqtt_client_init(&mqtt_cfg);

Expand Down Expand Up @@ -237,14 +239,15 @@ void GeneralStatusPayload(const PacketRequestGenerator *prg, const PacketReceive

void BankLevelInformation(const Rules *rules)
{
std::string bank_status;
bank_status.reserve(64);
// Output bank level information (just voltage for now)
for (int8_t bank = 0; bank < mysettings.totalNumberOfBanks; bank++)
{
ESP_LOGI(TAG, "Bank(%d) status payload", bank);
std::string bank_status;
bank_status.reserve(128);
ESP_LOGI(TAG, "Bank %d status payload", bank);
bank_status.clear();
bank_status.append("{\"voltage\":")
.append(float_to_string(rules->bankvoltage.at(bank) / 1000.0f))
.append(float_to_string((float)(rules->bankvoltage.at(bank)) / 1000.0f))
.append(",\"range\":")
.append(std::to_string(rules->VoltageRangeInBank(bank)))
.append("}");
Expand All @@ -262,7 +265,10 @@ void RuleStatus(const Rules *rules)
rule_status.append("{");
for (uint8_t i = 0; i < RELAY_RULES; i++)
{
rule_status.append("\"").append(std::to_string(i)).append("\":").append(std::to_string(rules->ruleOutcome((Rule)i) ? 1 : 0));
rule_status.append("\"")
.append(std::to_string(i))
.append("\":")
.append(std::to_string(rules->ruleOutcome((Rule)i) ? 1 : 0));
if (i < (RELAY_RULES - 1))
{
rule_status.append(",");
Expand All @@ -282,7 +288,11 @@ void OutputStatus(const RelayState *previousRelayState)
relay_status.append("{");
for (uint8_t i = 0; i < RELAY_TOTAL; i++)
{
relay_status.append("\"").append(std::to_string(i)).append("\":").append(std::to_string((previousRelayState[i] == RelayState::RELAY_ON) ? 1 : 0));
relay_status.append("\"")
.append(std::to_string(i))
.append("\":")
.append(std::to_string((previousRelayState[i] == RelayState::RELAY_ON) ? 1 : 0));

if (i < (RELAY_TOTAL - 1))
{
relay_status.append(",");
Expand Down Expand Up @@ -338,31 +348,29 @@ void MQTTCellData()

ESP_LOGI(TAG, "MQTT Payload for cell data");

std::string status;
status.reserve(128);

while (i < TotalNumberOfCells() && counter < MAX_MODULES_PER_ITERATION)
{
// Only send valid module data
if (cmi[i].valid)
{

std::string status;
std::string topic = mysettings.mqtt_topic;
status.reserve(128);

uint8_t bank = i / mysettings.totalNumberOfSeriesModules;
uint8_t m = i - (bank * mysettings.totalNumberOfSeriesModules);

status.append("{\"voltage\":").append(float_to_string(cmi[i].voltagemV / 1000.0f));
status.append(",\"vMax\":").append(float_to_string(cmi[i].voltagemVMax / 1000.0f));
status.append(",\"vMin\":").append(float_to_string(cmi[i].voltagemVMin / 1000.0f));
status.append(",\"inttemp\":").append(std::to_string(cmi[i].internalTemp));
status.append(",\"exttemp\":").append(std::to_string(cmi[i].externalTemp));
status.append(",\"bypass\":").append(std::to_string(cmi[i].inBypass ? 1 : 0));
status.append(",\"PWM\":").append(std::to_string((int)((float)cmi[i].PWMValue / (float)255.0 * 100)));
status.append(",\"bypassT\":").append(std::to_string(cmi[i].bypassOverTemp ? 1 : 0));
status.append(",\"bpc\":").append(std::to_string(cmi[i].badPacketCount));
status.append(",\"mAh\":").append(std::to_string(cmi[i].BalanceCurrentCount));
status.clear();
status.append("{\"voltage\":").append(float_to_string(cmi[i].voltagemV / 1000.0f)).append(",\"exttemp\":").append(std::to_string(cmi[i].externalTemp));

if (mysettings.mqtt_basic_cell_reporting == false)
{
status.append(",\"vMax\":").append(float_to_string(cmi[i].voltagemVMax / 1000.0f)).append(",\"vMin\":").append(float_to_string(cmi[i].voltagemVMin / 1000.0f)).append(",\"inttemp\":").append(std::to_string(cmi[i].internalTemp)).append(",\"bypass\":").append(std::to_string(cmi[i].inBypass ? 1 : 0)).append(",\"PWM\":").append(std::to_string((int)((float)cmi[i].PWMValue / (float)255.0 * 100))).append(",\"bypassT\":").append(std::to_string(cmi[i].bypassOverTemp ? 1 : 0)).append(",\"bpc\":").append(std::to_string(cmi[i].badPacketCount)).append(",\"mAh\":").append(std::to_string(cmi[i].BalanceCurrentCount));
}

status.append("}");

std::string topic = mysettings.mqtt_topic;
topic.append("/").append(std::to_string(bank)).append("/").append(std::to_string(m));
publish_message(topic, status);
}
Expand Down
7 changes: 7 additions & 0 deletions ESPController/src/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ static const char rs485parity_JSONKEY[] = "rs485parity";
static const char rs485stopbits_JSONKEY[] = "rs485stopbits";
static const char language_JSONKEY[] = "language";
static const char mqtt_enabled_JSONKEY[] = "enabled";
static const char mqtt_basic_cell_reporting_JSONKEY[] = "basiccellrpt";
static const char mqtt_uri_JSONKEY[] = "uri";
static const char mqtt_topic_JSONKEY[] = "topic";
static const char mqtt_username_JSONKEY[] = "username";
Expand Down Expand Up @@ -142,6 +143,7 @@ static const char dynamiccharge_NVSKEY[] = "dynamiccharge";
static const char preventcharging_NVSKEY[] = "preventchar";
static const char preventdischarge_NVSKEY[] = "preventdis";
static const char mqtt_enabled_NVSKEY[] = "mqttenable";
static const char mqtt_basic_cell_reporting_NVSKEY[] = "basiccellrpt";
static const char influxdb_enabled_NVSKEY[] = "infenabled";
static const char influxdb_loggingFreqSeconds_NVSKEY[] = "inflogFreq";
static const char tileconfig_NVSKEY[] = "tileconfig";
Expand Down Expand Up @@ -412,6 +414,7 @@ void SaveConfiguration(diybms_eeprom_settings *settings)
MACRO_NVSWRITE(preventcharging);
MACRO_NVSWRITE(preventdischarge);
MACRO_NVSWRITE(mqtt_enabled);
MACRO_NVSWRITE(mqtt_basic_cell_reporting);
MACRO_NVSWRITE(influxdb_enabled);
MACRO_NVSWRITE(influxdb_loggingFreqSeconds);

Expand Down Expand Up @@ -537,6 +540,7 @@ void LoadConfiguration(diybms_eeprom_settings *settings)
MACRO_NVSREAD(preventdischarge);

MACRO_NVSREAD(mqtt_enabled);
MACRO_NVSREAD(mqtt_basic_cell_reporting);
MACRO_NVSREAD(influxdb_enabled);
MACRO_NVSREAD(influxdb_loggingFreqSeconds);

Expand Down Expand Up @@ -586,6 +590,7 @@ void DefaultConfiguration(diybms_eeprom_settings *_myset)

// EEPROM settings are invalid so default configuration
_myset->mqtt_enabled = false;
_myset->mqtt_basic_cell_reporting = false;

_myset->canbusprotocol = CanBusProtocolEmulation::CANBUS_DISABLED;
_myset->canbusinverter = CanBusInverter::INVERTER_GENERIC;
Expand Down Expand Up @@ -1001,6 +1006,7 @@ void GenerateSettingsJSONDocument(DynamicJsonDocument *doc, diybms_eeprom_settin

JsonObject mqtt = root.createNestedObject("mqtt");
mqtt[mqtt_enabled_JSONKEY] = settings->mqtt_enabled;
mqtt[mqtt_basic_cell_reporting_JSONKEY] = settings->mqtt_basic_cell_reporting;
mqtt[mqtt_uri_JSONKEY] = settings->mqtt_uri;
mqtt[mqtt_topic_JSONKEY] = settings->mqtt_topic;
mqtt[mqtt_username_JSONKEY] = settings->mqtt_username;
Expand Down Expand Up @@ -1179,6 +1185,7 @@ void JSONToSettings(DynamicJsonDocument &doc, diybms_eeprom_settings *settings)
if (!mqtt.isNull())
{
settings->mqtt_enabled = mqtt[mqtt_enabled_JSONKEY];
settings->mqtt_basic_cell_reporting=mqtt[mqtt_basic_cell_reporting_JSONKEY];
strncpy(settings->mqtt_uri, mqtt[mqtt_uri_JSONKEY].as<String>().c_str(), sizeof(settings->mqtt_uri));
strncpy(settings->mqtt_topic, mqtt[mqtt_topic_JSONKEY].as<String>().c_str(), sizeof(settings->mqtt_topic));
strncpy(settings->mqtt_username, mqtt[mqtt_username_JSONKEY].as<String>().c_str(), sizeof(settings->mqtt_username));
Expand Down
3 changes: 3 additions & 0 deletions ESPController/src/webserver_json_post.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,16 @@ esp_err_t post_savemqtt_json_handler(httpd_req_t *req, bool urlEncoded)
{
// Default to off
mysettings.mqtt_enabled = false;
mysettings.mqtt_basic_cell_reporting=false;

// Username and password are optional and may not be HTTP posted from web browser
memset(mysettings.mqtt_username, 0, sizeof(mysettings.mqtt_username));
memset(mysettings.mqtt_password, 0, sizeof(mysettings.mqtt_password));

GetKeyValue(httpbuf, "mqttEnabled", &mysettings.mqtt_enabled, urlEncoded);

GetKeyValue(httpbuf, "mqttBasicReporting", &mysettings.mqtt_basic_cell_reporting, urlEncoded);

GetTextFromKeyValue(httpbuf, "mqttTopic", mysettings.mqtt_topic, sizeof(mysettings.mqtt_topic), urlEncoded);

GetTextFromKeyValue(httpbuf, "mqttUri", mysettings.mqtt_uri, sizeof(mysettings.mqtt_uri), urlEncoded);
Expand Down
14 changes: 7 additions & 7 deletions ESPController/src/webserver_json_requests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ int fileSystemListDirectory(httpd_req_t *r, char *buffer, size_t bufferLen, fs::
{
// Flush http buffer every X files to prevent overflows
httpd_resp_send_chunk(r, buffer, bufferused);
bufferused=0;
bufferused = 0;
}
}

Expand Down Expand Up @@ -806,16 +806,16 @@ esp_err_t content_handler_integration(httpd_req_t *req)

JsonObject mqtt = root.createNestedObject("mqtt");
mqtt["enabled"] = mysettings.mqtt_enabled;
mqtt["basiccellreporting"] = mysettings.mqtt_basic_cell_reporting;
mqtt["topic"] = mysettings.mqtt_topic;
mqtt["uri"] = mysettings.mqtt_uri;
mqtt["username"] = mysettings.mqtt_username;

mqtt["connected"]= mqttClient_connected;
mqtt["err_conn_count"]=mqtt_error_connection_count;
mqtt["err_trans_count"]=mqtt_error_transport_count;
mqtt["conn_count"]=mqtt_connection_count;
mqtt["disc_count"]=mqtt_disconnection_count;

mqtt["connected"] = mqttClient_connected;
mqtt["err_conn_count"] = mqtt_error_connection_count;
mqtt["err_trans_count"] = mqtt_error_transport_count;
mqtt["conn_count"] = mqtt_connection_count;
mqtt["disc_count"] = mqtt_disconnection_count;

// We don't output the password in the json file as this could breach security
// mqtt["password"] =mysettings.mqtt_password;
Expand Down
11 changes: 7 additions & 4 deletions ESPController/web_src/default.htm
Original file line number Diff line number Diff line change
Expand Up @@ -482,19 +482,22 @@ <h2>Global Settings</h2>

<div class="page" id="integrationPage">
<h1 id="ip1">Integration</h1>
<p id="ip2">
For security, you will need to re-enter the password for the service(s) you want to enable or modify, before you
save.
</p>

<div class="region">
<h2>MQTT</h2>
<p id="ip2">For security, you will need to re-enter the password for the MQTT service if you want to enable or modify, before you save.</p>
<p id="ip4">URI should be similar to mqtt://192.168.0.26:1833</p>
<p id="ip5">Basic cell data option reduces the amount of MQTT data being sent over the network.</p>
<form id="mqttForm" method="POST" action="/post/savemqtt" autocomplete="off">
<div class="settings">
<div>
<label for="mqttEnabled">Enabled</label>
<input type="checkbox" name="mqttEnabled" id="mqttEnabled" />
</div>
<div>
<label for="mqttBasicReporting">Basic cell data reporting only</label>
<input type="checkbox" name="mqttBasicReporting" id="mqttBasicReporting" />
</div>
<div>
<label for="mqttTopic">Topic</label>
<input type="input" name="mqttTopic" id="mqttTopic" value="diybms" required="" maxlength="32" />
Expand Down
1 change: 1 addition & 0 deletions ESPController/web_src/pagecode.js
Original file line number Diff line number Diff line change
Expand Up @@ -1735,6 +1735,7 @@ $(function () {
function (data) {

$("#mqttEnabled").prop("checked", data.mqtt.enabled);
$("#mqttBasicReporting").prop("checked", data.mqtt.basiccellreporting);
$("#mqttTopic").val(data.mqtt.topic);
$("#mqttUri").val(data.mqtt.uri);
$("#mqttUsername").val(data.mqtt.username);
Expand Down

0 comments on commit 58ff871

Please sign in to comment.