Skip to content

Commit f2dbc26

Browse files
committed
feat: expose cmd's via MQTT directly #31
1 parent fd11a09 commit f2dbc26

File tree

4 files changed

+46
-17
lines changed

4 files changed

+46
-17
lines changed

src/mqtt.cpp

+30-9
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,11 @@ void Mqtt::subscribe(const uint8_t device_type, const std::string & topic, mqtt_
6464
if (!mqtt_subfunctions_.empty()) {
6565
for (auto & mqtt_subfunction : mqtt_subfunctions_) {
6666
if ((mqtt_subfunction.device_type_ == device_type) && (strcmp(mqtt_subfunction.topic_.c_str(), topic.c_str()) == 0)) {
67-
// add the function, in case its not there
67+
// add the function (in case its not there) and quit because it already exists
6868
if (cb) {
6969
mqtt_subfunction.mqtt_subfunction_ = cb;
7070
}
71-
return; // it exists, exit
71+
return;
7272
}
7373
}
7474
}
@@ -89,8 +89,9 @@ void Mqtt::subscribe(const uint8_t device_type, const std::string & topic, mqtt_
8989

9090
// subscribe to the command topic if it doesn't exist yet
9191
void Mqtt::register_command(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_p cb) {
92-
std::string cmd_topic = EMSdevice::device_type_2_device_name(device_type);
92+
std::string cmd_topic = EMSdevice::device_type_2_device_name(device_type); // thermostat, boiler, etc...
9393

94+
// see if we have already a handler for the device type (boiler, thermostat). If not add it
9495
bool exists = false;
9596
if (!mqtt_subfunctions_.empty()) {
9697
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
@@ -101,15 +102,21 @@ void Mqtt::register_command(const uint8_t device_type, const __FlashStringHelper
101102
}
102103

103104
if (!exists) {
104-
Mqtt::subscribe(device_type, cmd_topic, nullptr); // use an empty function handler to signal this is a command function
105+
Mqtt::subscribe(device_type, cmd_topic, nullptr); // use an empty function handler to signal this is a command function only (e.g. ems-esp/boiler)
106+
LOG_DEBUG(F("Registering MQTT cmd %s with topic %s"), uuid::read_flash_string(cmd).c_str(), EMSdevice::device_type_2_device_name(device_type).c_str());
105107
}
106108

107-
LOG_DEBUG(F("Registering MQTT cmd %s with topic %s"), uuid::read_flash_string(cmd).c_str(), EMSdevice::device_type_2_device_name(device_type).c_str());
109+
// register the individual commands too (e.g. ems-esp/boiler/wwonetime)
110+
// https://github.com/emsesp/EMS-ESP32/issues/31
111+
std::string topic(100, '\0');
112+
topic = cmd_topic + "/" + uuid::read_flash_string(cmd);
113+
Mqtt::subscribe(device_type, topic, nullptr);
108114
}
109115

110-
// subscribe to an MQTT topic, and store the associated callback function. For generic functions not tied to a specific device
116+
// subscribe to an MQTT topic, and store the associated callback function
117+
// For generic functions not tied to a specific device
111118
void Mqtt::subscribe(const std::string & topic, mqtt_subfunction_p cb) {
112-
subscribe(0, topic, cb); // no device_id needed, if generic to EMS-ESP
119+
subscribe(0, topic, cb); // no device_id needed if generic to EMS-ESP
113120
}
114121

115122
// resubscribe to all MQTT topics
@@ -189,7 +196,7 @@ void Mqtt::show_mqtt(uuid::console::Shell & shell) {
189196
// show subscriptions
190197
shell.printfln(F("MQTT topic subscriptions:"));
191198
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
192-
shell.printfln(F(" %s/%s"), mqtt_base_.c_str(), mqtt_subfunction.topic_.c_str());
199+
shell.printfln(F(" %s/%s (%s)"), mqtt_base_.c_str(), mqtt_subfunction.topic_.c_str(), EMSdevice::device_type_2_device_name(mqtt_subfunction.device_type_).c_str());
193200
}
194201
shell.println();
195202

@@ -266,6 +273,20 @@ void Mqtt::on_message(const char * fulltopic, const char * payload, size_t len)
266273
return;
267274
}
268275

276+
// check if it's not json, then try and extract the command from the topic name
277+
if (message[0] != '{') {
278+
char * cmd_only = strrchr(topic, '/');
279+
if (cmd_only == NULL) {
280+
return; // invalid topic name
281+
}
282+
cmd_only++; // skip the /
283+
// LOG_INFO(F("devicetype= %d, topic = %s, cmd = %s, message = %s"), mf.device_type_, topic, cmd_only, message);
284+
if (!Command::call(mf.device_type_, cmd_only, message)) {
285+
LOG_ERROR(F("No matching cmd (%s) in topic %s, or invalid data"), cmd_only, topic);
286+
}
287+
return;
288+
}
289+
269290
// It's a command then with the payload being JSON like {"cmd":"<cmd>", "data":<data>, "id":<n>}
270291
// Find the command from the json and call it directly
271292
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc;
@@ -305,7 +326,7 @@ void Mqtt::on_message(const char * fulltopic, const char * payload, size_t len)
305326
}
306327

307328
if (!cmd_known) {
308-
LOG_ERROR(F("No matching cmd (%s), invalid data or command failed"), command);
329+
LOG_ERROR(F("No matching cmd (%s) or invalid data"), command);
309330
}
310331

311332
return;

src/test/test.cpp

+13-5
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121

2222
#include "test.h"
2323

24-
// create some fake test data
25-
2624
namespace emsesp {
2725

2826
// no shell
@@ -368,12 +366,22 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd) {
368366

369367
if (command == "boiler") {
370368
shell.printfln(F("Testing boiler..."));
369+
Mqtt::ha_enabled(false);
370+
Mqtt::nested_format(true);
371+
371372
run_test("boiler");
372373
shell.invoke_command("show devices");
373374
shell.invoke_command("show");
374-
// shell.invoke_command("call boiler info");
375-
// shell.invoke_command("call system publish");
376-
// shell.invoke_command("show mqtt");
375+
shell.invoke_command("call boiler info");
376+
shell.invoke_command("call system publish");
377+
378+
EMSESP::mqtt_.incoming("ems-esp/boiler/wwonetime", "1");
379+
EMSESP::mqtt_.incoming("ems-esp/boiler/wwonetime", "0");
380+
EMSESP::mqtt_.incoming("ems-esp/boiler/heatingtemp", "24");
381+
EMSESP::mqtt_.incoming("ems-esp/boiler/wwonetime", "test"); // should fail
382+
EMSESP::mqtt_.incoming("ems-esp/boiler", "{\"cmd\":\"flowtemp\",\"id\":0,\"data\":22}");
383+
384+
shell.invoke_command("show mqtt");
377385
}
378386

379387
if (command == "fr120") {

src/test/test.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ namespace emsesp {
3030
// #define EMSESP_TEST_DEFAULT "mixer"
3131
// #define EMSESP_TEST_DEFAULT "web"
3232
// #define EMSESP_TEST_DEFAULT "general"
33-
// #define EMSESP_TEST_DEFAULT "boiler"
33+
#define EMSESP_TEST_DEFAULT "boiler"
3434
// #define EMSESP_TEST_DEFAULT "mqtt2"
35-
#define EMSESP_TEST_DEFAULT "mqtt_nested"
35+
// #define EMSESP_TEST_DEFAULT "mqtt_nested"
3636
// #define EMSESP_TEST_DEFAULT "ha"
3737

3838
class Test {

src/version.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
#define EMSESP_APP_VERSION "3.0.1b0"
1+
#define EMSESP_APP_VERSION "3.0.1b1"
22
#define EMSESP_PLATFORM "ESP32"

0 commit comments

Comments
 (0)