Mqtt home assistant working
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
# MQTT Troubleshooting Guide
|
||||
|
||||
## Changes Made
|
||||
|
||||
### 1. **Fixed Discovery Topic**
|
||||
- Changed from `homeassistant/event/wand_spell/config` to `homeassistant/sensor/wand_spell/config`
|
||||
- The `event` component type doesn't work properly for spell data
|
||||
- Using `sensor` component allows state tracking in Home Assistant
|
||||
|
||||
### 2. **Added Comprehensive Debug Logging**
|
||||
All MQTT operations now show detailed logs:
|
||||
- **Connection**: Shows broker URI, username, network status
|
||||
- **Publishing**: Shows topic, payload, QoS, msg_id
|
||||
- **Published confirmation**: `MQTT_EVENT_PUBLISHED` confirms message was acknowledged by broker
|
||||
- **Subscriptions**: Confirms when subscriptions are successful
|
||||
- **Received data**: Shows any data received from broker
|
||||
|
||||
### 3. **Added Connectivity Test**
|
||||
- ESP32 now subscribes to `wand/test` topic on connect
|
||||
- This verifies bidirectional MQTT communication
|
||||
- You can test by publishing to this topic from Home Assistant
|
||||
|
||||
## How to Test
|
||||
|
||||
### Step 1: Recompile and Flash
|
||||
```bash
|
||||
./build-s3.sh flash monitor
|
||||
```
|
||||
|
||||
### Step 2: Watch Serial Output
|
||||
After connecting to WiFi, you should see:
|
||||
```
|
||||
I (xxxxx) ha_mqtt: ✓ Connected to MQTT broker
|
||||
I (xxxxx) ha_mqtt: 📤 Publishing discovery to: homeassistant/sensor/wand_spell/config
|
||||
I (xxxxx) ha_mqtt: 📤 Discovery payload: {"name":"Magic Wand Spell",...}
|
||||
I (xxxxx) ha_mqtt: Spell discovery msg_id: 1
|
||||
I (xxxxx) ha_mqtt: 📤 Publishing discovery to: homeassistant/sensor/wand_battery/config
|
||||
I (xxxxx) ha_mqtt: 📤 Discovery payload: {"name":"Wand Battery",...}
|
||||
I (xxxxx) ha_mqtt: Battery discovery msg_id: 2
|
||||
I (xxxxx) ha_mqtt: 📥 Subscribed to wand/test for connectivity verification [msg_id=3]
|
||||
I (xxxxx) ha_mqtt: ✓ MQTT subscription successful [msg_id=3]
|
||||
```
|
||||
|
||||
### Step 3: Test Bidirectional Communication
|
||||
In Home Assistant, go to **Developer Tools** → **MQTT**:
|
||||
|
||||
1. **Publish a test message:**
|
||||
- Topic: `wand/test`
|
||||
- Payload: `hello`
|
||||
- Click "PUBLISH"
|
||||
|
||||
2. **Check ESP32 serial output:**
|
||||
```
|
||||
I (xxxxx) ha_mqtt: 📥 MQTT data received on topic: wand/test
|
||||
I (xxxxx) ha_mqtt: Payload: hello
|
||||
```
|
||||
|
||||
If you see this, MQTT is working bidirectionally! ✓
|
||||
|
||||
### Step 4: Cast a Spell
|
||||
Wave your wand and cast a spell. You should see:
|
||||
```
|
||||
I (xxxxx) main: 🎯 Spell detected in callback - processing...
|
||||
I (xxxxx) main: → Checking MQTT connection (isConnected=1)
|
||||
I (xxxxx) main: → Calling mqttClient.publishSpell()
|
||||
I (xxxxx) ha_mqtt: publishSpell() called: spell_name='Incendio', confidence=0.994
|
||||
I (xxxxx) ha_mqtt: Connection status: connected=1, mqtt_client=0x...
|
||||
I (xxxxx) ha_mqtt: 📤 Publishing to topic 'wand/spell'
|
||||
I (xxxxx) ha_mqtt: 📤 Payload: {"spell":"Incendio","confidence":0.994}
|
||||
I (xxxxx) ha_mqtt: 📤 QoS: 1, Retain: false
|
||||
I (xxxxx) ha_mqtt: ✓ Published spell: Incendio (99.4%) [msg_id=XXX]
|
||||
I (xxxxx) ha_mqtt: ✓ MQTT message published successfully [msg_id=XXX]
|
||||
```
|
||||
|
||||
The **✓ MQTT message published successfully** line is critical - it means the broker acknowledged receipt!
|
||||
|
||||
### Step 5: Listen in Home Assistant
|
||||
In Home Assistant **Developer Tools** → **MQTT**:
|
||||
- Topic: `wand/spell`
|
||||
- Click "START LISTENING"
|
||||
|
||||
Cast a spell - you should immediately see:
|
||||
```json
|
||||
{"spell":"Incendio","confidence":0.994}
|
||||
```
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Issue 1: No "MQTT message published successfully" Event
|
||||
**Symptom:** You see "Published spell" but no "✓ MQTT message published successfully"
|
||||
|
||||
**Causes:**
|
||||
- QoS 1 requires broker acknowledgment
|
||||
- Broker might not be acknowledging messages
|
||||
- Check Home Assistant MQTT broker logs
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# In Home Assistant container or OS
|
||||
docker logs homeassistant 2>&1 | grep -i mqtt
|
||||
# or
|
||||
journalctl -u hassio-supervisor -f | grep -i mqtt
|
||||
```
|
||||
|
||||
### Issue 2: Discovery Not Working
|
||||
**Symptom:** No "Magic Wand Gateway" device appears in Home Assistant
|
||||
|
||||
**Check:**
|
||||
1. Home Assistant MQTT integration is enabled
|
||||
2. Discovery is enabled in MQTT integration settings
|
||||
3. ESP32 logs show discovery messages published (msg_id > 0)
|
||||
|
||||
**Manual verification:**
|
||||
```bash
|
||||
# Subscribe to discovery topics in HA Developer Tools → MQTT
|
||||
Topic: homeassistant/sensor/wand_spell/config
|
||||
```
|
||||
|
||||
You should see the discovery payload appear immediately after ESP32 connects.
|
||||
|
||||
### Issue 3: Messages Not Appearing in HA
|
||||
**Symptom:** ESP32 shows "published successfully" but HA sees nothing
|
||||
|
||||
**Debug steps:**
|
||||
|
||||
1. **Check MQTT broker is running:**
|
||||
```bash
|
||||
# From Linux machine on same network
|
||||
nc -zv 192.168.2.29 1883
|
||||
```
|
||||
|
||||
2. **Use mosquitto_sub to listen:**
|
||||
```bash
|
||||
mosquitto_sub -h 192.168.2.29 -p 1883 -u magicwandesp32 -P wlqJQtAfLvcYK5 -t 'wand/#' -v
|
||||
```
|
||||
This bypasses Home Assistant and listens directly to broker.
|
||||
|
||||
3. **Check Home Assistant MQTT integration:**
|
||||
- Settings → Devices & Services → MQTT
|
||||
- Should show "Connected"
|
||||
- Check broker address matches: `192.168.2.29`
|
||||
|
||||
4. **Check MQTT broker logs:**
|
||||
If using Mosquitto add-on in HA:
|
||||
- Settings → Add-ons → Mosquitto broker → Log tab
|
||||
|
||||
### Issue 4: Wrong Broker Configuration
|
||||
**Check your NVS settings match:**
|
||||
```
|
||||
MQTT broker: mqtt://192.168.2.29:1883 (or just "192.168.2.29" - code adds mqtt:// prefix)
|
||||
Username: magicwandesp32
|
||||
Password: wlqJQtAfLvcYK5
|
||||
```
|
||||
|
||||
Verify in ESP32 logs:
|
||||
```
|
||||
I (xxxxx) main: MQTT Configuration:
|
||||
I (xxxxx) main: Broker: mqtt://192.168.2.29:1883
|
||||
I (xxxxx) main: Username: magicwandesp32
|
||||
```
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
After these changes, you should see:
|
||||
|
||||
1. ✅ MQTT connects successfully
|
||||
2. ✅ Discovery messages published (msg_id > 0)
|
||||
3. ✅ Subscription to wand/test successful
|
||||
4. ✅ Test message from HA appears in ESP32 logs
|
||||
5. ✅ Spell published with positive msg_id
|
||||
6. ✅ "MQTT message published successfully" confirmation
|
||||
7. ✅ Spell appears in HA when listening to wand/spell
|
||||
|
||||
## Home Assistant Configuration
|
||||
|
||||
After successful connection, check for the auto-discovered entity:
|
||||
|
||||
**Settings** → **Devices & Services** → **MQTT** → Look for:
|
||||
- Device: "Magic Wand Gateway"
|
||||
- Entity: `sensor.magic_wand_spell`
|
||||
- Entity: `sensor.wand_battery`
|
||||
|
||||
Create a simple automation to test:
|
||||
```yaml
|
||||
alias: Test Wand MQTT
|
||||
trigger:
|
||||
- platform: mqtt
|
||||
topic: wand/spell
|
||||
action:
|
||||
- service: notify.persistent_notification
|
||||
data:
|
||||
title: "🪄 Wand Spell Detected!"
|
||||
message: "{{ trigger.payload_json.spell }} ({{ (trigger.payload_json.confidence * 100) | round }}%)"
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
If all tests pass but you still don't see data in Home Assistant:
|
||||
1. Check Home Assistant logs for MQTT errors
|
||||
2. Verify MQTT integration configuration in HA
|
||||
3. Try restarting Home Assistant after first discovery message
|
||||
4. Check if HA MQTT discovery is enabled:
|
||||
```yaml
|
||||
# In configuration.yaml
|
||||
mqtt:
|
||||
discovery: true
|
||||
```
|
||||
@@ -0,0 +1,154 @@
|
||||
# Home Assistant Automation Examples for Magic Wand
|
||||
# Add these to your configuration.yaml or create separate automation files
|
||||
|
||||
# Example 1: Lumos - Turn on lights
|
||||
automation:
|
||||
- alias: "Wand: Lumos - Lights On"
|
||||
trigger:
|
||||
- platform: mqtt
|
||||
topic: "wand/spell"
|
||||
condition:
|
||||
- condition: template
|
||||
value_template: "{{ trigger.payload_json.spell == 'Lumos' }}"
|
||||
- condition: template
|
||||
value_template: "{{ trigger.payload_json.confidence > 0.7 }}"
|
||||
action:
|
||||
- service: light.turn_on
|
||||
target:
|
||||
entity_id: light.living_room # Change to your light entity
|
||||
data:
|
||||
brightness: 255
|
||||
|
||||
# Example 2: Nox - Turn off lights
|
||||
- alias: "Wand: Nox - Lights Off"
|
||||
trigger:
|
||||
- platform: mqtt
|
||||
topic: "wand/spell"
|
||||
condition:
|
||||
- condition: template
|
||||
value_template: "{{ trigger.payload_json.spell == 'Nox' }}"
|
||||
- condition: template
|
||||
value_template: "{{ trigger.payload_json.confidence > 0.7 }}"
|
||||
action:
|
||||
- service: light.turn_off
|
||||
target:
|
||||
entity_id: light.living_room
|
||||
|
||||
# Example 3: Incendio - Red lights
|
||||
- alias: "Wand: Incendio - Red Fire"
|
||||
trigger:
|
||||
- platform: mqtt
|
||||
topic: "wand/spell"
|
||||
condition:
|
||||
- condition: template
|
||||
value_template: "{{ trigger.payload_json.spell == 'Incendio' }}"
|
||||
- condition: template
|
||||
value_template: "{{ trigger.payload_json.confidence > 0.7 }}"
|
||||
action:
|
||||
- service: light.turn_on
|
||||
target:
|
||||
entity_id: light.living_room
|
||||
data:
|
||||
brightness: 255
|
||||
rgb_color: [255, 0, 0] # Red
|
||||
- service: notify.persistent_notification
|
||||
data:
|
||||
message: "🔥 Incendio cast with {{ (trigger.payload_json.confidence * 100) | round }}% confidence!"
|
||||
|
||||
# Example 4: Aguamenti - Blue water effect
|
||||
- alias: "Wand: Aguamenti - Blue Water"
|
||||
trigger:
|
||||
- platform: mqtt
|
||||
topic: "wand/spell"
|
||||
condition:
|
||||
- condition: template
|
||||
value_template: "{{ trigger.payload_json.spell == 'Aguamenti' }}"
|
||||
action:
|
||||
- service: light.turn_on
|
||||
target:
|
||||
entity_id: light.living_room
|
||||
data:
|
||||
brightness: 200
|
||||
rgb_color: [0, 100, 255] # Blue
|
||||
|
||||
# Example 5: Alohomora - Unlock door
|
||||
- alias: "Wand: Alohomora - Unlock"
|
||||
trigger:
|
||||
- platform: mqtt
|
||||
topic: "wand/spell"
|
||||
condition:
|
||||
- condition: template
|
||||
value_template: "{{ trigger.payload_json.spell == 'Alohomora' }}"
|
||||
action:
|
||||
- service: lock.unlock
|
||||
target:
|
||||
entity_id: lock.front_door # Change to your lock entity
|
||||
- service: notify.mobile_app
|
||||
data:
|
||||
message: "Door unlocked by magic wand!"
|
||||
|
||||
# Example 6: Protego - Activate security
|
||||
- alias: "Wand: Protego - Arm Security"
|
||||
trigger:
|
||||
- platform: mqtt
|
||||
topic: "wand/spell"
|
||||
condition:
|
||||
- condition: template
|
||||
value_template: "{{ trigger.payload_json.spell == 'Protego' }}"
|
||||
action:
|
||||
- service: alarm_control_panel.alarm_arm_home
|
||||
target:
|
||||
entity_id: alarm_control_panel.home_alarm
|
||||
- service: light.turn_on
|
||||
target:
|
||||
entity_id: light.living_room
|
||||
data:
|
||||
brightness: 100
|
||||
rgb_color: [0, 0, 255] # Blue shield
|
||||
|
||||
# Example 7: Low battery notification
|
||||
- alias: "Wand: Low Battery Alert"
|
||||
trigger:
|
||||
- platform: mqtt
|
||||
topic: "wand/battery"
|
||||
condition:
|
||||
- condition: template
|
||||
value_template: "{{ trigger.payload_json.level | int < 20 }}"
|
||||
action:
|
||||
- service: notify.persistent_notification
|
||||
data:
|
||||
title: "⚡ Wand Battery Low"
|
||||
message: "Magic wand battery at {{ trigger.payload_json.level }}%"
|
||||
|
||||
# Sensor to track last spell (alternative to event entity)
|
||||
sensor:
|
||||
- platform: mqtt
|
||||
name: "Wand Last Spell"
|
||||
state_topic: "wand/spell"
|
||||
value_template: "{{ value_json.spell }}"
|
||||
json_attributes_topic: "wand/spell"
|
||||
json_attributes_template: "{{ {'confidence': value_json.confidence | float | round(3)} | tojson }}"
|
||||
|
||||
- platform: mqtt
|
||||
name: "Wand Battery Level"
|
||||
state_topic: "wand/battery"
|
||||
value_template: "{{ value_json.level }}"
|
||||
unit_of_measurement: "%"
|
||||
device_class: battery
|
||||
|
||||
# Script: All available spells list
|
||||
script:
|
||||
cast_random_spell:
|
||||
alias: "Cast Random Spell Effect"
|
||||
sequence:
|
||||
- choose:
|
||||
- conditions: "{{ states('sensor.wand_last_spell') == 'Lumos' }}"
|
||||
sequence:
|
||||
- service: light.turn_on
|
||||
target:
|
||||
area_id: living_room
|
||||
- conditions: "{{ states('sensor.wand_last_spell') == 'Nox' }}"
|
||||
sequence:
|
||||
- service: light.turn_off
|
||||
target:
|
||||
area_id: living_room
|
||||
@@ -163,6 +163,7 @@ public:
|
||||
const char *getSKU() const { return sku; }
|
||||
const char *getDeviceId() const { return device_id; }
|
||||
const char *getWandType() const { return wand_type; }
|
||||
const char *getWandMacAddress() const;
|
||||
|
||||
// Status
|
||||
bool isStreaming() const { return imuStreaming; }
|
||||
|
||||
@@ -11,6 +11,8 @@ class HAMqttClient
|
||||
private:
|
||||
void *mqtt_client; // esp_mqtt_client_handle_t
|
||||
bool connected;
|
||||
char chip_id[16]; // Store chip ID for topic paths
|
||||
void (*on_connected_callback)(); // Callback when MQTT connects
|
||||
|
||||
// MQTT event handler
|
||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data);
|
||||
@@ -31,8 +33,19 @@ public:
|
||||
// Publish battery level to Home Assistant
|
||||
bool publishBattery(uint8_t level);
|
||||
|
||||
// Publish wand information (firmware, serial, etc)
|
||||
bool publishWandInfo(const char *firmware_version, const char *serial_number,
|
||||
const char *sku, const char *device_id, const char *wand_type,
|
||||
const char *wand_mac);
|
||||
|
||||
// Publish wand disconnected status
|
||||
bool publishWandDisconnected();
|
||||
|
||||
// Check if connected to MQTT broker
|
||||
bool isConnected() const { return connected; }
|
||||
|
||||
// Set callback for when MQTT connects
|
||||
void onConnected(void (*callback)()) { on_connected_callback = callback; }
|
||||
};
|
||||
|
||||
#endif // HA_MQTT_H
|
||||
|
||||
+10
-1
@@ -1017,7 +1017,7 @@ void WandBLEClient::updateAHRS(const IMUSample &sample)
|
||||
dy = usbHID.getGamepadInvertY() ? -dy : dy;
|
||||
}
|
||||
#else
|
||||
dy = -dy; // Default: inverted
|
||||
dy = -dy; // Default: inverted
|
||||
#endif
|
||||
accum_dx += dx;
|
||||
accum_dy += dy;
|
||||
@@ -1137,6 +1137,15 @@ bool WandBLEClient::requestWandInfo()
|
||||
return success;
|
||||
}
|
||||
|
||||
const char *WandBLEClient::getWandMacAddress() const
|
||||
{
|
||||
static char mac_str[18]; // "XX:XX:XX:XX:XX:XX" + null terminator
|
||||
snprintf(mac_str, sizeof(mac_str), "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
peer_addr.val[5], peer_addr.val[4], peer_addr.val[3],
|
||||
peer_addr.val[2], peer_addr.val[1], peer_addr.val[0]);
|
||||
return mac_str;
|
||||
}
|
||||
|
||||
void WandBLEClient::processFirmwareVersion(const uint8_t *data, size_t length)
|
||||
{
|
||||
// Response format: [opcode][version_string...]
|
||||
|
||||
+423
-36
@@ -2,13 +2,18 @@
|
||||
#include "config.h"
|
||||
#include "esp_log.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_idf_version.h"
|
||||
#include "esp_mac.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define FIRMWARE_VERSION "1.0.0"
|
||||
|
||||
static const char *TAG = "ha_mqtt";
|
||||
|
||||
HAMqttClient::HAMqttClient()
|
||||
: mqtt_client(nullptr), connected(false)
|
||||
: mqtt_client(nullptr), connected(false), on_connected_callback(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -30,37 +35,259 @@ void HAMqttClient::mqtt_event_handler(void *handler_args, esp_event_base_t base,
|
||||
|
||||
// Publish Home Assistant MQTT discovery configuration
|
||||
{
|
||||
// Discovery topic: homeassistant/event/wand/config
|
||||
const char *discovery_topic = "homeassistant/event/wand_spell/config";
|
||||
char config_json[512];
|
||||
snprintf(config_json, sizeof(config_json),
|
||||
"{\"name\":\"Magic Wand Spell\","
|
||||
"\"state_topic\":\"wand/spell\","
|
||||
"\"value_template\":\"{{ value_json.spell }}\","
|
||||
"\"json_attributes_topic\":\"wand/spell\","
|
||||
"\"device\":{\"identifiers\":[\"esp32_wand\"],"
|
||||
"\"name\":\"Magic Wand Gateway\","
|
||||
"\"manufacturer\":\"DIY\","
|
||||
"\"model\":\"ESP32 Wand Gateway\"}}");
|
||||
// Get unique chip ID for this ESP32
|
||||
uint8_t mac[6];
|
||||
esp_read_mac(mac, ESP_MAC_WIFI_STA);
|
||||
char chip_id[16];
|
||||
snprintf(chip_id, sizeof(chip_id), "%02X%02X%02X%02X%02X%02X",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
|
||||
esp_mqtt_client_publish((esp_mqtt_client_handle_t)client->mqtt_client,
|
||||
discovery_topic, config_json, 0, 1, true);
|
||||
// Store chip_id in class for later use
|
||||
strncpy(client->chip_id, chip_id, sizeof(client->chip_id) - 1);
|
||||
client->chip_id[sizeof(client->chip_id) - 1] = '\0';
|
||||
|
||||
// Get ESP32 IP address
|
||||
char ip_str[16] = "unknown";
|
||||
esp_netif_ip_info_t ip_info;
|
||||
esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
|
||||
if (netif && esp_netif_get_ip_info(netif, &ip_info) == ESP_OK)
|
||||
{
|
||||
snprintf(ip_str, sizeof(ip_str), IPSTR, IP2STR(&ip_info.ip));
|
||||
}
|
||||
|
||||
// Build ESP-IDF version string
|
||||
char idf_version[32];
|
||||
snprintf(idf_version, sizeof(idf_version), "v%d.%d.%d",
|
||||
ESP_IDF_VERSION_MAJOR, ESP_IDF_VERSION_MINOR, ESP_IDF_VERSION_PATCH);
|
||||
|
||||
ESP_LOGI(TAG, "Device Chip ID: %s", chip_id);
|
||||
ESP_LOGI(TAG, "Device IP: %s", ip_str);
|
||||
ESP_LOGI(TAG, "Firmware: %s (ESP-IDF %s)", FIRMWARE_VERSION, idf_version);
|
||||
|
||||
// Reusable buffer for all discovery payloads (reduce stack usage)
|
||||
char *discovery_buffer = (char *)malloc(1200);
|
||||
if (!discovery_buffer)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for discovery messages");
|
||||
break;
|
||||
}
|
||||
|
||||
// Common device info JSON block (used by all sensors)
|
||||
char device_info[400];
|
||||
snprintf(device_info, sizeof(device_info),
|
||||
"\"device\":{"
|
||||
"\"identifiers\":[\"wand_%s\"],"
|
||||
"\"name\":\"Wand Gateway %s\","
|
||||
"\"manufacturer\":\"DIY\","
|
||||
"\"model\":\"ESP32-S3\","
|
||||
"\"sw_version\":\"%s\","
|
||||
"\"hw_version\":\"ESP-IDF %s\","
|
||||
"\"configuration_url\":\"http://%s\","
|
||||
"\"connections\":[[\"mac\",\"%s\"]]"
|
||||
"}",
|
||||
chip_id, chip_id, FIRMWARE_VERSION, idf_version, ip_str, chip_id);
|
||||
|
||||
// Spell sensor discovery - tracks last detected spell
|
||||
char discovery_topic[128];
|
||||
snprintf(discovery_topic, sizeof(discovery_topic), "homeassistant/sensor/wand_%s_spell/config", chip_id);
|
||||
snprintf(discovery_buffer, 1200,
|
||||
"{"
|
||||
"\"name\":\"Last Spell Cast\","
|
||||
"\"unique_id\":\"wand_%s_spell\","
|
||||
"\"object_id\":\"wand_%s_spell\","
|
||||
"\"state_topic\":\"wand/%s/spell\","
|
||||
"\"value_template\":\"{{ value_json.spell }}\","
|
||||
"\"json_attributes_topic\":\"wand/%s/spell\","
|
||||
"\"icon\":\"mdi:magic-staff\","
|
||||
"%s"
|
||||
"}",
|
||||
chip_id, chip_id, chip_id, chip_id, device_info);
|
||||
|
||||
ESP_LOGI(TAG, "📤 Publishing discovery to: %s", discovery_topic);
|
||||
ESP_LOGD(TAG, "📤 Discovery payload: %s", discovery_buffer);
|
||||
int msg_id1 = esp_mqtt_client_publish((esp_mqtt_client_handle_t)client->mqtt_client,
|
||||
discovery_topic, discovery_buffer, 0, 1, true);
|
||||
ESP_LOGI(TAG, " Spell discovery msg_id: %d", msg_id1);
|
||||
|
||||
// Battery sensor discovery
|
||||
const char *battery_discovery = "homeassistant/sensor/wand_battery/config";
|
||||
char battery_json[512];
|
||||
snprintf(battery_json, sizeof(battery_json),
|
||||
"{\"name\":\"Wand Battery\","
|
||||
"\"state_topic\":\"wand/battery\","
|
||||
snprintf(discovery_topic, sizeof(discovery_topic), "homeassistant/sensor/wand_%s_battery/config", chip_id);
|
||||
snprintf(discovery_buffer, 1200,
|
||||
"{"
|
||||
"\"name\":\"Wand Battery\","
|
||||
"\"unique_id\":\"wand_%s_battery\","
|
||||
"\"object_id\":\"wand_%s_battery\","
|
||||
"\"state_topic\":\"wand/%s/battery\","
|
||||
"\"unit_of_measurement\":\"%%\","
|
||||
"\"device_class\":\"battery\","
|
||||
"\"state_class\":\"measurement\","
|
||||
"\"value_template\":\"{{ value_json.level }}\","
|
||||
"\"device\":{\"identifiers\":[\"esp32_wand\"]}}");
|
||||
"\"icon\":\"mdi:battery\","
|
||||
"%s"
|
||||
"}",
|
||||
chip_id, chip_id, chip_id, device_info);
|
||||
|
||||
esp_mqtt_client_publish((esp_mqtt_client_handle_t)client->mqtt_client,
|
||||
battery_discovery, battery_json, 0, 1, true);
|
||||
ESP_LOGI(TAG, "📤 Publishing discovery to: %s", discovery_topic);
|
||||
ESP_LOGD(TAG, "📤 Discovery payload: %s", discovery_buffer);
|
||||
int msg_id2 = esp_mqtt_client_publish((esp_mqtt_client_handle_t)client->mqtt_client,
|
||||
discovery_topic, discovery_buffer, 0, 1, true);
|
||||
ESP_LOGI(TAG, " Battery discovery msg_id: %d", msg_id2);
|
||||
|
||||
ESP_LOGI(TAG, "Published Home Assistant discovery config");
|
||||
// Spell confidence sensor discovery
|
||||
snprintf(discovery_topic, sizeof(discovery_topic), "homeassistant/sensor/wand_%s_confidence/config", chip_id);
|
||||
snprintf(discovery_buffer, 1200,
|
||||
"{"
|
||||
"\"name\":\"Spell Confidence\","
|
||||
"\"unique_id\":\"wand_%s_confidence\","
|
||||
"\"object_id\":\"wand_%s_confidence\","
|
||||
"\"state_topic\":\"wand/%s/spell\","
|
||||
"\"unit_of_measurement\":\"%%\","
|
||||
"\"value_template\":\"{{ (value_json.confidence * 100) | round(1) }}\","
|
||||
"\"icon\":\"mdi:gauge\","
|
||||
"\"state_class\":\"measurement\","
|
||||
"%s"
|
||||
"}",
|
||||
chip_id, chip_id, chip_id, device_info);
|
||||
|
||||
ESP_LOGI(TAG, "📤 Publishing discovery to: %s", discovery_topic);
|
||||
ESP_LOGD(TAG, "📤 Discovery payload: %s", discovery_buffer);
|
||||
int msg_id3 = esp_mqtt_client_publish((esp_mqtt_client_handle_t)client->mqtt_client,
|
||||
discovery_topic, discovery_buffer, 0, 1, true);
|
||||
ESP_LOGI(TAG, " Confidence discovery msg_id: %d", msg_id3);
|
||||
|
||||
// Wand connection status sensor
|
||||
snprintf(discovery_topic, sizeof(discovery_topic), "homeassistant/binary_sensor/wand_%s_connected/config", chip_id);
|
||||
snprintf(discovery_buffer, 1200,
|
||||
"{"
|
||||
"\"name\":\"Wand Connected\","
|
||||
"\"unique_id\":\"wand_%s_connected\","
|
||||
"\"object_id\":\"wand_%s_connected\","
|
||||
"\"state_topic\":\"wand/%s/info\","
|
||||
"\"value_template\":\"{{ value_json.connected }}\","
|
||||
"\"payload_on\":\"True\","
|
||||
"\"payload_off\":\"False\","
|
||||
"\"device_class\":\"connectivity\","
|
||||
"\"icon\":\"mdi:magic-staff\","
|
||||
"%s"
|
||||
"}",
|
||||
chip_id, chip_id, chip_id, device_info);
|
||||
|
||||
ESP_LOGI(TAG, "📤 Publishing discovery to: %s", discovery_topic);
|
||||
int msg_id4 = esp_mqtt_client_publish((esp_mqtt_client_handle_t)client->mqtt_client,
|
||||
discovery_topic, discovery_buffer, 0, 1, true);
|
||||
ESP_LOGI(TAG, " Wand status discovery msg_id: %d", msg_id4);
|
||||
|
||||
// Wand firmware version sensor
|
||||
snprintf(discovery_topic, sizeof(discovery_topic), "homeassistant/sensor/wand_%s_firmware/config", chip_id);
|
||||
snprintf(discovery_buffer, 1200,
|
||||
"{"
|
||||
"\"name\":\"Wand Firmware\","
|
||||
"\"unique_id\":\"wand_%s_firmware\","
|
||||
"\"object_id\":\"wand_%s_firmware\","
|
||||
"\"state_topic\":\"wand/%s/info\","
|
||||
"\"value_template\":\"{{ value_json.firmware }}\","
|
||||
"\"icon\":\"mdi:chip\","
|
||||
"\"entity_category\":\"diagnostic\","
|
||||
"%s"
|
||||
"}",
|
||||
chip_id, chip_id, chip_id, device_info);
|
||||
|
||||
ESP_LOGI(TAG, "📤 Publishing discovery to: %s", discovery_topic);
|
||||
int msg_id5 = esp_mqtt_client_publish((esp_mqtt_client_handle_t)client->mqtt_client,
|
||||
discovery_topic, discovery_buffer, 0, 1, true);
|
||||
ESP_LOGI(TAG, " Wand firmware discovery msg_id: %d", msg_id5);
|
||||
|
||||
// Wand serial number sensor
|
||||
snprintf(discovery_topic, sizeof(discovery_topic), "homeassistant/sensor/wand_%s_serial/config", chip_id);
|
||||
snprintf(discovery_buffer, 1200,
|
||||
"{"
|
||||
"\"name\":\"Wand Serial Number\","
|
||||
"\"unique_id\":\"wand_%s_serial\","
|
||||
"\"object_id\":\"wand_%s_serial\","
|
||||
"\"state_topic\":\"wand/%s/info\","
|
||||
"\"value_template\":\"{{ value_json.serial }}\","
|
||||
"\"icon\":\"mdi:identifier\","
|
||||
"\"entity_category\":\"diagnostic\","
|
||||
"%s"
|
||||
"}",
|
||||
chip_id, chip_id, chip_id, device_info);
|
||||
|
||||
ESP_LOGI(TAG, "📤 Publishing discovery to: %s", discovery_topic);
|
||||
int msg_id6 = esp_mqtt_client_publish((esp_mqtt_client_handle_t)client->mqtt_client,
|
||||
discovery_topic, discovery_buffer, 0, 1, true);
|
||||
ESP_LOGI(TAG, " Wand serial discovery msg_id: %d", msg_id6);
|
||||
|
||||
// Wand MAC address sensor
|
||||
snprintf(discovery_topic, sizeof(discovery_topic), "homeassistant/sensor/wand_%s_mac/config", chip_id);
|
||||
snprintf(discovery_buffer, 1200,
|
||||
"{"
|
||||
"\"name\":\"Wand MAC Address\","
|
||||
"\"unique_id\":\"wand_%s_mac\","
|
||||
"\"object_id\":\"wand_%s_mac\","
|
||||
"\"state_topic\":\"wand/%s/info\","
|
||||
"\"value_template\":\"{{ value_json.wand_mac }}\","
|
||||
"\"icon\":\"mdi:bluetooth\","
|
||||
"\"entity_category\":\"diagnostic\","
|
||||
"%s"
|
||||
"}",
|
||||
chip_id, chip_id, chip_id, device_info);
|
||||
|
||||
ESP_LOGI(TAG, "📤 Publishing discovery to: %s", discovery_topic);
|
||||
int msg_id7 = esp_mqtt_client_publish((esp_mqtt_client_handle_t)client->mqtt_client,
|
||||
discovery_topic, discovery_buffer, 0, 1, true);
|
||||
ESP_LOGI(TAG, " Wand MAC discovery msg_id: %d", msg_id7);
|
||||
|
||||
// Free the discovery buffer
|
||||
free(discovery_buffer);
|
||||
|
||||
ESP_LOGI(TAG, "✓ Published Home Assistant discovery config (7 sensors + 1 binary_sensor)");
|
||||
|
||||
// Publish initial state for wand info (no wand connected yet)
|
||||
char wand_info_topic[64];
|
||||
snprintf(wand_info_topic, sizeof(wand_info_topic), "wand/%s/info", chip_id);
|
||||
const char *initial_wand_info = "{\"firmware\":\"unknown\",\"serial\":\"unknown\",\"sku\":\"unknown\",\"device_id\":\"unknown\",\"wand_type\":\"unknown\",\"wand_mac\":\"unknown\",\"connected\":false}";
|
||||
int init_msg_id = esp_mqtt_client_publish((esp_mqtt_client_handle_t)client->mqtt_client,
|
||||
wand_info_topic,
|
||||
initial_wand_info,
|
||||
strlen(initial_wand_info),
|
||||
1,
|
||||
true); // retain=true
|
||||
ESP_LOGI(TAG, "📤 Published initial wand state (no wand connected) [msg_id=%d]", init_msg_id);
|
||||
|
||||
// Publish initial battery state (unavailable until wand connects)
|
||||
char battery_topic[64];
|
||||
snprintf(battery_topic, sizeof(battery_topic), "wand/%s/battery", chip_id);
|
||||
const char *initial_battery = "{\"level\":0}";
|
||||
int battery_msg_id = esp_mqtt_client_publish((esp_mqtt_client_handle_t)client->mqtt_client,
|
||||
battery_topic,
|
||||
initial_battery,
|
||||
strlen(initial_battery),
|
||||
1,
|
||||
true); // retain=true
|
||||
ESP_LOGI(TAG, "📤 Published initial battery state [msg_id=%d]", battery_msg_id);
|
||||
|
||||
// Publish initial spell state (no spell detected yet)
|
||||
char spell_topic[64];
|
||||
snprintf(spell_topic, sizeof(spell_topic), "wand/%s/spell", chip_id);
|
||||
const char *initial_spell = "{\"spell\":\"No spell yet\",\"confidence\":0.0}";
|
||||
int spell_msg_id = esp_mqtt_client_publish((esp_mqtt_client_handle_t)client->mqtt_client,
|
||||
spell_topic,
|
||||
initial_spell,
|
||||
strlen(initial_spell),
|
||||
1,
|
||||
true); // retain=true
|
||||
ESP_LOGI(TAG, "📤 Published initial spell state [msg_id=%d]", spell_msg_id);
|
||||
|
||||
// Subscribe to a test topic to verify bidirectional MQTT connectivity
|
||||
int sub_id = esp_mqtt_client_subscribe((esp_mqtt_client_handle_t)client->mqtt_client,
|
||||
"wand/test", 0);
|
||||
ESP_LOGI(TAG, "📥 Subscribed to wand/test for connectivity verification [msg_id=%d]", sub_id);
|
||||
|
||||
// Call onConnected callback if registered
|
||||
if (client->on_connected_callback)
|
||||
{
|
||||
ESP_LOGI(TAG, "Calling MQTT connected callback...");
|
||||
client->on_connected_callback();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -69,6 +296,19 @@ void HAMqttClient::mqtt_event_handler(void *handler_args, esp_event_base_t base,
|
||||
client->connected = false;
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_PUBLISHED:
|
||||
ESP_LOGI(TAG, "✓ MQTT message published successfully [msg_id=%d]", event->msg_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBSCRIBED:
|
||||
ESP_LOGI(TAG, "✓ MQTT subscription successful [msg_id=%d]", event->msg_id);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_DATA:
|
||||
ESP_LOGI(TAG, "📥 MQTT data received on topic: %.*s", event->topic_len, event->topic);
|
||||
ESP_LOGI(TAG, " Payload: %.*s", event->data_len, event->data);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_ERROR:
|
||||
ESP_LOGE(TAG, "MQTT error occurred");
|
||||
if (event->error_handle && event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT)
|
||||
@@ -80,6 +320,7 @@ void HAMqttClient::mqtt_event_handler(void *handler_args, esp_event_base_t base,
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGD(TAG, "MQTT event: %d", event_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -141,8 +382,26 @@ void HAMqttClient::stop()
|
||||
|
||||
bool HAMqttClient::publishSpell(const char *spell_name, float confidence)
|
||||
{
|
||||
if (!connected || !mqtt_client || !spell_name)
|
||||
ESP_LOGI(TAG, "publishSpell() called: spell_name='%s', confidence=%.3f",
|
||||
spell_name ? spell_name : "(null)", confidence);
|
||||
ESP_LOGI(TAG, " Connection status: connected=%d, mqtt_client=%p",
|
||||
connected, mqtt_client);
|
||||
|
||||
if (!connected)
|
||||
{
|
||||
ESP_LOGW(TAG, " ❌ Cannot publish: Not connected to MQTT broker");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mqtt_client)
|
||||
{
|
||||
ESP_LOGW(TAG, " ❌ Cannot publish: MQTT client is NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!spell_name)
|
||||
{
|
||||
ESP_LOGW(TAG, " ❌ Cannot publish: spell_name is NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -152,38 +411,63 @@ bool HAMqttClient::publishSpell(const char *spell_name, float confidence)
|
||||
"{\"spell\":\"%s\",\"confidence\":%.3f}",
|
||||
spell_name, confidence);
|
||||
|
||||
char topic[64];
|
||||
snprintf(topic, sizeof(topic), "wand/%s/spell", chip_id);
|
||||
|
||||
ESP_LOGI(TAG, " 📤 Publishing to topic '%s'", topic);
|
||||
ESP_LOGI(TAG, " 📤 Payload: %s", json);
|
||||
ESP_LOGI(TAG, " 📤 QoS: 1, Retain: false");
|
||||
|
||||
int msg_id = esp_mqtt_client_publish((esp_mqtt_client_handle_t)mqtt_client,
|
||||
MQTT_TOPIC_SPELL,
|
||||
topic,
|
||||
json,
|
||||
0, // length (0 = use strlen)
|
||||
1, // QoS 1
|
||||
false); // retain
|
||||
strlen(json), // Explicit length instead of 0
|
||||
1, // QoS 1
|
||||
false); // retain
|
||||
|
||||
if (msg_id >= 0)
|
||||
{
|
||||
ESP_LOGI(TAG, "Published spell: %s (%.1f%%) [msg_id=%d]",
|
||||
ESP_LOGI(TAG, " ✓ Published spell: %s (%.1f%%) [msg_id=%d]",
|
||||
spell_name, confidence * 100.0f, msg_id);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "Failed to publish spell");
|
||||
ESP_LOGE(TAG, " ❌ Failed to publish spell [msg_id=%d]", msg_id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool HAMqttClient::publishBattery(uint8_t level)
|
||||
{
|
||||
if (!connected || !mqtt_client)
|
||||
ESP_LOGI(TAG, "publishBattery() called: level=%d%%", level);
|
||||
ESP_LOGI(TAG, " Connection status: connected=%d, mqtt_client=%p",
|
||||
connected, mqtt_client);
|
||||
|
||||
if (!connected)
|
||||
{
|
||||
ESP_LOGW(TAG, " ❌ Cannot publish: Not connected to MQTT broker");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mqtt_client)
|
||||
{
|
||||
ESP_LOGW(TAG, " ❌ Cannot publish: MQTT client is NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
char json[64];
|
||||
snprintf(json, sizeof(json), "{\"level\":%d}", level);
|
||||
|
||||
char topic[64];
|
||||
snprintf(topic, sizeof(topic), "wand/%s/battery", chip_id);
|
||||
|
||||
ESP_LOGI(TAG, " 📤 Publishing to topic '%s'", topic);
|
||||
ESP_LOGI(TAG, " 📤 Payload: %s", json);
|
||||
ESP_LOGI(TAG, " 📤 QoS: 1, Retain: false");
|
||||
|
||||
int msg_id = esp_mqtt_client_publish((esp_mqtt_client_handle_t)mqtt_client,
|
||||
"wand/battery",
|
||||
topic,
|
||||
json,
|
||||
0,
|
||||
1,
|
||||
@@ -191,9 +475,112 @@ bool HAMqttClient::publishBattery(uint8_t level)
|
||||
|
||||
if (msg_id >= 0)
|
||||
{
|
||||
ESP_LOGD(TAG, "Published battery: %d%% [msg_id=%d]", level, msg_id);
|
||||
ESP_LOGI(TAG, " ✓ Published battery: %d%% [msg_id=%d]", level, msg_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, " ❌ Failed to publish battery [msg_id=%d]", msg_id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool HAMqttClient::publishWandInfo(const char *firmware_version, const char *serial_number,
|
||||
const char *sku, const char *device_id, const char *wand_type,
|
||||
const char *wand_mac)
|
||||
{
|
||||
ESP_LOGI(TAG, "publishWandInfo() called");
|
||||
ESP_LOGI(TAG, " Connection status: connected=%d, mqtt_client=%p",
|
||||
connected, mqtt_client);
|
||||
|
||||
if (!connected || !mqtt_client)
|
||||
{
|
||||
ESP_LOGW(TAG, " ❌ Cannot publish: Not connected to MQTT broker");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build JSON with wand information
|
||||
// Check for empty strings, not just NULL
|
||||
const char *fw = (firmware_version && firmware_version[0]) ? firmware_version : "unknown";
|
||||
const char *sn = (serial_number && serial_number[0]) ? serial_number : "unknown";
|
||||
const char *sk = (sku && sku[0]) ? sku : "unknown";
|
||||
const char *did = (device_id && device_id[0]) ? device_id : "unknown";
|
||||
const char *wt = (wand_type && wand_type[0]) ? wand_type : "unknown";
|
||||
const char *mac = (wand_mac && wand_mac[0]) ? wand_mac : "unknown";
|
||||
|
||||
char json[512];
|
||||
snprintf(json, sizeof(json),
|
||||
"{"
|
||||
"\"firmware\":\"%s\","
|
||||
"\"serial\":\"%s\","
|
||||
"\"sku\":\"%s\","
|
||||
"\"device_id\":\"%s\","
|
||||
"\"wand_type\":\"%s\","
|
||||
"\"wand_mac\":\"%s\","
|
||||
"\"connected\":true"
|
||||
"}",
|
||||
fw, sn, sk, did, wt, mac);
|
||||
|
||||
char topic[64];
|
||||
snprintf(topic, sizeof(topic), "wand/%s/info", chip_id);
|
||||
|
||||
ESP_LOGI(TAG, " 📤 Publishing to topic '%s'", topic);
|
||||
ESP_LOGI(TAG, " 📤 Wand FW: %s, Serial: %s, Type: %s, MAC: %s",
|
||||
fw, sn, wt, mac);
|
||||
ESP_LOGI(TAG, " 📤 Payload: %s", json);
|
||||
|
||||
int msg_id = esp_mqtt_client_publish((esp_mqtt_client_handle_t)mqtt_client,
|
||||
topic,
|
||||
json,
|
||||
strlen(json),
|
||||
1,
|
||||
true); // retain=true so HA always has latest
|
||||
|
||||
if (msg_id >= 0)
|
||||
{
|
||||
ESP_LOGI(TAG, " ✓ Published wand info [msg_id=%d]", msg_id);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, " ❌ Failed to publish wand info [msg_id=%d]", msg_id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool HAMqttClient::publishWandDisconnected()
|
||||
{
|
||||
ESP_LOGI(TAG, "publishWandDisconnected() called");
|
||||
|
||||
if (!connected || !mqtt_client)
|
||||
{
|
||||
ESP_LOGW(TAG, " ⚠ Not connected to MQTT broker (skipping)");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Publish empty wand info with connected=false
|
||||
const char *json = "{\"firmware\":\"unknown\",\"serial\":\"unknown\",\"sku\":\"unknown\",\"device_id\":\"unknown\",\"wand_type\":\"unknown\",\"wand_mac\":\"unknown\",\"connected\":false}";
|
||||
|
||||
char topic[64];
|
||||
snprintf(topic, sizeof(topic), "wand/%s/info", chip_id);
|
||||
|
||||
ESP_LOGI(TAG, " 📤 Publishing disconnection to topic '%s'", topic);
|
||||
|
||||
int msg_id = esp_mqtt_client_publish((esp_mqtt_client_handle_t)mqtt_client,
|
||||
topic,
|
||||
json,
|
||||
strlen(json),
|
||||
1,
|
||||
true); // retain=true
|
||||
|
||||
if (msg_id >= 0)
|
||||
{
|
||||
ESP_LOGI(TAG, " ✓ Published wand disconnection [msg_id=%d]", msg_id);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, " ❌ Failed to publish wand disconnection [msg_id=%d]", msg_id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+126
@@ -189,29 +189,100 @@ void onSpellDetected(const char *spell_name, float confidence)
|
||||
#endif
|
||||
|
||||
#if ENABLE_HOME_ASSISTANT
|
||||
ESP_LOGI(TAG, "🎯 Spell detected in callback - processing...");
|
||||
|
||||
// Broadcast to web clients
|
||||
ESP_LOGI(TAG, " → Broadcasting to web clients");
|
||||
webServer.broadcastSpell(spell_name, confidence);
|
||||
|
||||
// Send to Home Assistant via MQTT (only if connected)
|
||||
ESP_LOGI(TAG, " → Checking MQTT connection (isConnected=%d)", mqttClient.isConnected());
|
||||
if (mqttClient.isConnected())
|
||||
{
|
||||
ESP_LOGI(TAG, " → Calling mqttClient.publishSpell()");
|
||||
mqttClient.publishSpell(spell_name, confidence);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, " ⚠ MQTT not connected - skipping MQTT publish");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Callback when MQTT connects - check if wand is already connected and publish its info
|
||||
void onMQTTConnected()
|
||||
{
|
||||
ESP_LOGI(TAG, "MQTT connected callback triggered");
|
||||
|
||||
// Check if wand is already connected
|
||||
if (wandClient.isConnected())
|
||||
{
|
||||
ESP_LOGI(TAG, "Wand already connected - publishing info to Home Assistant...");
|
||||
|
||||
// Request fresh wand info
|
||||
if (wandClient.requestWandInfo())
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(300));
|
||||
|
||||
mqttClient.publishWandInfo(
|
||||
wandClient.getFirmwareVersion(),
|
||||
wandClient.getSerialNumber(),
|
||||
wandClient.getSKU(),
|
||||
wandClient.getDeviceId(),
|
||||
wandClient.getWandType(),
|
||||
wandClient.getWandMacAddress());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "No wand connected yet");
|
||||
}
|
||||
}
|
||||
|
||||
// Callback when connection state changes
|
||||
void onConnectionChange(bool connected)
|
||||
{
|
||||
if (connected)
|
||||
{
|
||||
ESP_LOGI(TAG, "✓ Connected to wand");
|
||||
|
||||
// Request wand information (firmware, serial, etc.)
|
||||
if (wandClient.requestWandInfo())
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(500)); // Give time for info to be retrieved
|
||||
|
||||
// Publish wand info to Home Assistant
|
||||
#if ENABLE_HOME_ASSISTANT
|
||||
if (mqttClient.isConnected())
|
||||
{
|
||||
ESP_LOGI(TAG, "Publishing wand information to Home Assistant...");
|
||||
mqttClient.publishWandInfo(
|
||||
wandClient.getFirmwareVersion(),
|
||||
wandClient.getSerialNumber(),
|
||||
wandClient.getSKU(),
|
||||
wandClient.getDeviceId(),
|
||||
wandClient.getWandType(),
|
||||
wandClient.getWandMacAddress());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Notify web GUI
|
||||
webServer.broadcastWandStatus(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "✗ Disconnected from wand");
|
||||
|
||||
// Publish disconnected status to Home Assistant
|
||||
#if ENABLE_HOME_ASSISTANT
|
||||
if (mqttClient.isConnected())
|
||||
{
|
||||
ESP_LOGI(TAG, "Publishing wand disconnection to Home Assistant...");
|
||||
mqttClient.publishWandDisconnected();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check if this was a user-initiated disconnect
|
||||
if (wandClient.isUserDisconnectRequested())
|
||||
{
|
||||
@@ -852,6 +923,9 @@ extern "C" void app_main()
|
||||
{
|
||||
ESP_LOGI(TAG, "✓ MQTT client initialized for Home Assistant");
|
||||
ESP_LOGI(TAG, " Connection errors will retry every 30 seconds");
|
||||
|
||||
// Register callback to publish wand info if already connected
|
||||
mqttClient.onConnected(onMQTTConnected);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1017,6 +1091,30 @@ extern "C" void app_main()
|
||||
{
|
||||
ESP_LOGW(TAG, "WARNING: Failed to request wand information");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wait for info to be retrieved
|
||||
vTaskDelay(300 / portTICK_PERIOD_MS);
|
||||
|
||||
// Publish wand info to Home Assistant
|
||||
#if ENABLE_HOME_ASSISTANT
|
||||
if (mqttClient.isConnected())
|
||||
{
|
||||
ESP_LOGI(TAG, "Publishing wand info to Home Assistant...");
|
||||
mqttClient.publishWandInfo(
|
||||
wandClient.getFirmwareVersion(),
|
||||
wandClient.getSerialNumber(),
|
||||
wandClient.getSKU(),
|
||||
wandClient.getDeviceId(),
|
||||
wandClient.getWandType(),
|
||||
wandClient.getWandMacAddress());
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "MQTT not connected - wand info not published");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Wait before starting IMU streaming
|
||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
@@ -1145,6 +1243,26 @@ extern "C" void app_main()
|
||||
{
|
||||
ESP_LOGW(TAG, "WARNING: Failed to request wand information");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wait for info to be retrieved
|
||||
vTaskDelay(300 / portTICK_PERIOD_MS);
|
||||
|
||||
// Publish wand info to Home Assistant
|
||||
#if ENABLE_HOME_ASSISTANT
|
||||
if (mqttClient.isConnected())
|
||||
{
|
||||
ESP_LOGI(TAG, "Publishing wand info to Home Assistant...");
|
||||
mqttClient.publishWandInfo(
|
||||
wandClient.getFirmwareVersion(),
|
||||
wandClient.getSerialNumber(),
|
||||
wandClient.getSKU(),
|
||||
wandClient.getDeviceId(),
|
||||
wandClient.getWandType(),
|
||||
wandClient.getWandMacAddress());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Wait before starting IMU streaming
|
||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
@@ -1219,16 +1337,24 @@ extern "C" void app_main()
|
||||
if (battery_check_counter >= BATTERY_CHECK_INTERVAL)
|
||||
{
|
||||
uint8_t battery = wandClient.getBatteryLevel();
|
||||
ESP_LOGI(TAG, "🔋 Battery check: level=%d%%", battery);
|
||||
if (battery > 0)
|
||||
{
|
||||
#if ENABLE_HOME_ASSISTANT
|
||||
ESP_LOGI(TAG, " → Broadcasting battery to web clients");
|
||||
webServer.broadcastBattery(battery);
|
||||
|
||||
// Publish to Home Assistant (only if connected)
|
||||
ESP_LOGI(TAG, " → Checking MQTT connection (isConnected=%d)", mqttClient.isConnected());
|
||||
if (mqttClient.isConnected())
|
||||
{
|
||||
ESP_LOGI(TAG, " → Calling mqttClient.publishBattery()");
|
||||
mqttClient.publishBattery(battery);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, " ⚠ MQTT not connected - skipping battery publish");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
battery_check_counter = 0;
|
||||
|
||||
Reference in New Issue
Block a user