allow number and string for MQTT json commands - #445

This commit is contained in:
proddy
2020-08-15 19:53:55 +02:00
parent 64063fa6cd
commit 67877d07c5
7 changed files with 53 additions and 81 deletions

View File

@@ -112,7 +112,7 @@ Breaking change: The MQTT base has been removed in version 2. The hostname is on
All commands must be written as `{"cmd":<cmd> ,"data":<data>, "id":<n>}`. All commands must be written as `{"cmd":<cmd> ,"data":<data>, "id":<n>}`.
The `id` can be replaced with `hc` for some devices. `cmd` and `data` must be enclose in quotes as a string. The `id` can be replaced with `hc` for some devices and represented as a string or a number. `cmd` is a string, `data` can be a string or number.
``` ```
*boiler_cmd* *boiler_cmd*

View File

@@ -27,7 +27,6 @@ CXX_STANDARD := -std=c++11
# Defined Symbols # Defined Symbols
#---------------------------------------------------------------------- #----------------------------------------------------------------------
DEFINES += -DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_NO_LED DEFINES += -DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_NO_LED
DEFINES += -DRUN_TEST
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# Sources & Files # Sources & Files

View File

@@ -92,11 +92,6 @@ void EMSESPShell::display_banner() {
emsesp::EMSESP::watch_id(WATCH_ID_NONE); emsesp::EMSESP::watch_id(WATCH_ID_NONE);
emsesp::EMSESP::watch(EMSESP::WATCH_OFF); emsesp::EMSESP::watch(EMSESP::WATCH_OFF);
#if defined(EMSESP_STANDALONE)
#ifdef RUN_TEST
invoke_command("test"); // same as "test default"
#endif
#endif
} }
// pre-loads all the console commands into the MAIN context // pre-loads all the console commands into the MAIN context

View File

