From 83382f466071985219bab7b1f47ca0417d75b461 Mon Sep 17 00:00:00 2001 From: Dave Plummer Date: Sat, 2 Nov 2024 14:16:38 -0700 Subject: [PATCH 1/2] Add ESPNOW Support --- include/globals.h | 9 +++++++-- src/effectmanager.cpp | 2 +- src/main.cpp | 16 ++++++++++++++- src/network.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++ src/remotecontrol.cpp | 2 +- 5 files changed, 69 insertions(+), 5 deletions(-) diff --git a/include/globals.h b/include/globals.h index e1b1116d..4fb2c40e 100644 --- a/include/globals.h +++ b/include/globals.h @@ -753,8 +753,9 @@ extern RemoteDebug Debug; // Let everyone in the project know about it #define PROJECT_NAME "Plate Cover" #endif - #define ENABLE_WIFI 1 // Connect to WiFi - #define INCOMING_WIFI_ENABLED 1 // Accepting incoming color data and commands + #define ENABLE_ESPNOW 1 // Connect to ESPNOW and listen for packets + #define ENABLE_WIFI 0 // Connect to WiFi + #define INCOMING_WIFI_ENABLED 0 // Accepting incoming color data and commands #define WAIT_FOR_WIFI 0 // Hold in setup until we have WiFi - for strips without effects #define TIME_BEFORE_LOCAL 3 // How many seconds before the lamp times out and shows local content #define MAX_BUFFERS 60 // Times 4 channels, but they're only NUM_LEDS big @@ -1292,6 +1293,10 @@ extern RemoteDebug Debug; // Let everyone in the project know about it #define ENABLE_OTA 1 // Listen for over the air update to the flash #endif +#ifndef ENABLE_ESPNOW +#define ENABLE_ESPNOW 0 // Listen for ESPNOW packets +#endif + #ifndef ENABLE_NTP #define ENABLE_NTP 1 // Update the clock from NTP #endif diff --git a/src/effectmanager.cpp b/src/effectmanager.cpp index 87a3ef6f..d717e1c7 100644 --- a/src/effectmanager.cpp +++ b/src/effectmanager.cpp @@ -370,7 +370,7 @@ void EffectManager::ClearRemoteColor(bool retainRemoteEffect) void EffectManager::ApplyGlobalColor(CRGB color) { - debugI("Setting Global Color: %08X\n", (uint) color); + debugI("Setting Global Color: %08X\n", (uint32_t) color); auto& deviceConfig = g_ptrSystem->DeviceConfig(); deviceConfig.SetColorSettings(color, deviceConfig.GlobalColor()); diff --git a/src/main.cpp b/src/main.cpp index 72868706..4fda4026 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -165,12 +165,14 @@ #include "values.h" #include "improvserial.h" // ImprovSerial impl for setting WiFi credentials over the serial port #include +#include #if defined(TOGGLE_BUTTON_1) || defined(TOGGLE_BUTTON_2) #include "Bounce2.h" // For Bounce button class #endif void IRAM_ATTR ScreenUpdateLoopEntry(void *); +void onReceiveESPNOW(const uint8_t *macAddr, const uint8_t *data, int dataLen); // // Global Variables @@ -323,8 +325,19 @@ void setup() err = nvs_flash_init(); } + ESP_ERROR_CHECK(err); + #if ENABLE_ESPNOW + WiFi.mode(WIFI_STA); // or WIFI_AP if applicable + + if (esp_now_init() != ESP_OK) + throw std::runtime_error("Error initializing ESP-NOW"); + // Register receive callback function + esp_now_register_recv_cb(onReceiveESPNOW); + debugI("ESP-NOW initialized with MAC address: %s", WiFi.macAddress().c_str()); + #endif + #if ENABLE_WIFI String WiFi_ssid; String WiFi_password; @@ -534,6 +547,7 @@ void setup() taskManager.StartSocketThread(); SaveEffectManagerConfig(); + // Start the main loop } // loop - main execution loop @@ -569,7 +583,7 @@ void loop() String strOutput; #if ENABLE_WIFI - strOutput += str_sprintf("WiFi: %s, IP: %s, ", WLtoString(WiFi.status()), WiFi.localIP().toString().c_str()); + strOutput += str_sprintf("WiFi: %s, MAC: %s, IP: %s ", WLtoString(WiFi.status()), WiFi.macAddress().c_str(), WiFi.localIP().toString().c_str()); #endif strOutput += str_sprintf("Mem: %u, LargestBlk: %u, PSRAM Free: %u/%u, ", ESP.getFreeHeap(), ESP.getMaxAllocHeap(), ESP.getFreePsram(), ESP.getPsramSize()); diff --git a/src/network.cpp b/src/network.cpp index 5503b734..8050efbe 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -49,6 +49,51 @@ static DRAM_ATTR WiFiUDP l_Udp; // UDP object used for NNTP, etc DRAM_ATTR bool NTPTimeClient::_bClockSet = false; // Has our clock been set by SNTP? DRAM_ATTR std::mutex NTPTimeClient::_clockMutex; // Clock guard mutex for SNTP client +#if ENABLE_ESPNOW + +// ESPNOW Support +// +// We accept ESPNOW commands to change effects and so on. This is a simple structure that we'll receive over ESPNOW. +typedef enum +{ + ESPNOW_NEXTEFFECT, + ESPNOW_PREVEFFECT, +} ESPNOW_COMMAND; + +typedef struct Message +{ + byte cbSize; + ESPNOW_COMMAND command; +} Message; + +Message message; + +void onReceiveESPNOW(const uint8_t *macAddr, const uint8_t *data, int dataLen) +{ + memcpy(&message, data, sizeof(message)); + debugI("ESPNOW Message received."); + if (message.cbSize != sizeof(message)) + { + debugE("ESPNOW Message received with wrong structure size: %d but should be %d", message.cbSize, sizeof(message)); + return; + } + + switch(message.command) + { + case ESPNOW_NEXTEFFECT: + g_ptrSystem->EffectManager().NextEffect(); + break; + case ESPNOW_PREVEFFECT: + g_ptrSystem->EffectManager().PreviousEffect(); + break; + default: + debugE("ESPNOW Message received with unknown command: %d", message.command); + break; + } +} + +#endif + // processRemoteDebugCmd // // Callback function that the debug library (which exposes a little console over telnet and serial) calls diff --git a/src/remotecontrol.cpp b/src/remotecontrol.cpp index 83072146..04b98f15 100644 --- a/src/remotecontrol.cpp +++ b/src/remotecontrol.cpp @@ -151,7 +151,7 @@ void RemoteControl::handle() // crate a ColorFillEffect, and apply it as a temporary effect. This will override the current // effect until the next effect change or remote command. - debugI("Changing Color via remote: %08X\n", (uint) RemoteColorCodes[i].color); + debugI("Changing Color via remote: %08X\n", (uint32_t) RemoteColorCodes[i].color); effectManager.ApplyGlobalColor(RemoteColorCodes[i].color); #if FULL_COLOR_REMOTE_FILL auto effect = make_shared_psram("Remote Color", RemoteColorCodes[i].color, 1, true); From 100603296cbcb8692b1c2acc8f7f125bf7c96d24 Mon Sep 17 00:00:00 2001 From: Dave Plummer Date: Sun, 3 Nov 2024 08:40:32 -0800 Subject: [PATCH 2/2] Cleanup --- src/network.cpp | 63 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/src/network.cpp b/src/network.cpp index 8050efbe..f6d2532a 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -54,24 +54,56 @@ DRAM_ATTR std::mutex NTPTimeClient::_clockMutex; // ESPNOW Support // // We accept ESPNOW commands to change effects and so on. This is a simple structure that we'll receive over ESPNOW. -typedef enum +enum class ESPNowCommand : uint8_t { - ESPNOW_NEXTEFFECT, + ESPNOW_NEXTEFFECT = 1, ESPNOW_PREVEFFECT, -} ESPNOW_COMMAND; + ESPNOW_SETEFFECT, + ESPNOW_INVALID = 255 // Followed by a uint32_t argument +}; -typedef struct Message +// Message class +// +// Encapsulates an ESPNOW message, which is a command and an optional argument +class Message { - byte cbSize; - ESPNOW_COMMAND command; -} Message; +public: + constexpr Message(ESPNowCommand cmd, uint32_t argument) + : cbSize(sizeof(Message)), command(cmd), arg1(argument) + { + } + + constexpr Message() + : cbSize(sizeof(Message)), command(ESPNowCommand::ESPNOW_INVALID), arg1(0) + { + } -Message message; + const uint8_t* data() const + { + return reinterpret_cast(this); + } + + constexpr size_t byte_size() const + { + return sizeof(Message); + } + + uint8_t cbSize; + ESPNowCommand command; + uint32_t arg1; +} __attribute__((packed)); + +// onReceiveESPNOW +// +// Callback function for ESPNOW that is called when a data packet is received void onReceiveESPNOW(const uint8_t *macAddr, const uint8_t *data, int dataLen) { + Message message; + memcpy(&message, data, sizeof(message)); debugI("ESPNOW Message received."); + if (message.cbSize != sizeof(message)) { debugE("ESPNOW Message received with wrong structure size: %d but should be %d", message.cbSize, sizeof(message)); @@ -80,14 +112,23 @@ void onReceiveESPNOW(const uint8_t *macAddr, const uint8_t *data, int dataLen) switch(message.command) { - case ESPNOW_NEXTEFFECT: + case ESPNowCommand::ESPNOW_NEXTEFFECT: + debugI("ESPNOW Next effect"); g_ptrSystem->EffectManager().NextEffect(); break; - case ESPNOW_PREVEFFECT: + + case ESPNowCommand::ESPNOW_PREVEFFECT: + debugI("ESPNOW Previous effect"); g_ptrSystem->EffectManager().PreviousEffect(); break; + + case ESPNowCommand::ESPNOW_SETEFFECT: + debugI("ESPNOW Setting effect index to %d", message.arg1); + g_ptrSystem->EffectManager().SetCurrentEffectIndex(message.arg1); + break; + default: - debugE("ESPNOW Message received with unknown command: %d", message.command); + debugE("ESPNOW Message received with unknown command: %d", (byte) message.command); break; } }