diff --git a/CHANGELOG.md b/CHANGELOG.md index d1f78d769..40eefa499 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file. ### Added - Initial support for optional ``Template`` JSON fieldpair ``"CMND":";;..."`` (#11788) - ESP32 pulldown buttons ``Button_d`` and ``Button_id`` (#10814) +- Support for MQTT using Azure IoT Hub by Kevin Saye (#11906) ## [Released] diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 80d1a08ab..5904545a6 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -80,6 +80,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota ### Added - Initial support for optional ``Template`` JSON fieldpair ``"CMND":";;..."`` [#11788](https://github.com/arendst/Tasmota/issues/11788) - ESP32 pulldown buttons ``Button_d`` and ``Button_id`` [#10814](https://github.com/arendst/Tasmota/issues/10814) +- Support for MQTT using Azure IoT Hub by Kevin Saye [#11906](https://github.com/arendst/Tasmota/issues/11906) ### Breaking Changed diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index b7147058b..5a5dda444 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -419,6 +419,7 @@ // Any valid fingerprint with the old algo will be automatically updated to the new algo. // Enable this if you want to disable the old algo check, which should be more secure // for USE_4K_RSA (support for 4096 bits certificates, instead of 2048), you need to uncommend `-DUSE_4K_RSA` in `build_flags` from `platform.ini` or `platform_override.ini` +// #define USE_MQTT_AZURE_IOT // Enable MQTT for Azure IoT Hub (+1k code) // -- Telegram Protocol --------------------------- //#define USE_TELEGRAM // Support for Telegram protocol (+49k code, +7.0k mem and +4.8k additional during connection handshake) diff --git a/tasmota/xdrv_02_mqtt.ino b/tasmota/xdrv_02_mqtt.ino index 48aa65d9d..8fcb330a4 100644 --- a/tasmota/xdrv_02_mqtt.ino +++ b/tasmota/xdrv_02_mqtt.ino @@ -23,11 +23,11 @@ #define MQTT_WIFI_CLIENT_TIMEOUT 200 // Wifi TCP connection timeout (default is 5000 mSec) #endif -#if defined(USE_MQTT_AZURE_IOT) - #include - #undef MQTT_PORT - #define MQTT_PORT 8883 -#endif //USE_MQTT_AZURE_IOT +#ifdef USE_MQTT_AZURE_IOT +#include +#undef MQTT_PORT +#define MQTT_PORT 8883 +#endif // USE_MQTT_AZURE_IOT #define USE_MQTT_NEW_PUBSUBCLIENT @@ -231,14 +231,14 @@ void MqttDisconnect(void) { } void MqttSubscribeLib(const char *topic) { - #if defined(USE_MQTT_AZURE_IOT) - // Azure IoT Hub currently does not support custom topics: https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-mqtt-support - String realTopicString = "devices/" + String(SettingsText(SET_MQTT_CLIENT)); - realTopicString += "/messages/devicebound/#"; - MqttClient.subscribe(realTopicString.c_str()); - #else //USE_MQTT_AZURE_IOT - MqttClient.subscribe(topic); - #endif //USE_MQTT_AZURE_IOT +#ifdef USE_MQTT_AZURE_IOT + // Azure IoT Hub currently does not support custom topics: https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-mqtt-support + String realTopicString = "devices/" + String(SettingsText(SET_MQTT_CLIENT)); + realTopicString += "/messages/devicebound/#"; + MqttClient.subscribe(realTopicString.c_str()); +#else + MqttClient.subscribe(topic); +#endif // USE_MQTT_AZURE_IOT MqttClient.loop(); // Solve LmacRxBlk:1 messages } @@ -258,24 +258,24 @@ bool MqttPublishLib(const char* topic, bool retained) { } bool result; - #if defined(USE_MQTT_AZURE_IOT) - String sourceTopicString = String(topic); - sourceTopicString.replace("/", "%2F"); - String topicString = "devices/" + String(SettingsText(SET_MQTT_CLIENT)); - topicString+= "/messages/events/topic=" + sourceTopicString; +#ifdef USE_MQTT_AZURE_IOT + String sourceTopicString = String(topic); + sourceTopicString.replace("/", "%2F"); + String topicString = "devices/" + String(SettingsText(SET_MQTT_CLIENT)); + topicString+= "/messages/events/topic=" + sourceTopicString; - JsonParser mqtt_message((char*) String(TasmotaGlobal.mqtt_data).c_str()); - JsonParserObject message_object = mqtt_message.getRootObject(); - if (message_object.isValid()) { // only sending valid JSON, yet this is optional - result = MqttClient.publish(topicString.c_str(), TasmotaGlobal.mqtt_data, retained); - AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "Sending '%s'"), TasmotaGlobal.mqtt_data); - } else { - AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "Invalid JSON, '%s' for topic '%s', not sending to Azure IoT Hub"), TasmotaGlobal.mqtt_data, topic); - result = true; - } - #else //USE_MQTT_AZURE_IOT - result = MqttClient.publish(topic, TasmotaGlobal.mqtt_data, retained); - #endif //USE_MQTT_AZURE_IOT + JsonParser mqtt_message((char*) String(TasmotaGlobal.mqtt_data).c_str()); + JsonParserObject message_object = mqtt_message.getRootObject(); + if (message_object.isValid()) { // only sending valid JSON, yet this is optional + result = MqttClient.publish(topicString.c_str(), TasmotaGlobal.mqtt_data, retained); + AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "Sending '%s'"), TasmotaGlobal.mqtt_data); + } else { + AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_MQTT "Invalid JSON, '%s' for topic '%s', not sending to Azure IoT Hub"), TasmotaGlobal.mqtt_data, topic); + result = true; + } +#else + result = MqttClient.publish(topic, TasmotaGlobal.mqtt_data, retained); +#endif // USE_MQTT_AZURE_IOT yield(); // #3313 return result; } @@ -307,24 +307,24 @@ void MqttDataHandler(char* mqtt_topic, uint8_t* mqtt_data, unsigned int data_len // Save MQTT data ASAP as it's data is discarded by PubSubClient with next publish as used in MQTTlog char topic[TOPSZ]; - #if defined(USE_MQTT_AZURE_IOT) - // for Azure, we read the topic from the property of the message - String fullTopicString = String(mqtt_topic); - int startOfTopic = fullTopicString.indexOf("TOPIC="); - if (startOfTopic == -1){ - AddLog(LOG_LEVEL_ERROR, PSTR(D_LOG_MQTT "Azure IoT message without the property TOPIC, case sensitive.")); - return; - } - String newTopic = fullTopicString.substring(startOfTopic + 6); - newTopic.replace("%2F", "/"); - if (newTopic.indexOf("/") == -1){ - AddLog(LOG_LEVEL_ERROR, PSTR(D_LOG_MQTT "Invalid Topic %s"), newTopic.c_str()); - return; - } - strlcpy(topic, newTopic.c_str(), sizeof(topic)); - #else //USE_MQTT_AZURE_IOT - strlcpy(topic, mqtt_topic, sizeof(topic)); - #endif //USE_MQTT_AZURE_IOT +#ifdef USE_MQTT_AZURE_IOT + // for Azure, we read the topic from the property of the message + String fullTopicString = String(mqtt_topic); + int startOfTopic = fullTopicString.indexOf("TOPIC="); + if (startOfTopic == -1){ + AddLog(LOG_LEVEL_ERROR, PSTR(D_LOG_MQTT "Azure IoT message without the property TOPIC, case sensitive.")); + return; + } + String newTopic = fullTopicString.substring(startOfTopic + 6); + newTopic.replace("%2F", "/"); + if (newTopic.indexOf("/") == -1){ + AddLog(LOG_LEVEL_ERROR, PSTR(D_LOG_MQTT "Invalid Topic %s"), newTopic.c_str()); + return; + } + strlcpy(topic, newTopic.c_str(), sizeof(topic)); +#else + strlcpy(topic, mqtt_topic, sizeof(topic)); +#endif // USE_MQTT_AZURE_IOT mqtt_data[data_len] = 0; char data[data_len +1]; memcpy(data, mqtt_data, sizeof(data)); @@ -753,10 +753,9 @@ void MqttReconnect(void) { } String azureMqtt_userString = String(SettingsText(SET_MQTT_HOST)) + "/" + String(SettingsText(SET_MQTT_CLIENT)); + "/?api-version=2018-06-30"; if (MqttClient.connect(TasmotaGlobal.mqtt_client, azureMqtt_userString.c_str(), mqtt_pwd, stopic, 1, lwt_retain, TasmotaGlobal.mqtt_data, MQTT_CLEAN_SESSION)) { -#else //USE_MQTT_AZURE_IOT +#else if (MqttClient.connect(TasmotaGlobal.mqtt_client, mqtt_user, mqtt_pwd, stopic, 1, lwt_retain, TasmotaGlobal.mqtt_data, MQTT_CLEAN_SESSION)) { -#endif //USE_MQTT_AZURE_IOT - +#endif // USE_MQTT_AZURE_IOT #ifdef USE_MQTT_TLS if (Mqtt.mqtt_tls) { #ifdef ESP8266