@@ -186,7 +186,7 @@ char * Helpers::render_value(char * result, const int16_t value, const uint8_t f
return nullptr; return nullptr;
} }
// just print it if mo conversion required (format = 0) // just print it if no conversion required (format = 0)
if (!format) { if (!format) {
itoa(result, value, 10); itoa(result, value, 10);
return result; return result;
@@ -406,7 +406,7 @@ bool Helpers::value2bool(const char * v, bool & value) {
if ((bool_str == "off") || (bool_str == "0") or (bool_str == "false")) { if ((bool_str == "off") || (bool_str == "0") or (bool_str == "false")) {
value = false; value = false;
return true; // is a bool return true; // is a bool
} }
return false; // not a bool return false; // not a bool

View File

@@ -192,10 +192,12 @@ void Mqtt::show_mqtt(uuid::console::Shell & shell) {
shell.println(); shell.println();
} // namespace emsesp } // namespace emsesp
#if defined(EMSESP_DEBUG)
// simulate receiving a MQTT message, used only for testing // simulate receiving a MQTT message, used only for testing
void Mqtt::incoming(char * topic, char * payload) { void Mqtt::incoming(const char * topic, const char * payload) {
on_message(topic, payload, strlen(payload)); on_message(topic, payload, strlen(payload));
} }
#endif
// calls a command, context is the device_type // calls a command, context is the device_type
// id may be used to represent a heating circuit for example // id may be used to represent a heating circuit for example
@@ -223,7 +225,7 @@ bool Mqtt::call_command(const uint8_t device_type, const char * cmd, const char
} }
// received an MQTT message that we subscribed too // received an MQTT message that we subscribed too
void Mqtt::on_message(char * topic, char * payload, size_t len) { void Mqtt::on_message(const char * topic, const char * payload, size_t len) {
if (len == 0) { if (len == 0) {
return; return;
} }
@@ -257,7 +259,7 @@ void Mqtt::on_message(char * topic, char * payload, size_t len) {
return; return;
} }
// check for hc and id // check for hc and id, and convert to int
int8_t n = -1; // no value int8_t n = -1; // no value
if (doc.containsKey("hc")) { if (doc.containsKey("hc")) {
n = doc["hc"]; n = doc["hc"];
@@ -265,9 +267,20 @@ void Mqtt::on_message(char * topic, char * payload, size_t len) {
n = doc["id"]; n = doc["id"];
} }
if (!call_command(mf.device_type_, command, doc["data"], n)) { bool cmd_known = false;
// if we got here we didn't find a matching command JsonVariant data = doc["data"];
LOG_ERROR(F("MQTT error: no matching cmd: %s"), command); if (data.is<char *>()) {
cmd_known = call_command(mf.device_type_, command, data.as<char *>(), n);
} else if (data.is<int>()) {
char data_str[10];
cmd_known = call_command(mf.device_type_, command, Helpers::itoa(data_str, (int16_t)data.as<int>()), n);
} else if (data.is<float>()) {
char data_str[10];
cmd_known = call_command(mf.device_type_, command, Helpers::render_value(data_str, (float)data.as<float>(), 2), n);
}
if (!cmd_known) {
LOG_ERROR(F("MQTT: no matching cmd or invalid data: %s"), command);
} }
return; return;

View File

@@ -96,7 +96,9 @@ class Mqtt {
mqttClient_->disconnect(); mqttClient_->disconnect();
} }
void incoming(char * topic, char * payload); // for testing #if defined(EMSESP_DEBUG)
void incoming(const char * topic, const char * payload); // for testing only
#endif
static bool connected() { static bool connected() {
return mqttClient_->connected(); return mqttClient_->connected();
@@ -163,7 +165,7 @@ class Mqtt {
static std::shared_ptr<const MqttMessage> queue_subscribe_message(const std::string & topic); static std::shared_ptr<const MqttMessage> queue_subscribe_message(const std::string & topic);
void on_publish(uint16_t packetId); void on_publish(uint16_t packetId);
void on_message(char * topic, char * payload, size_t len); void on_message(const char * topic, const char * payload, size_t len);
void process_queue(); void process_queue();
void process_all_queue(); void process_all_queue();

View File

@@ -28,7 +28,7 @@ namespace emsesp {
// used with the 'test' command, under su/admin // used with the 'test' command, under su/admin
void Test::run_test(uuid::console::Shell & shell, const std::string & command) { void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
if (command == "default") { if (command == "default") {
run_test(shell, "general"); // add the default test case here run_test(shell, "mqtt"); // add the default test case here
} }
if (command.empty()) { if (command.empty()) {
@@ -553,78 +553,40 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
shell.loop_all(); shell.loop_all();
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char boiler_topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
char payload[100]; char thermostat_topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
char system_topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
// test publish and adding to queue // test publish and adding to queue
EMSESP::txservice_.flush_tx_queue(); EMSESP::txservice_.flush_tx_queue();
EMSESP::EMSESP::mqtt_.publish("boiler_cmd", "test me"); EMSESP::EMSESP::mqtt_.publish("boiler_cmd", "test me");
Mqtt::show_mqtt(shell); // show queue Mqtt::show_mqtt(shell); // show queue
strcpy(topic, "ems-esp/boiler_cmd"); strcpy(boiler_topic, "ems-esp/boiler_cmd");
strcpy(payload, "12345"); strcpy(thermostat_topic, "ems-esp/thermostat_cmd");
EMSESP::mqtt_.incoming(topic, payload); // invalid format strcpy(system_topic, "ems-esp/saystem_cmd");
EMSESP::mqtt_.incoming(payload, payload); // no matching topic
strcpy(topic, "ems-esp/boiler_cmd"); EMSESP::mqtt_.incoming(boiler_topic, "12345"); // invalid format
strcpy(payload, "{\"cmd\":\"garbage\",\"data\":22.52}"); EMSESP::mqtt_.incoming("bad_topic", "12345"); // no matching topic
EMSESP::mqtt_.incoming(topic, payload); // should report error EMSESP::mqtt_.incoming(boiler_topic, "{\"cmd\":\"garbage\",\"data\":22.52}"); // should report error
EMSESP::mqtt_.incoming(boiler_topic, "{\"cmd\":\"comfort\",\"data\":\"eco\"}");
EMSESP::mqtt_.incoming(boiler_topic, "{\"cmd\":\"wwactivated\",\"data\":\"1\"}");
EMSESP::mqtt_.incoming(boiler_topic, "{\"cmd\":\"wwactivated\",\"data\":1}");
EMSESP::mqtt_.incoming(boiler_topic, "{\"cmd\":\"flowtemp\",\"data\":55}");
strcpy(topic, "ems-esp/boiler_cmd"); EMSESP::mqtt_.incoming(system_topic, "{\"cmd\":\"send\",\"data\":\"01 02 03 04 05\"}");
strcpy(payload, "{\"cmd\":\"comfort\",\"data\":\"eco\"}"); EMSESP::mqtt_.incoming(system_topic, "{\"cmd\":\"pin\",\"id\":12,\"data\":\"1\"}");
EMSESP::mqtt_.incoming(topic, payload);
strcpy(topic, "ems-esp/boiler_cmd"); EMSESP::mqtt_.incoming(thermostat_topic, "{\"cmd\":\"wwmode\",\"data\":\"auto\"}");
strcpy(payload, "{\"cmd\":\"wwactivated\",\"data\":\"1\"}"); EMSESP::mqtt_.incoming(thermostat_topic, "{\"cmd\":\"control\",\"data\":\"1\"}");
EMSESP::mqtt_.incoming(topic, payload); EMSESP::mqtt_.incoming(thermostat_topic, "{\"cmd\":\"control\",\"data\":1}");
EMSESP::mqtt_.incoming(thermostat_topic, "{\"cmd\":\"mode\",\"data\":\"auto\",\"id\":2}");
strcpy(topic, "ems-esp/boiler_cmd"); EMSESP::mqtt_.incoming(thermostat_topic, "{\"cmd\":\"mode\",\"data\":\"auto\",\"hc\":2}"); // hc as number
strcpy(payload, "{\"cmd\":\"wwactivated\",\"data\":1}"); EMSESP::mqtt_.incoming(thermostat_topic, "{\"cmd\":\"mode\",\"data\":\"auto\",\"hc\":\"2\"}"); // hc as string
EMSESP::mqtt_.incoming(topic, payload); EMSESP::mqtt_.incoming(thermostat_topic, "{\"cmd\":\"temp\",\"data\":22.56}");
EMSESP::mqtt_.incoming(thermostat_topic, "{\"cmd\":\"temp\",\"data\":22}");
strcpy(topic, "ems-esp/boiler_cmd"); EMSESP::mqtt_.incoming(thermostat_topic, "{\"cmd\":\"temp\",\"data\":\"22.56\"}");
strcpy(payload, "{\"cmd\":\"flowtemp\",\"data\":55}"); EMSESP::mqtt_.incoming(thermostat_topic, "{\"cmd\":\"temp\",\"id\":2,\"data\":22}");
EMSESP::mqtt_.incoming(topic, payload);
strcpy(topic, "ems-esp/system_cmd");
strcpy(payload, "{\"cmd\":\"send\",\"data\":\"01 02 03 04 05\"}");
EMSESP::mqtt_.incoming(topic, payload);
strcpy(topic, "ems-esp/system_cmd");
strcpy(payload, "{\"cmd\":\"pin\",\"id\":12,\"data\":\"1\"}");
EMSESP::mqtt_.incoming(topic, payload);
strcpy(topic, "ems-esp/thermostat_cmd");
strcpy(payload, "{\"cmd\":\"wwmode\",\"data\":\"auto\"}");
EMSESP::mqtt_.incoming(topic, payload);
strcpy(topic, "ems-esp/thermostat_cmd");
strcpy(payload, "{\"cmd\":\"control\",\"data\":\"1\"}");
EMSESP::mqtt_.incoming(topic, payload);
strcpy(topic, "ems-esp/thermostat_cmd");
strcpy(payload, "{\"cmd\":\"control\",\"data\":1}");
EMSESP::mqtt_.incoming(topic, payload);
strcpy(topic, "ems-esp/thermostat_cmd");
strcpy(payload, "{\"cmd\":\"mode\",\"data\":\"auto\",\"id\":2}"); // with id
EMSESP::mqtt_.incoming(topic, payload);
strcpy(topic, "ems-esp/thermostat_cmd");
strcpy(payload, "{\"cmd\":\"mode\",\"data\":\"auto\",\"hc\":2}"); // with hc
EMSESP::mqtt_.incoming(topic, payload);
strcpy(topic, "ems-esp/thermostat_cmd");
strcpy(payload, "{\"cmd\":\"temp\",\"data\":22.52}");
EMSESP::mqtt_.incoming(topic, payload);
strcpy(topic, "ems-esp/thermostat_cmd");
strcpy(payload, "{\"cmd\":\"temp\",\"data\":22.52}");
EMSESP::mqtt_.incoming(topic, payload);
strcpy(topic, "ems-esp/thermostat_cmd");
strcpy(payload, "{\"cmd\":\"temp\",\"id\":2,\"data\":22}");
EMSESP::mqtt_.incoming(topic, payload);
// EMSESP::txservice_.show_tx_queue(); // EMSESP::txservice_.show_tx_queue();
// EMSESP::publish_all_values(); // EMSESP::publish_all_values();
@@ -636,6 +598,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
shell.invoke_command("call"); shell.invoke_command("call");
shell.invoke_command("call wwmode"); shell.invoke_command("call wwmode");
shell.invoke_command("call mode auto 2"); shell.invoke_command("call mode auto 2");
shell.invoke_command("call temp 22.56");
Mqtt::resubscribe(); Mqtt::resubscribe();
Mqtt::show_mqtt(shell); // show queue Mqtt::show_mqtt(shell); // show queue