140 lines
4.1 KiB
Markdown
140 lines
4.1 KiB
Markdown
# 💓 MQTT Heartbeat Feature
|
|
|
|
## Overview
|
|
Implemented a **retained MQTT heartbeat** system that sends periodic status updates every 30 seconds when the controller is connected to MQTT.
|
|
|
|
## What It Does
|
|
|
|
### Heartbeat Message
|
|
Every 30 seconds, the controller publishes a **retained** message to:
|
|
```
|
|
vesper/{deviceID}/status/heartbeat
|
|
```
|
|
|
|
### Message Format
|
|
```json
|
|
{
|
|
"status": "INFO",
|
|
"type": "heartbeat",
|
|
"payload": {
|
|
"device_id": "VESPER-ABC123",
|
|
"firmware_version": "130",
|
|
"timestamp": "Uptime: 5h 23m 45s",
|
|
"ip_address": "192.168.1.100",
|
|
"gateway": "192.168.1.1",
|
|
"uptime_ms": 19425000
|
|
}
|
|
}
|
|
```
|
|
|
|
### Key Features
|
|
✅ **Retained Message** - Only the LAST heartbeat stays on the broker
|
|
✅ **Auto-Start** - Begins when MQTT connects
|
|
✅ **Auto-Stop** - Stops when MQTT disconnects
|
|
✅ **30-Second Interval** - Periodic updates
|
|
✅ **First Beat Immediate** - Sends first heartbeat right after connecting
|
|
✅ **QoS 1** - Reliable delivery
|
|
|
|
## Why This is Awesome
|
|
|
|
### For Your Flutter App
|
|
1. **Immediate Status** - Any new connection gets the last known status instantly
|
|
2. **Stale Detection** - Can detect if controller went offline (timestamp too old)
|
|
3. **Device Discovery** - Apps can subscribe to `vesper/+/status/heartbeat` to find all controllers
|
|
4. **No Polling** - Just subscribe once and get automatic updates
|
|
|
|
### Example App Logic
|
|
```dart
|
|
// Subscribe to heartbeat
|
|
mqtt.subscribe('vesper/DEVICE-123/status/heartbeat');
|
|
|
|
// On message received
|
|
if (heartbeat.uptime_ms > lastSeen.uptime_ms + 120000) {
|
|
// No heartbeat for 2+ minutes = controller offline
|
|
showOfflineWarning();
|
|
}
|
|
```
|
|
|
|
## Implementation Details
|
|
|
|
### Files Modified
|
|
1. **MQTTAsyncClient.hpp** - Added heartbeat timer and methods
|
|
2. **MQTTAsyncClient.cpp** - Implemented heartbeat logic
|
|
3. **Networking.hpp** - Added `getGateway()` method
|
|
4. **Networking.cpp** - Implemented `getGateway()` method
|
|
|
|
### New Methods Added
|
|
```cpp
|
|
void startHeartbeat(); // Start 30s periodic timer
|
|
void stopHeartbeat(); // Stop timer
|
|
void publishHeartbeat(); // Build and publish message
|
|
void heartbeatTimerCallback(); // Timer callback handler
|
|
```
|
|
|
|
### Timer Configuration
|
|
- **Type**: FreeRTOS Software Timer
|
|
- **Mode**: Auto-reload (repeating)
|
|
- **Period**: 30,000 ms (30 seconds)
|
|
- **Core**: Runs on Core 0 (MQTT task core)
|
|
|
|
## Testing
|
|
|
|
### How to Test
|
|
1. Flash the firmware
|
|
2. Subscribe to the heartbeat topic:
|
|
```bash
|
|
mosquitto_sub -h YOUR_BROKER -t "vesper/+/status/heartbeat" -v
|
|
```
|
|
3. You should see heartbeats every 30 seconds
|
|
4. Disconnect the controller - the last message stays retained
|
|
5. Reconnect - you'll immediately see the last retained message, then new ones every 30s
|
|
|
|
### Expected Serial Output
|
|
```
|
|
💓 Starting MQTT heartbeat (every 30 seconds)
|
|
💓 Published heartbeat (retained) - IP: 192.168.1.100, Uptime: 45000ms
|
|
💓 Published heartbeat (retained) - IP: 192.168.1.100, Uptime: 75000ms
|
|
❤️ Stopped MQTT heartbeat (when MQTT disconnects)
|
|
```
|
|
|
|
## Future Enhancements (Optional)
|
|
|
|
### Possible Additions:
|
|
- Add actual RTC timestamp (instead of just uptime)
|
|
- Add WiFi signal strength (RSSI) for WiFi connections
|
|
- Add free heap memory
|
|
- Add current playback status
|
|
- Add bell configuration version/hash
|
|
|
|
### Implementation Example:
|
|
```cpp
|
|
// In publishHeartbeat()
|
|
payload["rssi"] = WiFi.RSSI(); // WiFi signal strength
|
|
payload["free_heap"] = ESP.getFreeHeap();
|
|
payload["playback_active"] = player.isPlaying;
|
|
```
|
|
|
|
## Configuration
|
|
|
|
### Current Settings (can be changed in MQTTAsyncClient.hpp):
|
|
```cpp
|
|
static const unsigned long HEARTBEAT_INTERVAL = 30000; // 30 seconds
|
|
```
|
|
|
|
To change interval to 60 seconds:
|
|
```cpp
|
|
static const unsigned long HEARTBEAT_INTERVAL = 60000; // 60 seconds
|
|
```
|
|
|
|
## Notes
|
|
- Message is published with **QoS 1** (at least once delivery)
|
|
- Message is **retained** (broker keeps last message)
|
|
- Timer starts automatically when MQTT connects
|
|
- Timer stops automatically when MQTT disconnects
|
|
- First heartbeat is sent immediately upon connection (no 30s wait)
|
|
|
|
---
|
|
**Feature Implemented**: January 2025
|
|
**Version**: Firmware v130+
|
|
**Status**: ✅ Production Ready
|