void BootNormal::_mqttCallback(char* topic, char* payload) { String message = String(payload); String unified = String(topic); unified.remove(0, strlen(Config.get().mqtt.baseTopic) + strlen(Config.get().deviceId) + 1); // Remove devices/${id}/ --- +1 for / // Device properties if (Config.get().ota.enabled && unified == "$ota") { if (message != this->_interface->firmware.version) { Logger.log(F("✴ OTA available (version ")); Logger.log(message); Logger.logln(F(")")); if (strlen(payload) + 1 <= MAX_FIRMWARE_VERSION_LENGTH) { strcpy(this->_otaVersion, payload); this->_flaggedForOta = true; Logger.logln(F("Flagged for OTA")); } else { Logger.logln(F("Version string received is too long")); } } return; } else if (unified == "$reset" && message == "true") { this->_fillMqttTopic(PSTR("/$reset")); MqttClient.publish("false", true); this->_flaggedForReset = true; Logger.logln(F("Flagged for reset by network")); return; } // Implicit node properties unified.remove(unified.length() - 4, 4); // Remove /set unsigned int separator = 0; for (unsigned int i = 0; i < unified.length(); i++) { if (unified.charAt(i) == '/') { separator = i; break; } } String node = unified.substring(0, separator); String property = unified.substring(separator + 1); int homieNodeIndex = -1; for (int i = 0; i < this->_interface->registeredNodesCount; i++) { const HomieNode* homieNode = this->_interface->registeredNodes[i]; if (node == homieNode->getId()) { homieNodeIndex = i; break; } } if (homieNodeIndex == -1) { Logger.log(F("Node ")); Logger.log(node); Logger.logln(F(" not registered")); return; } const HomieNode* homieNode = this->_interface->registeredNodes[homieNodeIndex]; int homieNodePropertyIndex = -1; for (int i = 0; i < homieNode->getSubscriptionsCount(); i++) { Subscription subscription = homieNode->getSubscriptions()[i]; if (property == subscription.property) { homieNodePropertyIndex = i; break; } } if (!homieNode->getSubscribeToAll() && homieNodePropertyIndex == -1) { Logger.log(F("Node ")); Logger.log(node); Logger.log(F(" not subscribed to ")); Logger.logln(property); return; } Logger.logln(F("Calling global input handler...")); bool handled = this->_interface->globalInputHandler(node, property, message); if (handled) return; Logger.logln(F("Calling node input handler...")); handled = homieNode->getInputHandler()(property, message); if (handled) return; if (homieNodePropertyIndex != -1) { // might not if subscribed to all only Subscription homieNodeSubscription = homieNode->getSubscriptions()[homieNodePropertyIndex]; Logger.logln(F("Calling property input handler...")); handled = homieNodeSubscription.inputHandler(message); } if (!handled){ Logger.logln(F("No handlers handled the following packet:")); Logger.log(F(" • Node ID: ")); Logger.logln(node); Logger.log(F(" • Property: ")); Logger.logln(property); Logger.log(F(" • Value: ")); Logger.logln(message); } }
void BootNormal::_onMqttMessage(char* topic, char* payload, uint8_t qos, size_t len, size_t index, size_t total) { if (total == 0) return; // no empty message possible topic = topic + strlen(_interface->config->get().mqtt.baseTopic) + strlen(_interface->config->get().deviceId) + 1; // Remove devices/${id}/ --- +1 for / if (strcmp_P(topic, PSTR("$ota/payload")) == 0) { // If this is the $ota payload if (_flaggedForOta) { if (index == 0) { Update.begin(total); _interface->logger->logln(F("OTA started")); _interface->logger->logln(F("Triggering HOMIE_OTA_STARTED event...")); _interface->eventHandler(HOMIE_OTA_STARTED); } _interface->logger->log(F("Receiving OTA payload (")); _interface->logger->log(index + len); _interface->logger->log(F("/")); _interface->logger->log(total); _interface->logger->logln(F(")...")); Update.write((uint8_t*)payload, len); if (index + len == total) { bool success = Update.end(); if (success) { _interface->logger->logln(F("✔ OTA success")); _interface->logger->logln(F("Triggering HOMIE_OTA_SUCCESSFUL event...")); _interface->eventHandler(HOMIE_OTA_SUCCESSFUL); _flaggedForReboot = true; } else { _interface->logger->logln(F("✖ OTA failed")); _interface->logger->logln(F("Triggering HOMIE_OTA_FAILED event...")); _interface->eventHandler(HOMIE_OTA_FAILED); } _flaggedForOta = false; _interface->mqttClient->unsubscribe(_prefixMqttTopic(PSTR("/$ota/payload"))); } } else { _interface->logger->log(F("Receiving OTA payload but not requested, skipping...")); } return; } if (_mqttPayloadBuffer == nullptr) _mqttPayloadBuffer = std::unique_ptr<char[]>(new char[total + 1]); memcpy(_mqttPayloadBuffer.get() + index, payload, len); if (index + len != total) return; _mqttPayloadBuffer.get()[total] = '\0'; if (strcmp_P(topic, PSTR("$ota")) == 0) { // If this is the $ota announcement if (strcmp(_mqttPayloadBuffer.get(), _interface->firmware.version) != 0) { _interface->logger->log(F("✴ OTA available (version ")); _interface->logger->log(_mqttPayloadBuffer.get()); _interface->logger->logln(F(")")); _interface->logger->logln(F("Subscribing to OTA payload...")); _interface->mqttClient->subscribe(_prefixMqttTopic(PSTR("/$ota/payload")), 0); _flaggedForOta = true; } return; } if (strcmp_P(topic, PSTR("$reset")) == 0 && strcmp(_mqttPayloadBuffer.get(), "true") == 0) { _interface->mqttClient->publish(_prefixMqttTopic(PSTR("/$reset")), 1, true, "false"); _flaggedForReset = true; _interface->logger->logln(F("Flagged for reset by network")); return; } // Implicit node properties topic[strlen(topic) - 4] = '\0'; // Remove /set uint16_t separator = 0; for (uint16_t i = 0; i < strlen(topic); i++) { if (topic[i] == '/') { separator = i; break; } } char* node = topic; node[separator] = '\0'; char* property = topic + separator + 1; HomieNode* homieNode = HomieNode::find(node); if (!homieNode) { _interface->logger->log(F("Node ")); _interface->logger->log(node); _interface->logger->logln(F(" not registered")); return; } Subscription subscription; bool subscriptionFound = false; for (Subscription iSubscription : homieNode->getSubscriptions()) { if (strcmp(property, iSubscription.property) == 0) { subscription = iSubscription; subscriptionFound = true; break; } } if (!homieNode->isSubscribedToAll() && !subscriptionFound) { _interface->logger->log(F("Node ")); _interface->logger->log(node); _interface->logger->log(F(" not subscribed to ")); _interface->logger->logln(property); return; } _interface->logger->logln(F("Calling global input handler...")); bool handled = _interface->globalInputHandler(String(node), String(property), String(_mqttPayloadBuffer.get())); if (handled) return; _interface->logger->logln(F("Calling node input handler...")); handled = homieNode->handleInput(String(property), String(_mqttPayloadBuffer.get())); if (handled) return; if (subscriptionFound) { // might not if subscribed to all only _interface->logger->logln(F("Calling property input handler...")); handled = subscription.inputHandler(String(_mqttPayloadBuffer.get())); } if (!handled){ _interface->logger->logln(F("No handlers handled the following packet:")); _interface->logger->log(F(" • Node ID: ")); _interface->logger->logln(node); _interface->logger->log(F(" • Property: ")); _interface->logger->logln(property); _interface->logger->log(F(" • Value: ")); _interface->logger->logln(_mqttPayloadBuffer.get()); } }