Add accelerometer deadzone via UART and ESP-NOW.

Filter BMA456 logs by configurable LSB threshold; master can set deadzone
for local sensor or slaves using ACCEL_DEADZONE (UART) and ESP-NOW broadcast
until unicast delivery is restored.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-18 23:06:25 +02:00
co-authored by Cursor
parent e5db0b21c7
commit ee38ce551a
24 changed files with 838 additions and 73 deletions
+81 -19
View File
@@ -1,3 +1,4 @@
#include "bosch456.h"
#include "client_registry.h"
#include "esp_now_comm.h"
#include "esp_now_proto.h"
@@ -109,6 +110,35 @@ static esp_err_t send_message(const uint8_t *dest_mac,
return err;
}
static esp_err_t send_accel_deadzone(uint32_t client_id, uint32_t deadzone) {
alox_EspNowMessage msg = alox_EspNowMessage_init_zero;
msg.type = alox_EspNowMessageType_ESPNOW_SET_ACCEL_DEADZONE;
msg.which_payload = alox_EspNowMessage_accel_deadzone_tag;
msg.payload.accel_deadzone.deadzone = deadzone;
msg.payload.accel_deadzone.client_id = client_id;
return send_message(ESPNOW_BCAST, &msg);
}
esp_err_t esp_now_comm_send_accel_deadzone(uint32_t client_id, uint32_t deadzone) {
if (!s_config.master) {
return ESP_ERR_INVALID_STATE;
}
esp_err_t err = send_accel_deadzone(client_id, deadzone);
if (err == ESP_OK) {
ESP_LOGI(TAG,
"broadcast SET_ACCEL_DEADZONE deadzone=%lu client_id=%lu%s",
(unsigned long)deadzone, (unsigned long)client_id,
client_id == 0 ? " (all slaves)" : "");
} else {
ESP_LOGW(TAG, "broadcast SET_ACCEL_DEADZONE failed: %s",
esp_err_to_name(err));
}
return err;
}
static void send_presence(const uint8_t *dest_mac,
alox_EspNowMessageType type) {
alox_EspNowMessage msg = alox_EspNowMessage_init_zero;
@@ -133,6 +163,29 @@ static void slave_reset_join(void) {
s_last_discover_ms = 0;
}
static void handle_slave_accel_deadzone(const uint8_t *master_mac,
const alox_EspNowAccelDeadzone *cfg) {
uint32_t my_id = s_own_mac[5];
if (cfg->client_id != 0 && cfg->client_id != my_id) {
return;
}
if (s_slave_joined && !mac_equal(master_mac, s_master_mac)) {
return;
}
char mac_str[18];
mac_to_str(master_mac, mac_str, sizeof(mac_str));
ESP_LOGI(TAG,
"accel deadzone from master %s: %lu LSB id=%lu (sensor %s)",
mac_str, (unsigned long)cfg->deadzone, (unsigned long)my_id,
bma456_is_ready() ? "ok" : "not installed");
bma456_set_accel_deadzone(cfg->deadzone);
}
static void handle_client_presence(const alox_EspNowSlavePresence *presence,
const uint8_t mac[CLIENT_MAC_LEN]) {
if (presence->network != s_config.network) {
@@ -184,6 +237,7 @@ static void handle_discover(const uint8_t *sender_mac,
memcpy(s_master_mac, sender_mac, ESP_NOW_ETH_ALEN);
s_slave_joined = true;
s_last_discover_ms = now;
ensure_peer(sender_mac);
char mac_str[18];
mac_to_str(sender_mac, mac_str, sizeof(mac_str));
@@ -247,34 +301,42 @@ static void espnow_recv_cb(const esp_now_recv_info_t *info, const uint8_t *data,
return;
}
alox_EspNowMessage msg = alox_EspNowMessage_init_zero;
uint8_t peer_mac[CLIENT_MAC_LEN];
if (!s_config.master) {
alox_EspNowMessage msg = alox_EspNowMessage_init_zero;
esp_now_proto_setup_message_decode(&msg, peer_mac);
if (esp_now_proto_decode(data, (size_t)len, &msg) != ESP_OK) {
if (esp_now_proto_decode(data, (size_t)len, &msg) != ESP_OK) {
ESP_LOGW(TAG, "slave: ESP-NOW decode failed (%d bytes)", len);
return;
}
switch (msg.which_payload) {
case alox_EspNowMessage_discover_tag:
handle_discover(info->src_addr, &msg.payload.discover);
break;
case alox_EspNowMessage_accel_deadzone_tag:
handle_slave_accel_deadzone(info->src_addr, &msg.payload.accel_deadzone);
break;
default:
ESP_LOGW(TAG, "slave: unhandled ESP-NOW which=%u type=%u", msg.which_payload,
(unsigned)msg.type);
break;
}
return;
}
if (!s_config.master) {
if (msg.type != alox_EspNowMessageType_ESPNOW_DISCOVER ||
msg.which_payload != alox_EspNowMessage_discover_tag) {
return;
}
handle_discover(info->src_addr, &msg.payload.discover);
alox_EspNowMessage msg = alox_EspNowMessage_init_zero;
uint8_t peer_mac[CLIENT_MAC_LEN];
if (esp_now_proto_decode_with_mac(data, (size_t)len, &msg, peer_mac) !=
ESP_OK) {
ESP_LOGW(TAG, "master: ESP-NOW decode failed (%d bytes)", len);
return;
}
const alox_EspNowSlavePresence *presence = esp_now_proto_get_presence(&msg);
if (presence == NULL) {
return;
if (presence != NULL) {
handle_client_presence(presence, peer_mac);
}
if (msg.type != alox_EspNowMessageType_ESPNOW_SLAVE_INFO &&
msg.type != alox_EspNowMessageType_ESPNOW_HEARTBEAT) {
return;
}
handle_client_presence(presence, peer_mac);
}
static void master_discover_task(void *param) {