diff --git a/include/schedule.hpp b/include/schedule.hpp index 91cab9f..23bb993 100644 --- a/include/schedule.hpp +++ b/include/schedule.hpp @@ -23,7 +23,7 @@ class Schedule { void setAddress(const uint8_t source); void setDistance(const uint8_t distance); - void publishRaw(const char *payload); + void publishRaw(const bool enable); void handleFilter(const char *payload); void handleSend(const char *payload); diff --git a/include/store.hpp b/include/store.hpp index d738a6f..1fdb39c 100644 --- a/include/store.hpp +++ b/include/store.hpp @@ -13,7 +13,7 @@ struct Command { std::string key; // ebus command as string - std::vector command; // ebus command as vector ZZ PB SB NN DBx + std::vector command; // ebus command as vector of "ZZPBSBNNDBx" std::string unit; // unit of the received data bool active; // active sending of command uint32_t interval; // minimum interval between two commands in seconds @@ -32,7 +32,7 @@ class Store { void enqueCommand(const char *payload); void insertCommand(const char *payload); - void removeCommand(const char *topic); + void removeCommand(const char *payload); void publishCommands(); const std::string getCommands() const; @@ -41,7 +41,8 @@ class Store { const bool active() const; Command *nextActiveCommand(); - Command *findPassiveCommand(const std::vector &master); + std::vector findPassiveCommands( + const std::vector &master); void loadCommands(); void saveCommands() const; @@ -68,9 +69,9 @@ class Store { void deserializeCommands(const char *payload); static void publishCommand(const std::vector *commands, - const std::string &key, bool remove); + const std::string &key, const bool remove); - static void publishHomeAssistant(const Command *command, bool remove); + static void publishHomeAssistant(const Command *command, const bool remove); }; extern Store store; diff --git a/src/mqtt.cpp b/src/mqtt.cpp index d8c49d7..4e557aa 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -13,27 +13,31 @@ void onMqttConnect(bool sessionPresent) { // payload: true #ifdef EBUS_INTERNAL - mqttClient.subscribe("ebus/config/insert/#", 0); + mqttClient.subscribe("ebus/config/insert", 0); // Insert new command - // topic : ebus/config/insert/NAME_OF_COMMAND + // topic : ebus/config/insert // payload: ebus command in form of "ZZPBSBNNDBx" for e.g. // { - // "command": "08b509030d0600", + // "key": "UNIQUE_KEY", + // "command": "fe070009", // "unit": "°C", - // "active": true, - // "interval": 60, - // "master": false, + // "active": false, + // "interval": 0, + // "master": true, // "position": 1, - // "datatype": "DATA2c", - // "topic": "Aussentemperatur", + // "datatype": "DATA2b", + // "topic": "outdoor/temperature", // "ha": true, // "ha_class": "temperature" // } - mqttClient.subscribe("ebus/config/remove/#", 0); + mqttClient.subscribe("ebus/config/remove", 0); // Remove loaded command - // topic : ebus/config/remove/NAME_OF_COMMAND - // payload: true + // topic : ebus/config/remove + // payload: UNIQUE_KEY of ebus command + // { + // "key": "UNIQUE_KEY" + // } mqttClient.subscribe("ebus/config/list", 0); // Publish loaded commands @@ -43,7 +47,7 @@ void onMqttConnect(bool sessionPresent) { mqttClient.subscribe("ebus/config/raw", 0); // Enable/disable the raw data printout // topic : ebus/config/raw - // payload: true or false + // payload: true mqttClient.subscribe("ebus/config/filter", 0); // Insert raw data filter @@ -51,7 +55,7 @@ void onMqttConnect(bool sessionPresent) { // payload: array of sequences for e.g. // [ // "0700", - // "b509" + // "fe" // ] mqttClient.subscribe("ebus/config/load", 0); @@ -74,8 +78,8 @@ void onMqttConnect(bool sessionPresent) { // topic : ebus/config/send // payload: array of ebus command(s) in form of "ZZPBSBNNDBx" for e.g. // [ - // "08070400", - // "08b509030d0600" + // "05070400", + // "15070400" // ] #endif } @@ -94,14 +98,14 @@ void onMqttMessage(const char *topic, const char *payload, if (String(payload).equalsIgnoreCase("true")) reset(); } #ifdef EBUS_INTERNAL - else if (tmp.startsWith("ebus/config/insert/")) { + if (tmp.equals("ebus/config/insert")) { if (String(payload).length() > 0) store.enqueCommand(payload); - } else if (tmp.startsWith("ebus/config/remove/")) { - if (String(payload).equalsIgnoreCase("true")) store.removeCommand(topic); + } else if (tmp.equals("ebus/config/remove")) { + if (String(payload).length() > 0) store.removeCommand(payload); } else if (tmp.equals("ebus/config/list")) { if (String(payload).equalsIgnoreCase("true")) store.publishCommands(); } else if (tmp.equals("ebus/config/raw")) { - schedule.publishRaw(payload); + schedule.publishRaw(String(payload).equalsIgnoreCase("true")); } else if (tmp.equals("ebus/config/filter")) { if (String(payload).length() > 0) schedule.handleFilter(payload); } else if (tmp.equals("ebus/config/load")) { diff --git a/src/schedule.cpp b/src/schedule.cpp index 7a022d0..c5c79e8 100644 --- a/src/schedule.cpp +++ b/src/schedule.cpp @@ -2,6 +2,8 @@ #include +#include + #include "bus.hpp" #include "mqtt.hpp" @@ -69,18 +71,7 @@ void Schedule::setDistance(const uint8_t distance) { distanceCommands = distance * 1000; } -void Schedule::publishRaw(const char *payload) { - JsonDocument doc; - DeserializationError error = deserializeJson(doc, payload); - - if (error) { - std::string err = "DeserializationError "; - err += error.c_str(); - mqttClient.publish("ebus/config/error", 0, false, err.c_str()); - } else { - raw = doc.as(); - } -} +void Schedule::publishRaw(const bool enable) { raw = enable; } void Schedule::handleFilter(const char *payload) { JsonDocument doc; @@ -276,13 +267,13 @@ void Schedule::processPassive(const std::vector &master, } } - Command *pasCommand = store.findPassiveCommand(master); - if (pasCommand != nullptr) { - if (pasCommand->master) - publishValue(pasCommand, + std::vector pasCommands = store.findPassiveCommands(master); + for (Command *command : pasCommands) { + if (command->master) + publishValue(command, ebus::Sequence::range(master, 4, master.size() - 4)); else - publishValue(pasCommand, slave); + publishValue(command, slave); } } diff --git a/src/store.cpp b/src/store.cpp index 166e4cd..33e8b4b 100644 --- a/src/store.cpp +++ b/src/store.cpp @@ -23,10 +23,11 @@ void Store::insertCommand(const char *payload) { } else { Command command; - std::string key = doc["command"].as(); + std::string key = doc["key"].as(); command.key = key; - command.command = ebus::Sequence::to_vector(key); + command.command = + ebus::Sequence::to_vector(doc["command"].as()); command.unit = doc["unit"].as(); command.active = doc["active"].as(); command.interval = doc["interval"].as(); @@ -52,37 +53,45 @@ void Store::insertCommand(const char *payload) { if (it != usedCommands->end()) usedCommands->erase(it); usedCommands->push_back(command); - publishCommand(usedCommands, command.key, false); + publishCommand(usedCommands, key, false); init = true; lastInsert = millis(); } } -void Store::removeCommand(const char *topic) { - std::string tmp = topic; - std::string key(tmp.substr(tmp.rfind("/") + 1)); - - const std::vector::const_iterator actIt = - std::find_if(activeCommands.begin(), activeCommands.end(), - [&key](const Command &cmd) { return cmd.key == key; }); - - if (actIt != activeCommands.end()) { - publishCommand(&activeCommands, key, true); +void Store::removeCommand(const char *payload) { + JsonDocument doc; + DeserializationError error = deserializeJson(doc, payload); - activeCommands.erase(actIt); + if (error) { + std::string err = "DeserializationError "; + err += error.c_str(); + mqttClient.publish("ebus/config/error", 0, false, err.c_str()); } else { - const std::vector::const_iterator pasIt = - std::find_if(passiveCommands.begin(), passiveCommands.end(), + std::string key = doc["key"].as(); + + const std::vector::const_iterator actIt = + std::find_if(activeCommands.begin(), activeCommands.end(), [&key](const Command &cmd) { return cmd.key == key; }); - if (pasIt != passiveCommands.end()) { - publishCommand(&passiveCommands, key, true); + if (actIt != activeCommands.end()) { + publishCommand(&activeCommands, key, true); - passiveCommands.erase(pasIt); + activeCommands.erase(actIt); } else { - std::string err = key + " not found"; - mqttClient.publish("ebus/config/error", 0, false, err.c_str()); + const std::vector::const_iterator pasIt = + std::find_if(passiveCommands.begin(), passiveCommands.end(), + [&key](const Command &cmd) { return cmd.key == key; }); + + if (pasIt != passiveCommands.end()) { + publishCommand(&passiveCommands, key, true); + + passiveCommands.erase(pasIt); + } else { + std::string err = key + " not found"; + mqttClient.publish("ebus/config/error", 0, false, err.c_str()); + } } } } @@ -105,7 +114,9 @@ const std::string Store::getCommands() const { if (activeCommands.size() > 0) { for (const Command &command : activeCommands) { JsonObject obj = doc.add(); - obj["command"] = command.key; + + obj["key"] = command.key; + obj["command"] = ebus::Sequence::to_string(command.command); obj["unit"] = command.unit; obj["active"] = true; obj["interval"] = command.interval; @@ -121,7 +132,9 @@ const std::string Store::getCommands() const { if (passiveCommands.size() > 0) { for (const Command &command : passiveCommands) { JsonObject obj = doc.add(); - obj["command"] = command.key; + + obj["key"] = command.key; + obj["command"] = ebus::Sequence::to_string(command.command); obj["unit"] = command.unit; obj["active"] = false; obj["interval"] = command.interval; @@ -181,24 +194,16 @@ Command *Store::nextActiveCommand() { return command; } -Command *Store::findPassiveCommand(const std::vector &master) { - Command *command = nullptr; +std::vector Store::findPassiveCommands( + const std::vector &master) { + std::vector commands; - size_t count = - std::count_if(passiveCommands.begin(), passiveCommands.end(), - [&master](const Command &cmd) { - return ebus::Sequence::contains(master, cmd.command); - }); - - if (count > 0) { - command = - &(*std::find_if(passiveCommands.begin(), passiveCommands.end(), - [&master](const Command &cmd) { - return ebus::Sequence::contains(master, cmd.command); - })); + for (Command &command : passiveCommands) { + if (ebus::Sequence::contains(master, command.command)) + commands.push_back(&(command)); } - return command; + return commands; } void Store::loadCommands() { @@ -288,7 +293,9 @@ const std::string Store::serializeCommands() const { if (activeCommands.size() > 0) { for (const Command &command : activeCommands) { JsonArray arr = doc.add(); + arr.add(command.key); + arr.add(ebus::Sequence::to_string(command.command)); arr.add(command.unit); arr.add(true); arr.add(command.interval); @@ -304,7 +311,9 @@ const std::string Store::serializeCommands() const { if (passiveCommands.size() > 0) { for (const Command &command : passiveCommands) { JsonArray arr = doc.add(); + arr.add(command.key); + arr.add(ebus::Sequence::to_string(command.command)); arr.add(command.unit); arr.add(false); arr.add(command.interval); @@ -340,16 +349,17 @@ void Store::deserializeCommands(const char *payload) { for (JsonVariant variant : array) { JsonDocument tmpDoc; - tmpDoc["command"] = variant[0]; - tmpDoc["unit"] = variant[1]; - tmpDoc["active"] = variant[2]; - tmpDoc["interval"] = variant[3]; - tmpDoc["master"] = variant[4]; - tmpDoc["position"] = variant[5]; - tmpDoc["datatype"] = variant[6]; - tmpDoc["topic"] = variant[7]; - tmpDoc["ha"] = variant[8]; - tmpDoc["ha_class"] = variant[9]; + tmpDoc["key"] = variant[0]; + tmpDoc["command"] = variant[1]; + tmpDoc["unit"] = variant[2]; + tmpDoc["active"] = variant[3]; + tmpDoc["interval"] = variant[4]; + tmpDoc["master"] = variant[5]; + tmpDoc["position"] = variant[6]; + tmpDoc["datatype"] = variant[7]; + tmpDoc["topic"] = variant[8]; + tmpDoc["ha"] = variant[9]; + tmpDoc["ha_class"] = variant[10]; std::string tmpPayload; serializeJson(tmpDoc, tmpPayload); @@ -360,7 +370,7 @@ void Store::deserializeCommands(const char *payload) { } void Store::publishCommand(const std::vector *commands, - const std::string &key, bool remove) { + const std::string &key, const bool remove) { const std::vector::const_iterator it = std::find_if(commands->begin(), commands->end(), [&key](const Command &cmd) { return cmd.key == key; }); @@ -373,7 +383,8 @@ void Store::publishCommand(const std::vector *commands, if (!remove) { JsonDocument doc; - doc["command"] = it->key; + doc["key"] = it->key; + doc["command"] = ebus::Sequence::to_string(it->command); doc["unit"] = it->unit; doc["active"] = it->active; doc["interval"] = it->interval; @@ -392,15 +403,13 @@ void Store::publishCommand(const std::vector *commands, if (remove) { topic = "ebus/values/" + it->topic; mqttClient.publish(topic.c_str(), 0, false, ""); - - publishHomeAssistant(&(*it), true); - } else { - publishHomeAssistant(&(*it), !it->ha); } + + if (it->ha) publishHomeAssistant(&(*it), remove); } } -void Store::publishHomeAssistant(const Command *command, bool remove) { +void Store::publishHomeAssistant(const Command *command, const bool remove) { std::string name = command->topic; std::replace(name.begin(), name.end(), '/', '_'); @@ -418,7 +427,7 @@ void Store::publishHomeAssistant(const Command *command, bool remove) { doc["state_topic"] = "ebus/values/" + command->topic; if (command->unit.compare("null") != 0 && command->unit.length() > 0) doc["unit_of_measurement"] = command->unit; - doc["unique_id"] = command->key; + doc["unique_id"] = command->key; // TODO(yuhu-): use MAC + key doc["value_template"] = "{{value_json.value}}"; serializeJson(doc, payload);