Files
project-vesper/vesper/HEARTBEAT_FEATURE.md

4.1 KiB

💓 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

{
  "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

// 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

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:
    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:

// 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):

static const unsigned long HEARTBEAT_INTERVAL = 30000;  // 30 seconds

To change interval to 60 seconds:

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