diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index d35614561..c4ef41407 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -396,6 +396,8 @@ // -- ESP-NOW ------------------------------------- //#define USE_TASMESH // Enable Tasmota Mesh using ESP-NOW (+11k code) +//#define USE_TASMESH_HEARTBEAT // If enabled, the broker will detect when nodes come online and offline and send Birth and LWT messages over MQTT correspondingly +//#define TASMESH_OFFLINE_DELAY 3 // Maximum number of seconds since the last heartbeat before the broker considers a node to be offline // -- OTA ----------------------------------------- //#define USE_ARDUINO_OTA // Add optional support for Arduino OTA with ESP8266 (+13k code) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_57_1_tasmesh_support.ino b/tasmota/tasmota_xdrv_driver/xdrv_57_1_tasmesh_support.ino index c2d70c61d..eefe976a9 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_57_1_tasmesh_support.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_57_1_tasmesh_support.ino @@ -91,6 +91,10 @@ struct mesh_peer_t { uint32_t lastMessageFromPeer; // Time of last message from peer #ifdef ESP32 char topic[MESH_TOPICSZ]; +#ifdef USE_TASMESH_HEARTBEAT + bool isAlive; // True if we have gotten a heartbeat recently + uint32_t lastHeartbeatFromPeer; // Time of last heartbeat from peer +#endif // USE_TASMESH_HEARTBEAT #endif //ESP32 }; @@ -164,7 +168,10 @@ enum MESH_Packet_Type { // Type of packet PACKET_TYPE_REGISTER_NODE, // register a node with encrypted broker-MAC, announce mqtt topic to ESP32-proxy - broker will send time ASAP PACKET_TYPE_REFRESH_NODE, // refresh node infos with encrypted broker-MAC, announce mqtt topic to ESP32-proxy - broker will send time slightly delayed PACKET_TYPE_MQTT, // send regular mqtt messages, single or multipackets - PACKET_TYPE_WANTTOPIC // the broker has no topic for this peer/node + PACKET_TYPE_WANTTOPIC, // the broker has no topic for this peer/node +#ifdef USE_TASMESH_HEARTBEAT + PACKET_TYPE_HEARTBEAT // sent periodically from nodes to the broker to signal aliveness +#endif // USE_TASMESH_HEARTBEAT }; /*********************************************************************************************\ diff --git a/tasmota/tasmota_xdrv_driver/xdrv_57_9_tasmesh.ino b/tasmota/tasmota_xdrv_driver/xdrv_57_9_tasmesh.ino index b6fc08630..415a4c20d 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_57_9_tasmesh.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_57_9_tasmesh.ino @@ -472,6 +472,22 @@ void MESHevery50MSecond(void) { // do something on the node // AddLog(LOG_LEVEL_DEBUG, PSTR("MSH: %30_H), (uint8_t *)&MESH.packetToConsume.front()); +#ifdef USE_TASMESH_HEARTBEAT + for (auto &_peer : MESH.peers){ + if (memcmp(_peer.MAC, MESH.packetToConsume.front().sender, 6) == 0) { + _peer.lastHeartbeatFromPeer = millis(); + + if (!_peer.isAlive) { + _peer.isAlive = true; + char stopic[TOPSZ]; + GetTopic_P(stopic, TELE, _peer.topic, S_LWT); + MqttPublishPayload(stopic, PSTR(MQTT_LWT_ONLINE)); + } + break; + } + } +#endif // USE_TASMESH_HEARTBEAT + MESHencryptPayload(&MESH.packetToConsume.front(), 0); switch (MESH.packetToConsume.front().type) { // case PACKET_TYPE_REGISTER_NODE: @@ -546,6 +562,9 @@ void MESHevery50MSecond(void) { // AddLog(LOG_LEVEL_INFO, PSTR("MSH: %*_H), MESH.packetToConsume.front().chunkSize, (uint8_t *)&MESH.packetToConsume.front().payload); } break; + case PACKET_TYPE_HEARTBEAT: + break; + default: AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t *)&MESH.packetToConsume.front(), MESH.packetToConsume.front().chunkSize +5); break; @@ -582,6 +601,17 @@ void MESHEverySecond(void) { AddLog(LOG_LEVEL_INFO, PSTR("MSH: Multi packets in buffer %u"), MESH.multiPackets.size()); MESH.multiPackets.erase(MESH.multiPackets.begin()); } + +#ifdef USE_TASMESH_HEARTBEAT + for (auto &_peer : MESH.peers){ + if (_peer.isAlive && TimePassedSince(_peer.lastHeartbeatFromPeer) > TASMESH_OFFLINE_DELAY * 1000) { + _peer.isAlive = false; + char stopic[TOPSZ]; + GetTopic_P(stopic, TELE, _peer.topic, S_LWT); + MqttPublishPayload(stopic, PSTR(MQTT_LWT_OFFLINE)); + } + } +#endif // USE_TASMESH_HEARTBEAT } #else // ESP8266 @@ -649,6 +679,16 @@ void MESHEverySecond(void) { MESHsetWifi(1); WifiBegin(3, MESH.channel); } + +#ifdef USE_TASMESH_HEARTBEAT + MESH.sendPacket.counter++; + MESH.sendPacket.TTL = 2; + MESH.sendPacket.chunks = 0; + MESH.sendPacket.chunk = 0; + MESH.sendPacket.chunkSize = 0; + MESH.sendPacket.type = PACKET_TYPE_HEARTBEAT; + MESHsendPacket(&MESH.sendPacket); +#endif // USE_TASMESH_HEARTBEAT } }