[LED] Refactor LED handling (#2051)

Refactor LED handling into a library
Use a task instead of relying on the loop for precise timing

Co-authored-by: Florian <1technophile@users.noreply.github.com>
This commit is contained in:
Florian
2024-09-13 09:55:56 -05:00
committed by GitHub
parent 20af9ccf11
commit 435b8ca3d9
14 changed files with 932 additions and 437 deletions

1
.gitignore vendored
View File

@@ -9,6 +9,7 @@ main/certs/private*
lib/*
!lib/esp32-bt-lib
!lib/TheengsUtils
!lib/LEDManager
CMakeLists.txt
dependencies.lock
sdkconfig.*

View File

@@ -300,17 +300,97 @@ Minimum: 0, Maximum: 255, Default defined by DEFAULT_ADJ_BRIGHTNESS
`mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoSYS/config" -m '{"brightness":200}'`
## State LED usage
## Understanding LED Indicators in OpenMQTTGateway
With boards having one or several RGB Led, OpenMQTTGateway uses them to provide visual feedback about its current state. This guide will help you interpret these LED signals to understand what's happening with your gateway.
The gateway can support up to 3 LED to display its operating state:
* LED_INFO
switched ON when network and MQTT connection are OK
5s ON, 5s OFF when MQTT is disconnected
2s ON, 2s OFF when NETWORK is disconnected
## LED Color Guide
OpenMQTTGateway uses a variety of colors to indicate different states:
* LED_RECEIVE
Blink for `TimeLedON` 1s when the gateway receive a signal from one of its module so as to send to MQTT
Green (0x00FF00): Indicates normal operation or successful connections
Blue (0x0000FF): Shows processing or offline status
Orange (0xFFA500): Indicates waiting states or minor issues
Yellow (0xFFFF00): Used during the onboarding process
Red (0xFF0000): Signals an error state
Magenta (0xFF00FF): Indicates local Over-The-Air (OTA) updates
Purple (0x8000FF): Shows remote OTA updates are in progress
* LED_SEND
Blink for `TimeLedON` 1s when the gateway send a signal with one of its module from an MQTT command
## Understanding Gateway States
Here's what different LED behaviors mean:
### Power On
Color: Green
Behavior: Solid light
Meaning: The gateway is powered and operational
### Processing
Color: Blue
Behavior: Blinking (3 times)
Meaning: The gateway is processing data
### Waiting for Onboarding
Color: Orange
Behavior: Solid light
Meaning: The gateway is ready to be set up
### Onboarding in Progress
Color: Yellow
Behavior: Solid light
Meaning: The gateway is being configured
### Network Connected
Color: Green
Behavior: Solid light
Meaning: Successfully connected to the network
### Network Disconnected
Color: Orange
Behavior: Blinking
Meaning: Lost connection to the network
### MQTT Broker Connected
Color: Green
Behavior: Solid light
Meaning: Successfully connected to the MQTT broker
### MQTT Broker Disconnected
Color: Orange
Behavior: Blinking
Meaning: Lost connection to the MQTT broker
### Offline
Color: Blue
Behavior: Blinking
Meaning: The gateway is offline
### Local OTA Update
Color: Magenta
Behavior: Blinking
Meaning: A local Over-The-Air update is in progress
### Remote OTA Update
Color: Purple
Behavior: Blinking
Meaning: A remote Over-The-Air update is in progress
### Error
Color: Red
Behavior: Blinking (3 times)
Meaning: An error has occurred
### Actuator On/Off
Color: Green
Behavior: Depends on actuator state
Meaning: Indicates the state of a connected actuator

View File

@@ -62,8 +62,8 @@ lib_deps =
build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DLED_SEND_RECEIVE=2'
'-DLED_SEND_RECEIVE_ON=0'
'-DLED_PIN=2'
'-DLED_PIN_ON=0'
'-DESP32_ETHERNET=true'
'-DETH_PHY_TYPE=ETH_PHY_LAN8720'
'-DETH_PHY_ADDR=0'
@@ -71,13 +71,13 @@ build_flags =
'-DETH_PHY_MDC=23'
'-DETH_PHY_MDIO=18'
'-DETH_CLK_MODE=ETH_CLOCK_GPIO16_OUT'
'-DANEOPIX_IND_DATA_GPIO=32'
'-DANEOPIX_IND_NUM_LEDS=4'
'-DANEOPIX_INFO_LED=0'
'-DANEOPIX_SEND_RECEIVE_LED=1'
'-DANEOPIX_ERROR_LED=1'
'-DANEOPIX_BRIGHTNESS=10'
'-DRGB_INDICATORS=true'
'-DLED_ADDRESSABLE_PIN1=32'
'-DLED_ADDRESSABLE_NUM=4'
'-DLED_BROKER=0'
'-DLED_PROCESSING=1'
'-DLED_ERROR=1'
'-DDEFAULT_ADJ_BRIGHTNESS=10'
'-DLED_ADDRESSABLE=true'
'-DAttemptBLEConnect=false'
'-DUSE_MAC_AS_GATEWAY_NAME'
'-DGATEWAY_MANUFACTURER="Theengs"'
@@ -100,8 +100,6 @@ lib_deps =
build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DLED_SEND_RECEIVE=2'
'-DLED_SEND_RECEIVE_ON=0'
'-DESP32_ETHERNET=true'
'-DETH_PHY_TYPE=ETH_PHY_LAN8720'
'-DETH_PHY_ADDR=0'
@@ -109,13 +107,14 @@ build_flags =
'-DETH_PHY_MDC=23'
'-DETH_PHY_MDIO=18'
'-DETH_CLK_MODE=ETH_CLOCK_GPIO16_OUT'
'-DANEOPIX_IND_DATA_GPIO=32'
'-DANEOPIX_IND_NUM_LEDS=4'
'-DANEOPIX_INFO_LED=0'
'-DANEOPIX_SEND_RECEIVE_LED=1'
'-DANEOPIX_ERROR_LED=1'
'-DANEOPIX_BRIGHTNESS=100'
'-DRGB_INDICATORS=true'
'-DLED_ADDRESSABLE=true'
'-DLED_ADDRESSABLE_PIN1=32'
'-DLED_ADDRESSABLE_NUM=4'
'-DLED_ERROR=3'
'-DLED_PROCESSING=3'
'-DLED_BROKER=2'
'-DLED_NETWORK=1'
'-DLED_POWER=0'
'-DAttemptBLEConnect=false'
'-DTRIGGER_GPIO=4'
'-DUSE_MAC_AS_GATEWAY_NAME'
@@ -331,8 +330,8 @@ lib_deps =
build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DLED_SEND_RECEIVE=2'
'-DLED_SEND_RECEIVE_ON=0'
'-DLED_PIN=2'
'-DLED_PIN_ON=0'
'-DGateway_Name="OMG_ESP32_BLE"'
custom_description = Regular BLE gateway with adaptive scanning activated, automatically adapts the scan parameters depending on your devices
@@ -348,8 +347,8 @@ lib_deps =
build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DLED_SEND_RECEIVE=2'
'-DLED_SEND_RECEIVE_ON=0'
'-DLED_PIN=2'
'-DLED_PIN_ON=0'
'-DGateway_Name="OMG_ESP32_BLE"'
'-DMQTT_BROKER_MODE=true'
custom_description = MQTT Broker with BLE gateway with adaptive scanning activated, automatically adapts the scan parameters depending on your devices
@@ -366,8 +365,8 @@ build_flags =
${com-esp32.build_flags}
'-DBLEDecoder=false'
'-DZgatewayBT="BT"'
'-DLED_SEND_RECEIVE=2'
'-DLED_SEND_RECEIVE_ON=0'
'-DLED_PIN=2'
'-DLED_PIN_ON=0'
'-DGateway_Name="OMG_ESP32_BLE"'
'-DMQTTDecodeTopic="undecoded"'
custom_description = BLE gateway with the decoding offloaded to Theengs Gateway
@@ -385,8 +384,8 @@ build_flags =
${com-esp32.build_flags}
'-UZmqttDiscovery="HADiscovery"'
'-DZgatewayBT="BT"'
'-DLED_SEND_RECEIVE=2'
'-DLED_SEND_RECEIVE_ON=0'
'-DLED_PIN=2'
'-DLED_PIN_ON=0'
'-DARDUINO_LOOP_STACK_SIZE=17500'
'-DMQTT_SECURE_DEFAULT=true'
'-DMQTT_CERT_VALIDATE_DEFAULT=true'
@@ -410,8 +409,8 @@ lib_deps =
build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DLED_SEND_RECEIVE=13'
'-DLED_SEND_RECEIVE_ON=0'
'-DLED_PIN=13'
'-DLED_PIN_ON=0'
'-DGateway_Name="OMG_ESP32_FTH_BLE"'
custom_description = BLE Gateway
custom_hardware = ESP32 Feather Adafruit
@@ -428,8 +427,8 @@ lib_deps =
build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DLED_SEND_RECEIVE=22'
'-DLED_SEND_RECEIVE_ON=0'
'-DLED_PIN=22'
'-DLED_PIN_ON=0'
'-DGateway_Name="OMG_LOLIN32LITE_BLE"'
;; Low power parameters, uncomment and fill credentials
'-DDEFAULT_LOW_POWER_MODE=INTERVAL'
@@ -458,8 +457,8 @@ lib_deps =
build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DLED_SEND_RECEIVE=33'
'-DLED_SEND_RECEIVE_ON=1'
'-DLED_PIN=33'
'-DLED_PIN_ON=1'
'-DTRIGGER_GPIO=34'
'-DESP32_ETHERNET=true'
'-DGateway_Name="OMG_ESP32_OLM_GTWE"'
@@ -553,8 +552,8 @@ build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DZgatewayIR="IR"'
'-DLED_SEND_RECEIVE=19'
'-DLED_SEND_RECEIVE_ON=1'
'-DLED_PIN=19'
'-DLED_PIN_ON=1'
'-DTRIGGER_GPIO=35'
'-DIR_EMITTER_GPIO=17'
'-DDEFAULT_LOW_POWER_MODE=ALWAYS_ON'
@@ -578,7 +577,7 @@ build_flags =
'-DZgatewayBT="BT"'
'-DZsensorGPIOInput="GPIOInput"'
'-DZboardM5STACK="M5Stack"'
'-DLED_SEND_RECEIVE=15'
'-DLED_PIN=15'
'-DTRIGGER_GPIO=37'
'-DSLEEP_BUTTON=38'
'-DINPUT_GPIO=39'
@@ -626,8 +625,8 @@ build_flags =
'-DZboardM5STICKC="M5StickC"'
'-DACTUATOR_ONOFF_GPIO=10'
'-DINPUT_GPIO=37'
'-DLED_SEND_RECEIVE=10'
'-DLED_SEND_RECEIVE_ON=0'
'-DLED_PIN=10'
'-DLED_PIN_ON=0'
'-DSLEEP_BUTTON=39'
'-DTRIGGER_GPIO=39'
'-DIR_EMITTER_INVERTED=true'
@@ -657,8 +656,8 @@ build_flags =
'-DZboardM5STICKCP="M5StickCP"'
'-DACTUATOR_ONOFF_GPIO=10'
'-DINPUT_GPIO=37'
'-DLED_SEND_RECEIVE=10'
'-DLED_SEND_RECEIVE_ON=0'
'-DLED_PIN=10'
'-DLED_PIN_ON=0'
'-DSLEEP_BUTTON=39'
'-DTRIGGER_GPIO=39'
'-DIR_EMITTER_INVERTED=true'
@@ -687,9 +686,14 @@ build_flags =
'-DTRIGGER_GPIO=39'
'-DSLEEP_BUTTON=39'
'-DIR_EMITTER_GPIO=12'
'-DANEOPIX_IND_DATA_GPIO=27'
'-DANEOPIX_IND_NUM_LEDS=25'
'-DRGB_INDICATORS=true'
'-DLED_ADDRESSABLE_PIN1=27'
'-DLED_ADDRESSABLE_NUM=25'
'-DLED_ADDRESSABLE=true'
'-DLED_ERROR=4'
'-DLED_PROCESSING=3'
'-DLED_BROKER=2'
'-DLED_NETWORK=1'
'-DLED_POWER=0'
'-DGateway_Name="OMG_ATOM_M"'
board_upload.speed = 1500000
custom_description = Compact enclosure ESP32 with BLE gateway
@@ -713,9 +717,9 @@ build_flags =
'-DTRIGGER_GPIO=39'
'-DSLEEP_BUTTON=39'
'-DIR_EMITTER_GPIO=12'
'-DANEOPIX_IND_DATA_GPIO=27'
'-DANEOPIX_IND_NUM_LEDS=1'
'-DRGB_INDICATORS=true'
'-DLED_ADDRESSABLE_PIN1=27'
'-DLED_ADDRESSABLE_NUM=1'
'-DLED_ADDRESSABLE=true'
'-DGateway_Name="OMG_ATOM_L"'
board_upload.speed = 1500000
custom_description = Compact enclosure ESP32 with BLE gateway
@@ -1145,11 +1149,11 @@ build_flags =
'-DZgatewayLORA="LORA"'
'-DZgatewayBT="BT"'
'-DGateway_Name="OMG_ESP32_BLE_LORA"'
'-DLED_SEND_RECEIVE=21' # T-BEAM board V0.5
# '-DLED_SEND_RECEIVE=14' # T-BEAM board V0.7
# '-DLED_SEND_RECEIVE=4' # T-BEAM board V1.0+
'-DLED_PIN=21' # T-BEAM board V0.5
# '-DLED_PIN=14' # T-BEAM board V0.7
# '-DLED_PIN=4' # T-BEAM board V1.0+
'-DTimeLedON=0.05'
'-DLED_SEND_RECEIVE_ON=1' # Set 0 for board V1.0+
'-DLED_PIN_ON=1' # Set 0 for board V1.0+
# for V0.5 and V0.7 ONLY (V1.0+ as onboard AXP202 dedicated chip, need driver)
# it's a 100K/100K divider (so 2 divider) and connected to GPIO35
'-DZsensorADC="ADC"'
@@ -1173,9 +1177,9 @@ build_flags =
'-DZgatewayLORA="LORA"'
'-DLORA_BAND=868E6'
'-DGateway_Name="OMG_ESP32_LORA"'
'-DLED_SEND_RECEIVE=25'
'-DLED_PIN=25'
'-DTimeLedON=0.1'
'-DLED_SEND_RECEIVE_ON=1'
'-DLED_PIN_ON=1'
; *** ssd1306 Display Options ***
'-DZdisplaySSD1306="HELTEC_SSD1306"'
; '-DLOG_TO_OLED=true' ; Enable log to OLED
@@ -1352,7 +1356,7 @@ build_flags =
${com-esp.build_flags}
'-DZgatewayIR="IR"'
'-DTRIGGER_GPIO=13'
'-DLED_SEND_RECEIVE=4'
'-DLED_PIN=4'
'-DIR_EMITTER_GPIO=14'
'-DIR_RECEIVER_GPIO=5'
'-UMQTTsetMQTT' ;We remove this function to have sufficient FLASH available for OTA, you should also use ESPWifiManualSetup and 'board_build.ldscript = eagle.flash.1m64.ld' to save flash memory and have OTA working
@@ -1565,8 +1569,8 @@ lib_deps =
build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DLED_SEND_RECEIVE=2'
'-DLED_SEND_RECEIVE_ON=0'
'-DLED_PIN=2'
'-DLED_PIN_ON=0'
'-DTimeBtwRead=0'
'-DScan_duration=3000'
'-DAttemptBLEConnect=false'
@@ -1585,9 +1589,9 @@ lib_deps =
build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DANEOPIX_IND_DATA_GPIO=48'
'-DANEOPIX_IND_NUM_LEDS=1'
'-DRGB_INDICATORS=true'
'-DLED_ADDRESSABLE_PIN1=48'
'-DLED_ADDRESSABLE_NUM=1'
'-DLED_ADDRESSABLE=true'
'-DNO_INT_TEMP_READING=true' ; Internal temperature reading not building on ESP32 C3 or S3
'-DGateway_Name="OMG_ESP32_BLE"'
custom_description = BLE gateway on the S3
@@ -1605,9 +1609,9 @@ build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DZgatewayIR="IR"'
'-DANEOPIX_IND_DATA_GPIO=35'
'-DANEOPIX_IND_NUM_LEDS=1'
'-DRGB_INDICATORS=true'
'-DLED_ADDRESSABLE_PIN1=35'
'-DLED_ADDRESSABLE_NUM=1'
'-DLED_ADDRESSABLE=true'
'-DTRIGGER_GPIO=41'
'-DIR_EMITTER_GPIO=12'
'-DNO_INT_TEMP_READING=true' ; Internal temperature reading not building on ESP32 C3 or S3
@@ -1628,9 +1632,9 @@ lib_deps =
build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DANEOPIX_IND_DATA_GPIO=8'
'-DANEOPIX_IND_NUM_LEDS=1'
'-DRGB_INDICATORS=true'
'-DLED_ADDRESSABLE_PIN1=8'
'-DLED_ADDRESSABLE_NUM=1'
'-DLED_ADDRESSABLE=true'
'-DNO_INT_TEMP_READING=true' ; Internal temperature reading not building on ESP32 C3 or S3
'-DGateway_Name="OMG_ESP32_BLE"'
custom_description = BLE gateway on the C3
@@ -1647,7 +1651,7 @@ build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DLED_INFO=19'
'-DLED_SEND_RECEIVE=20'
'-DLED_PIN=20'
'-DNO_INT_TEMP_READING=true' ; Internal temperature reading not building on ESP32 C3 or S3
'-DGateway_Name="OMG_AirM2M_Core_ESP32C3"'
custom_description = BLE gateway on the C3
@@ -1666,11 +1670,11 @@ lib_deps =
build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DANEOPIX_IND_DATA_GPIO=8'
'-DANEOPIX_IND_NUM_LEDS=1'
; '-DANEOPIX_BRIGHTNESS=10' ; 0 - 255, default 20
'-DLED_ADDRESSABLE_PIN1=8'
'-DLED_ADDRESSABLE_NUM=1'
; '-DDEFAULT_ADJ_BRIGHTNESS=10' ; 0 - 255, default 20
'-DANEOPIX_COLOR_SCHEME=2' ; blue based signalling colors
'-DRGB_INDICATORS=true'
'-DLED_ADDRESSABLE=true'
'-DNO_INT_TEMP_READING=true' ; No internal temperature reading on ESP32 C3 or S3
'-DTRIGGER_GPIO=7'
'-DGateway_Name="OpenMQTTGateway_ESP32C3_DKC02"'
@@ -1698,11 +1702,11 @@ lib_deps =
build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DANEOPIX_IND_DATA_GPIO=7'
'-DANEOPIX_IND_NUM_LEDS=1'
; '-DANEOPIX_BRIGHTNESS=10' ; 0 - 255, default 20
'-DLED_ADDRESSABLE_PIN1=7'
'-DLED_ADDRESSABLE_NUM=1'
; '-DDEFAULT_ADJ_BRIGHTNESS=10' ; 0 - 255, default 20
'-DANEOPIX_COLOR_SCHEME=1' ; Alternative LED colour scheme: 2 = blue/gold. 1 = green/gold
'-DRGB_INDICATORS=true'
'-DLED_ADDRESSABLE=true'
; The momentary switch on the board is connected to GPIO9
'-DTRIGGER_GPIO=9'
'-DNO_INT_TEMP_READING=true' ; No internal temperature on ESP32 C3 or S3
@@ -1738,9 +1742,9 @@ build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DTRIGGER_GPIO=3'
'-DANEOPIX_IND_DATA_GPIO=2'
'-DANEOPIX_IND_NUM_LEDS=1'
'-DRGB_INDICATORS=true'
'-DLED_ADDRESSABLE_PIN1=2'
'-DLED_ADDRESSABLE_NUM=1'
'-DLED_ADDRESSABLE=true'
'-DNO_INT_TEMP_READING=true' ; Internal temperature reading not building on ESP32 C3 or S3
'-DUSE_MAC_AS_GATEWAY_NAME'
custom_description = BLE gateway on ESP32C3
@@ -1759,8 +1763,8 @@ lib_deps =
build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DLED_SEND_RECEIVE=2'
'-DLED_SEND_RECEIVE_ON=0'
'-DLED_PIN=2'
'-DLED_PIN_ON=0'
'-DGateway_Name="OMG_THINGPULSE_ETH_BLE"'
'-DESP32_ETHERNET=true'
'-DETH_PHY_TYPE=ETH_PHY_LAN8720'
@@ -1769,13 +1773,13 @@ build_flags =
'-DETH_PHY_MDC=23'
'-DETH_PHY_MDIO=18'
'-DETH_CLK_MODE=ETH_CLOCK_GPIO16_OUT'
'-DANEOPIX_IND_DATA_GPIO=32'
'-DANEOPIX_IND_NUM_LEDS=4'
'-DANEOPIX_INFO_LED=0'
'-DANEOPIX_SEND_RECEIVE_LED=1'
'-DANEOPIX_ERROR_LED=2'
'-DANEOPIX_BRIGHTNESS=255'
'-DRGB_INDICATORS=true'
'-DLED_ADDRESSABLE_PIN1=32'
'-DLED_ADDRESSABLE_NUM=4'
'-DLED_BROKER=0'
'-DLED_PROCESSING=1'
'-DLED_ERROR=2'
'-DDEFAULT_ADJ_BRIGHTNESS=255'
'-DLED_ADDRESSABLE=true'
; '-DsimplePublishing=true'
custom_description = BLE Gateway using ethernet or wifi with external antenna
custom_hardware = ThingPulse gateway single ESP32
@@ -1793,8 +1797,8 @@ lib_deps =
build_flags =
${com-esp32.build_flags}
'-DZgatewayBT="BT"'
'-DLED_SEND_RECEIVE=2'
'-DLED_SEND_RECEIVE_ON=0'
'-DLED_PIN=2'
'-DLED_PIN_ON=0'
'-DGateway_Name="OMG_ESP32_BLE"'
'-DUSE_BLUFI=1'
'-DARDUINO_LOOP_STACK_SIZE=17500'

View File

@@ -0,0 +1,243 @@
/*
Theengs LEDManager - We Unite Sensors in One Open-Source Interface
Copyright: (c)Florian ROBERT
This file is part of LEDManager library.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "LEDManager.h"
LEDManager::LEDManager() : globalBrightness(255) {}
void LEDManager::addLEDStrip(int pin, int numLeds) {
LEDStrip ledStrip;
ledStrip.pin = pin;
#ifdef LED_ADDRESSABLE
ledStrip.strip = new Adafruit_NeoPixel(numLeds, pin, NEO_GRB + NEO_KHZ800);
ledStrip.strip->begin();
ledStrip.strip->show();
ledStrip.strip->setBrightness(globalBrightness);
#else
pinMode(pin, OUTPUT);
#endif
ledStrip.ledStates.resize(numLeds, {OFF, OFF, 0, 0, 0, 0, 0, false, 255, FADE_AMOUNT, {OFF, 0, -1, false}});
ledStrips.push_back(ledStrip);
}
void LEDManager::setMode(int stripIndex, int ledIndex, Mode mode, uint32_t color, int durationOrBlinkCount) {
if (stripIndex >= 0 && stripIndex < ledStrips.size()) {
if (ledIndex == -1) {
for (int i = 0; i < ledStrips[stripIndex].ledStates.size(); i++) {
setModeForSingleLED(stripIndex, i, mode, color, durationOrBlinkCount);
}
} else if (ledIndex >= 0 && ledIndex < ledStrips[stripIndex].ledStates.size()) {
setModeForSingleLED(stripIndex, ledIndex, mode, color, durationOrBlinkCount);
}
}
}
void LEDManager::setModeForSingleLED(int stripIndex, int ledIndex, Mode mode, uint32_t color, int durationOrBlinkCount) {
auto& state = ledStrips[stripIndex].ledStates[ledIndex];
if ((state.mode == BLINK || state.mode == PULSE) && state.durationOrBlinkCount > 0) {
state.queuedState = {mode, color, durationOrBlinkCount, true};
return;
}
if (mode != BLINK && mode != PULSE) {
state.previousMode = state.mode;
state.previousColor = state.color;
}
state.mode = mode;
state.color = color;
state.durationOrBlinkCount = durationOrBlinkCount;
state.lastUpdateTime = millis();
state.blinkCounter = 0;
state.isBlinkOn = false;
state.brightness = globalBrightness;
state.fadeAmount = FADE_AMOUNT;
state.queuedState.isQueued = false;
}
void LEDManager::setBrightness(uint8_t brightness) {
#ifdef LED_ADDRESSABLE
globalBrightness = brightness;
for (auto& ledStrip : ledStrips) {
ledStrip.strip->setBrightness(brightness);
for (auto& state : ledStrip.ledStates) {
state.brightness = brightness;
}
}
#endif
}
void LEDManager::setLEDColor(int stripIndex, int ledIndex, uint32_t color) {
if (stripIndex < 0 || stripIndex >= ledStrips.size()) return;
if (ledIndex < 0 || ledIndex >= ledStrips[stripIndex].ledStates.size()) return;
uint8_t r, g, b;
extractRGB(color, r, g, b);
r = (r * globalBrightness) / 255;
g = (g * globalBrightness) / 255;
b = (b * globalBrightness) / 255;
#ifdef LED_ADDRESSABLE
ledStrips[stripIndex].strip->setPixelColor(ledIndex, r, g, b);
ledStrips[stripIndex].strip->show();
#else
// For non-addressable LEDs, we'll use the first LED of each strip
if (ledIndex == 0) {
int pin = ledStrips[stripIndex].pin;
analogWrite(pin, (r + g + b) / 3); // Average of RGB for single-color LED
}
#endif
}
void LEDManager::update() {
for (int stripIndex = 0; stripIndex < ledStrips.size(); stripIndex++) {
for (int ledIndex = 0; ledIndex < ledStrips[stripIndex].ledStates.size(); ledIndex++) {
auto& state = ledStrips[stripIndex].ledStates[ledIndex];
switch (state.mode) {
case BLINK:
handleBlink(stripIndex, ledIndex);
break;
case PULSE:
handlePulse(stripIndex, ledIndex);
break;
case STATIC:
handleStatic(stripIndex, ledIndex);
break;
case OFF:
setLEDColor(stripIndex, ledIndex, 0);
break;
}
}
#ifdef LED_ADDRESSABLE
ledStrips[stripIndex].strip->show();
#endif
}
}
void LEDManager::handleBlink(int stripIndex, int ledIndex) {
auto& state = ledStrips[stripIndex].ledStates[ledIndex];
unsigned long currentTime = millis();
if (currentTime - state.lastUpdateTime >= BLINK_INTERVAL) {
state.lastUpdateTime = currentTime;
if (state.durationOrBlinkCount > 0) {
if (state.blinkCounter == 0) {
state.blinkCounter = state.durationOrBlinkCount * 2;
} else {
state.blinkCounter--;
if (state.blinkCounter == 0) {
if (state.queuedState.isQueued) {
applyQueuedState(stripIndex, ledIndex);
} else {
returnToPreviousState(stripIndex, ledIndex);
}
return;
}
}
}
state.isBlinkOn = !state.isBlinkOn;
if (state.isBlinkOn) {
setLEDColor(stripIndex, ledIndex, state.color);
} else {
setLEDColor(stripIndex, ledIndex, 0);
}
}
}
void LEDManager::handlePulse(int stripIndex, int ledIndex) {
auto& state = ledStrips[stripIndex].ledStates[ledIndex];
unsigned long currentTime = millis();
if (currentTime - state.lastUpdateTime >= PULSE_INTERVAL) {
state.lastUpdateTime = currentTime;
state.brightness += state.fadeAmount;
if (state.brightness <= 0 || state.brightness >= 255) {
state.fadeAmount = -state.fadeAmount;
state.brightness = constrain(state.brightness, 0, 255);
if (state.durationOrBlinkCount > 0) {
state.durationOrBlinkCount--;
if (state.durationOrBlinkCount == 0) {
if (state.queuedState.isQueued) {
applyQueuedState(stripIndex, ledIndex);
} else {
returnToPreviousState(stripIndex, ledIndex);
}
return;
}
}
}
uint32_t adjustedColor = (state.color & 0xFF000000) |
(((state.color & 0x00FF0000) * state.brightness / 255) & 0x00FF0000) |
(((state.color & 0x0000FF00) * state.brightness / 255) & 0x0000FF00) |
(((state.color & 0x000000FF) * state.brightness / 255) & 0x000000FF);
setLEDColor(stripIndex, ledIndex, adjustedColor);
}
}
void LEDManager::handleStatic(int stripIndex, int ledIndex) {
auto& state = ledStrips[stripIndex].ledStates[ledIndex];
unsigned long currentTime = millis();
if (state.durationOrBlinkCount > 0) {
if (currentTime - state.lastUpdateTime >= static_cast<unsigned long>(state.durationOrBlinkCount) * 1000) {
if (state.queuedState.isQueued) {
applyQueuedState(stripIndex, ledIndex);
} else {
returnToPreviousState(stripIndex, ledIndex);
}
return;
}
}
setLEDColor(stripIndex, ledIndex, state.color);
}
void LEDManager::returnToPreviousState(int stripIndex, int ledIndex) {
auto& state = ledStrips[stripIndex].ledStates[ledIndex];
state.mode = state.previousMode;
state.color = state.previousColor;
state.durationOrBlinkCount = -1; // Set to infinite for the previous state
state.lastUpdateTime = millis();
state.blinkCounter = 0;
state.isBlinkOn = false;
state.brightness = globalBrightness;
state.fadeAmount = FADE_AMOUNT;
}
void LEDManager::applyQueuedState(int stripIndex, int ledIndex) {
auto& state = ledStrips[stripIndex].ledStates[ledIndex];
state.mode = state.queuedState.mode;
state.color = state.queuedState.color;
state.durationOrBlinkCount = state.queuedState.durationOrBlinkCount;
state.lastUpdateTime = millis();
state.blinkCounter = 0;
state.isBlinkOn = false;
state.brightness = globalBrightness;
state.fadeAmount = FADE_AMOUNT;
state.queuedState.isQueued = false;
}
void LEDManager::extractRGB(uint32_t color, uint8_t& r, uint8_t& g, uint8_t& b) {
r = (color >> 16) & 0xFF;
g = (color >> 8) & 0xFF;
b = color & 0xFF;
}

107
lib/LEDManager/LEDManager.h Normal file
View File

@@ -0,0 +1,107 @@
/*
Theengs LEDManager - We Unite Sensors in One Open-Source Interface
Copyright: (c)Florian ROBERT
This file is part of LEDManager library.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef LED_MANAGER_H
#define LED_MANAGER_H
#include <Arduino.h>
#include <vector>
#ifdef LED_ADDRESSABLE
# include <Adafruit_NeoPixel.h>
#endif
#ifndef BLINK_INTERVAL
# define BLINK_INTERVAL 500
#endif
#ifndef PULSE_INTERVAL
# define PULSE_INTERVAL 30
#endif
#ifndef FADE_AMOUNT
# define FADE_AMOUNT 5
#endif
// Define the pins for the RGB LED power if needed
#ifndef LED_ADDRESSABLE_POWER
# define LED_ADDRESSABLE_POWER -1
#endif
class LEDManager {
public:
enum Mode { OFF,
STATIC,
BLINK,
PULSE };
LEDManager();
void init();
void addLEDStrip(int pin, int numLeds);
void setMode(int stripIndex, int ledIndex, Mode mode, uint32_t color, int durationOrBlinkCount = -1);
void update();
void setBrightness(uint8_t brightness);
private:
struct QueuedState {
Mode mode;
uint32_t color;
int durationOrBlinkCount;
bool isQueued;
};
struct LEDState {
Mode mode;
Mode previousMode;
uint32_t color;
uint32_t previousColor;
int durationOrBlinkCount;
unsigned long lastUpdateTime;
int blinkCounter;
bool isBlinkOn;
int brightness;
int fadeAmount;
QueuedState queuedState;
};
struct LEDStrip {
#ifdef LED_ADDRESSABLE
Adafruit_NeoPixel* strip;
#endif
int pin;
std::vector<LEDState> ledStates;
};
std::vector<LEDStrip> ledStrips;
int globalBrightness;
void setModeForSingleLED(int stripIndex, int ledIndex, Mode mode, uint32_t color, int durationOrBlinkCount);
void setLEDColor(int stripIndex, int ledIndex, uint32_t color);
void handleBlink(int stripIndex, int ledIndex);
void handlePulse(int stripIndex, int ledIndex);
void handleStatic(int stripIndex, int ledIndex);
void returnToPreviousState(int stripIndex, int ledIndex);
void applyQueuedState(int stripIndex, int ledIndex);
void extractRGB(uint32_t color, uint8_t& r, uint8_t& g, uint8_t& b);
};
#endif // LED_MANAGER_H

132
lib/LEDManager/README.md Normal file
View File

@@ -0,0 +1,132 @@
# LEDManager Library
## Overview
The LEDManager library provides a flexible and easy-to-use interface for controlling LEDs in projects. It supports both addressable LED strips and individual non-addressable LEDs, offering various modes of operation such as static, blinking, and pulsing. The library is designed to work seamlessly with PlatformIO and can be easily configured using build flags.
## Features
- Support for both addressable LED strips and individual non-addressable LEDs
- Multiple operation modes: OFF, STATIC, BLINK, and PULSE
- Individual control of LEDs within each strip (for addressable LEDs)
- Global brightness control
- Queueing of LED states for complex sequences
- Automatic return to previous state after temporary modes
- Compatible with PlatformIO build flags for easy configuration
- Customizable color schemes
## Installation
1. Clone this repository or download the ZIP file.
2. Extract the contents to your PlatformIO project's `lib` directory.
## Configuration
Configure the LEDManager library using build flags in your `platformio.ini` file:
```ini
build_flags =
; For addressable LEDs:
-DLED_ADDRESSABLE=true
; For non-addressable LEDs, comment out the line above
; Optional timing configurations:
-DBLINK_INTERVAL=500
-DPULSE_INTERVAL=30
-DFADE_AMOUNT=5
```
## Usage
Here's a basic example of how to use the LEDManager library:
```cpp
#include "LEDManager.h"
LEDManager ledManager;
void setup() {
#ifdef LED_ADDRESSABLE
ledManager.addLEDStrip(5, 30); // Add addressable LED strip on pin 5 with 30 LEDs
#else
ledManager.addLEDStrip(5, 1); // Add non-addressable LED on pin 5
ledManager.addLEDStrip(6, 1); // Add non-addressable LED on pin 6
#endif
ledManager.setBrightness(128); // Set global brightness to 50%
}
void loop() {
#ifdef LED_ADDRESSABLE
// Set all LEDs on the strip to static green
ledManager.setMode(0, -1, LEDManager::STATIC, LED_COLOR_GREEN);
// Blink first 5 LEDs red for 3 times
for (int i = 0; i < 5; i++) {
ledManager.setMode(0, i, LEDManager::BLINK, LED_COLOR_RED, 3);
}
#else
// Set first LED to static green
ledManager.setMode(0, 0, LEDManager::STATIC, LED_COLOR_GREEN);
// Blink second LED red
ledManager.setMode(1, 0, LEDManager::BLINK, LED_COLOR_RED, 3);
#endif
ledManager.update();
delay(100);
}
```
## API Reference
### Initialization and Setup
```cpp
LEDManager ledManager;
ledManager.addLEDStrip(int pin, int numLeds);
```
### Setting LED Mode
```cpp
ledManager.setMode(int stripIndex, int ledIndex, Mode mode, uint32_t color, int durationOrBlinkCount = -1);
```
- `stripIndex`: Index of the LED strip (0-based)
- `ledIndex`: LED index within the strip (0-based) or -1 for all LEDs in the strip (addressable LEDs only)
- `mode`: `LEDManager::OFF`, `LEDManager::STATIC`, `LEDManager::BLINK`, or `LEDManager::PULSE`
- `color`: Color value (use predefined colors from LEDColorDefinitions.h or custom 24-bit RGB values)
- `durationOrBlinkCount`: Duration for STATIC mode (in milliseconds), blink/pulse count for BLINK/PULSE modes (-1 for infinite)
### Setting Brightness
```cpp
ledManager.setBrightness(brightness);
```
- `brightness`: Global brightness value (0-255)
### Updating LEDs
Call this method in your main loop to update LED states:
```cpp
ledManager.update();
```
## Advanced Configuration
You can customize the behavior of the LEDManager by defining the following build flags:
- `BLINK_INTERVAL`: Sets the interval (in milliseconds) between blink states (default: 500)
- `PULSE_INTERVAL`: Sets the interval (in milliseconds) between pulse updates (default: 30)
- `FADE_AMOUNT`: Sets the increment/decrement value for pulsing (default: 5)
## Contributing
Contributions to the LEDManager library are welcome! Please feel free to submit a Pull Request.
## License
This library is released under the LGPL V3 License.

View File

@@ -434,260 +434,84 @@ ss_cnt_parameters cnt_parameters_array[cnt_parameters_array_size] = {
# define ota_timeout_millis 30000
#endif
/*-------------ERRORS, INFOS, SEND RECEIVE Display through LED----------------*/
#ifndef RGB_INDICATORS // Management of Errors, reception/emission and informations indicators with basic LED
/*-------------DEFINE PINs FOR STATUS LEDs----------------*/
# ifndef LED_SEND_RECEIVE
# ifdef ESP8266
//# define LED_SEND_RECEIVE 40
# elif ESP32
//# define LED_SEND_RECEIVE 40
# endif
# endif
# ifndef LED_SEND_RECEIVE_ON
# define LED_SEND_RECEIVE_ON HIGH
# endif
# ifndef LED_ERROR
# ifdef ESP8266
//# define LED_ERROR 42
# elif ESP32
//# define LED_ERROR 42
# endif
# endif
# ifndef LED_ERROR_ON
# define LED_ERROR_ON HIGH
# endif
# ifndef RGB_LED_ON_ON
# define RGB_LED_ON_ON HIGH
# endif
# ifndef LED_INFO
# ifdef ESP8266
//# define LED_INFO 44
# elif ESP32
//# define LED_INFO 44
# endif
# endif
# ifndef LED_INFO_ON
# define LED_INFO_ON HIGH
# endif
# ifdef RGB_LED_ON
# define SetupIndicatorError() \
pinMode(RGB_LED_ON, OUTPUT);
# define ONIndicatorON() digitalWrite(RGB_LED_ON, RGB_LED_ON_ON)
# else
# define ONIndicatorON()
# endif
# ifdef LED_ERROR
# define SetupIndicatorError() \
pinMode(LED_ERROR, OUTPUT); \
ErrorIndicatorOFF();
# define ErrorIndicatorON() digitalWrite(LED_ERROR, LED_ERROR_ON)
# define ErrorIndicatorOFF() digitalWrite(LED_ERROR, !LED_ERROR_ON)
# else
# define SetupIndicatorError()
# define ErrorIndicatorON()
# define ErrorIndicatorOFF()
# endif
# ifdef LED_SEND_RECEIVE
# define SetupIndicatorSendReceive() \
pinMode(LED_SEND_RECEIVE, OUTPUT); \
SendReceiveIndicatorOFF();
# define SendReceiveIndicatorON() digitalWrite(LED_SEND_RECEIVE, LED_SEND_RECEIVE_ON)
# define SendReceiveIndicatorOFF() digitalWrite(LED_SEND_RECEIVE, !LED_SEND_RECEIVE_ON)
# else
# define SetupIndicatorSendReceive()
# define SendReceiveIndicatorON()
# define SendReceiveIndicatorOFF()
# endif
# ifdef LED_INFO
# define SetupIndicatorInfo() \
pinMode(LED_INFO, OUTPUT); \
InfoIndicatorOFF();
# define InfoIndicatorON() digitalWrite(LED_INFO, LED_INFO_ON)
# define InfoIndicatorOFF() digitalWrite(LED_INFO, !LED_INFO_ON)
# else
# define SetupIndicatorInfo()
# define InfoIndicatorON()
# define InfoIndicatorOFF()
# endif
# define CriticalIndicatorON() // Not used
# define PowerIndicatorON() // Not used
# define PowerIndicatorOFF() // Not used
# define SetupIndicators() // Not used
#else // Management of Errors, reception/emission and informations indicators with RGB LED
# include <Adafruit_NeoPixel.h>
# ifndef ANEOPIX_IND_TYPE // needs library constants
# define ANEOPIX_IND_TYPE NEO_GRB + NEO_KHZ800 // ws2812 and alike
# endif
Adafruit_NeoPixel leds(ANEOPIX_IND_NUM_LEDS, ANEOPIX_IND_DATA_GPIO, ANEOPIX_IND_TYPE);
# ifdef ANEOPIX_IND_DATA_GPIO2 // Only used for Critical Indicator
// assume the same LED type
Adafruit_NeoPixel leds2(ANEOPIX_IND_NUM_LEDS, ANEOPIX_IND_DATA_GPIO2, ANEOPIX_IND_TYPE);
# endif
# ifdef ANEOPIX_IND_DATA_GPIO3
// assume the same LED type
Adafruit_NeoPixel leds3(ANEOPIX_IND_NUM_LEDS, ANEOPIX_IND_DATA_GPIO3, ANEOPIX_IND_TYPE);
# endif
// LED index depending on state, each state can have a different LED index or be grouped if there is a limited number of LEDs
#ifndef LED_ERROR
# define LED_ERROR 0
#endif
#ifndef LED_PROCESSING
# define LED_PROCESSING 0
#endif
#ifndef LED_BROKER
# define LED_BROKER 0
#endif
#ifndef LED_NETWORK
# define LED_NETWORK 0
#endif
#ifndef LED_POWER
# define LED_POWER -1
#endif
# ifndef RGB_LED_POWER
# define RGB_LED_POWER -1 // If the RGB Led is linked to GPIO pin for power define it here
// Single standard LED pin
#ifndef LED_PIN
# ifdef LED_BUILTIN
# define LED_PIN LED_BUILTIN
# endif
# ifndef ANEOPIX_BRIGHTNESS
# define ANEOPIX_BRIGHTNESS 20 // Set Default maximum RGB brightness to approx 10% (0-255 scale)
#endif
#ifndef LED_PIN_ON
# define LED_PIN_ON HIGH
#endif
#ifndef LED_ACTUATOR_ONOFF
# ifdef LED_BUILTIN
# define LED_ACTUATOR_ONOFF LED_BUILTIN
# endif
# ifndef DEFAULT_ADJ_BRIGHTNESS
# define DEFAULT_ADJ_BRIGHTNESS 255 // Set Default RGB adjustable brightness
# endif
# ifndef ANEOPIX_COLOR_SCHEME // allow for different color combinations
# define ANEOPIX_COLOR_SCHEME 0
# endif
// Allow to set LED used (for example thingpulse gateway has 4 we use them independently)
# ifndef ANEOPIX_ON_LED
# define ANEOPIX_ON_LED 0 // First Led
# endif
# ifndef ANEOPIX_INFO_LED
# define ANEOPIX_INFO_LED 0 // First Led
# endif
# ifndef ANEOPIX_SEND_RECEIVE_LED
# define ANEOPIX_SEND_RECEIVE_LED 0 // First Led
# endif
# ifndef ANEOPIX_ERROR_LED
# define ANEOPIX_ERROR_LED 0 // First Led
# endif
# ifndef ANEOPIX_CRITICAL_LED
# define ANEOPIX_CRITICAL_LED 0 // First Led
# endif
// compile time calculation of color values
# define ANEOPIX_RED ((0xFF * ANEOPIX_BRIGHTNESS) >> 8) << 16
# define ANEOPIX_RED_DIM ((0x3F * ANEOPIX_BRIGHTNESS) >> 8) << 16 // dimmed /4
# define ANEOPIX_ORANGE (((0xFF * ANEOPIX_BRIGHTNESS) >> 8) << 16) | \
(((0xA5 * ANEOPIX_BRIGHTNESS) >> 8) << 8)
# define ANEOPIX_GOLD (((0xFF * ANEOPIX_BRIGHTNESS) >> 8) << 16) | \
(((0xD7 * ANEOPIX_BRIGHTNESS) >> 8) << 8)
# define ANEOPIX_GREEN ((0xFF * ANEOPIX_BRIGHTNESS) >> 8) << 8
# define ANEOPIX_GREEN_DIM ((0x3F * ANEOPIX_BRIGHTNESS) >> 8) << 8 // dimmed /4
# define ANEOPIX_AQUA (((0xFF * ANEOPIX_BRIGHTNESS) >> 8) << 8) | \
(0xFF * ANEOPIX_BRIGHTNESS) >> 8
# define ANEOPIX_BLUE (0xFF * ANEOPIX_BRIGHTNESS) >> 8
# define ANEOPIX_BLUE_DIM (0x3F * ANEOPIX_BRIGHTNESS) >> 8 // dimmed /4
# define ANEOPIX_BLACK 0
#endif
# if ANEOPIX_COLOR_SCHEME == 0
// original color combination remains default
# define ANEOPIX_INFO ANEOPIX_GREEN
# define ANEOPIX_ERROR ANEOPIX_ORANGE
# define ANEOPIX_SENDRECEIVE ANEOPIX_BLUE
# define ANEOPIX_CRITICAL ANEOPIX_RED // second led
# define ANEOPIX_POWER ANEOPIX_GREEN // second led
# define ANEOPIX_BOOT ANEOPIX_BLACK // unused
# define ANEOPIX_OFF ANEOPIX_BLACK
// color combinations tested for good visibility of onboard leds
# elif ANEOPIX_COLOR_SCHEME == 1
# define ANEOPIX_INFO ANEOPIX_GREEN_DIM // dimmed green info background
# define ANEOPIX_ERROR ANEOPIX_RED_DIM
# define ANEOPIX_SENDRECEIVE ANEOPIX_GOLD // bright gold = sending
# define ANEOPIX_CRITICAL ANEOPIX_BLACK // unused
# define ANEOPIX_POWER ANEOPIX_BLACK // unused
# define ANEOPIX_BOOT ANEOPIX_AQUA
# define ANEOPIX_OFF ANEOPIX_BLACK
# else
# define ANEOPIX_INFO ANEOPIX_BLUE_DIM // dimmed blue info background
# define ANEOPIX_ERROR ANEOPIX_RED_DIM
# define ANEOPIX_SENDRECEIVE ANEOPIX_GOLD // bright gold = sending
# define ANEOPIX_CRITICAL ANEOPIX_BLACK // unused
# define ANEOPIX_POWER ANEOPIX_BLACK // unused
# define ANEOPIX_BOOT ANEOPIX_AQUA
# define ANEOPIX_OFF ANEOPIX_BLACK
# endif
# if !defined(ANEOPIX_IND_DATA_GPIO2) && !defined(ANEOPIX_IND_DATA_GPIO3)
// during boot the RGB LED is on to signal also reboots
# define SetupIndicators() \
if (RGB_LED_POWER > -1) { \
pinMode(RGB_LED_POWER, OUTPUT); \
digitalWrite(RGB_LED_POWER, HIGH); \
} \
leds.begin(); \
leds.setPixelColor(ANEOPIX_INFO_LED, ANEOPIX_BOOT); \
leds.show();
# elif defined(ANEOPIX_IND_DATA_GPIO2) && !defined(ANEOPIX_IND_DATA_GPIO3)
# define SetupIndicators() \
if (RGB_LED_POWER > -1) { \
pinMode(RGB_LED_POWER, OUTPUT); \
digitalWrite(RGB_LED_POWER, HIGH); \
} \
leds.begin(); \
leds2.begin();
# else
# define SetupIndicators() \
if (RGB_LED_POWER > -1) { \
pinMode(RGB_LED_POWER, OUTPUT); \
digitalWrite(RGB_LED_POWER, HIGH); \
} \
leds.begin(); \
leds2.begin(); \
leds3.begin();
# endif
# ifndef RGB_LED_ERROR
# define RGB_LED_ERROR leds
# endif
# ifndef RGB_LED_SR
# define RGB_LED_SR leds
# endif
# ifndef RGB_LED_INFO
# define RGB_LED_INFO leds
# endif
# ifndef RGB_LED_ON
# define RGB_LED_ON leds
# endif
# define ONIndicatorON() \
RGB_LED_ON.setPixelColor(ANEOPIX_ON_LED, ANEOPIX_POWER); \
RGB_LED_ON.setBrightness(SYSConfig.rgbbrightness); \
RGB_LED_ON.show();
# define ErrorIndicatorON() \
RGB_LED_ERROR.setPixelColor(ANEOPIX_ERROR_LED, ANEOPIX_ERROR); \
RGB_LED_ERROR.setBrightness(SYSConfig.rgbbrightness); \
RGB_LED_ERROR.show();
# define ErrorIndicatorOFF() \
RGB_LED_ERROR.setPixelColor(ANEOPIX_ERROR_LED, ANEOPIX_OFF); \
RGB_LED_ERROR.show();
# define SendReceiveIndicatorON() \
RGB_LED_SR.setPixelColor(ANEOPIX_SEND_RECEIVE_LED, ANEOPIX_SENDRECEIVE); \
RGB_LED_SR.setBrightness(SYSConfig.rgbbrightness); \
RGB_LED_SR.show();
# define SendReceiveIndicatorOFF() \
RGB_LED_SR.setPixelColor(ANEOPIX_SEND_RECEIVE_LED, ANEOPIX_OFF); \
RGB_LED_SR.show();
# define InfoIndicatorON() \
RGB_LED_INFO.setPixelColor(ANEOPIX_INFO_LED, ANEOPIX_INFO); \
RGB_LED_INFO.setBrightness(SYSConfig.rgbbrightness); \
RGB_LED_INFO.show();
# define InfoIndicatorOFF() \
RGB_LED_INFO.setPixelColor(ANEOPIX_INFO_LED, ANEOPIX_OFF); \
RGB_LED_INFO.show();
# ifdef ANEOPIX_IND_DATA_GPIO2 // Used for relay power indicator
// For the critical ON indicator there is no method to turn it off, the only way is to unplug the device
// This enable to have persistence of the indicator to inform the user
# ifndef LED_CRITICAL
# define LED_CRITICAL leds2
# endif
# ifndef LED_POWER
# define LED_POWER leds2
# endif
# define CriticalIndicatorON() \
LED_CRITICAL.setPixelColor(ANEOPIX_INFO_LED, ANEOPIX_CRITICAL); \
LED_CRITICAL.setBrightness(255); \
LED_CRITICAL.show();
# define PowerIndicatorON() \
LED_POWER.setPixelColor(ANEOPIX_INFO_LED, ANEOPIX_INFO); \
LED_POWER.setBrightness(SYSConfig.rgbbrightness); \
LED_POWER.show();
# define PowerIndicatorOFF() \
LED_POWER.setPixelColor(ANEOPIX_INFO_LED, ANEOPIX_OFF); \
LED_POWER.show();
# endif
# define SetupIndicatorInfo()
# define SetupIndicatorSendReceive()
# define SetupIndicatorError()
// TODO adapt to other boards
#ifndef DEFAULT_ADJ_BRIGHTNESS
# define DEFAULT_ADJ_BRIGHTNESS 255 // Set Default RGB adjustable brightness
#endif
#ifndef LED_POWER_COLOR
# define LED_POWER_COLOR 0x00FF00 // Green
#endif
#ifndef LED_PROCESSING_COLOR
# define LED_PROCESSING_COLOR 0x0000FF // Blue
#endif
#ifndef LED_WAITING_ONBOARD_COLOR
# define LED_WAITING_ONBOARD_COLOR 0xFFA500 // Orange
#endif
#ifndef LED_ONBOARD_COLOR
# define LED_ONBOARD_COLOR 0xFFFF00 // Yellow
#endif
#ifndef LED_NETWORK_OK_COLOR
# define LED_NETWORK_OK_COLOR 0x00FF00 // Green
#endif
#ifndef LED_NETWORK_ERROR_COLOR
# define LED_NETWORK_ERROR_COLOR 0xFFA500 // Orange
#endif
#ifndef LED_BROKER_OK_COLOR
# define LED_BROKER_OK_COLOR 0x00FF00 // Green
#endif
#ifndef LED_BROKER_ERROR_COLOR
# define LED_BROKER_ERROR_COLOR 0xFFA500 // Orange
#endif
#ifndef LED_OFFLINE_COLOR
# define LED_OFFLINE_COLOR 0x0000FF // Blue
#endif
#ifndef LED_OTA_LOCAL_COLOR
# define LED_OTA_LOCAL_COLOR 0xFF00FF // Magenta
#endif
#ifndef LED_OTA_REMOTE_COLOR
# define LED_OTA_REMOTE_COLOR 0x8000FF // Purple
#endif
#ifndef LED_ERROR_COLOR
# define LED_ERROR_COLOR 0xFF0000 // Red
#endif
#ifndef LED_ACTUATOR_ONOFF_COLOR
# define LED_ACTUATOR_ONOFF_COLOR 0x00FF00 // Green
#endif
#ifndef LED_COLOR_BLACK
# define LED_COLOR_BLACK 0x000000
#endif
#ifdef ESP8266
@@ -827,7 +651,7 @@ struct SYSConfig_s {
bool offline;
bool discovery; // HA discovery convention
bool ohdiscovery; // OH discovery specificities
#ifdef RGB_INDICATORS
#ifdef LED_ADDRESSABLE
int rgbbrightness; // brightness of the RGB LED
#endif
enum PowerMode powerMode;

View File

@@ -100,11 +100,13 @@ void ONOFFConfig_load(){};
# endif
void updatePowerIndicator() {
# ifdef LED_ACTUATOR_ONOFF
if (digitalRead(ACTUATOR_ONOFF_GPIO) == ACTUATOR_ON) {
PowerIndicatorON();
ledManager.setMode(LED_ACTUATOR_ONOFF, 0, LEDManager::Mode::STATIC, LED_ACTUATOR_ONOFF_COLOR);
} else {
PowerIndicatorOFF();
ledManager.setMode(LED_ACTUATOR_ONOFF, 0, LEDManager::Mode::STATIC, LED_COLOR_BLACK);
}
# endif
}
void setupONOFF() {
@@ -142,11 +144,13 @@ void MQTTtoONOFF(char* topicOri, JsonObject& ONOFFdata) {
Log.notice(F("GPIO number: %d" CR), gpio);
pinMode(gpio, OUTPUT);
digitalWrite(gpio, boolSWITCHTYPE);
# ifdef LED_ACTUATOR_ONOFF
if (boolSWITCHTYPE == ACTUATOR_ON) {
PowerIndicatorON();
ledManager.setMode(LED_ACTUATOR_ONOFF, 0, LEDManager::Mode::STATIC, LED_ACTUATOR_ONOFF_COLOR);
} else {
PowerIndicatorOFF();
ledManager.setMode(LED_ACTUATOR_ONOFF, 0, LEDManager::Mode::STATIC, LED_COLOR_BLACK);
}
# endif
# ifdef ESP32
if (ONOFFConfig.useLastStateOnStart) {
ONOFFdata["save"] = true;
@@ -221,11 +225,13 @@ void MQTTtoONOFF(char* topicOri, char* datacallback) {
ON = false;
digitalWrite(gpio, ON);
# ifdef LED_ACTUATOR_ONOFF
if (ON == ACTUATOR_ON) {
PowerIndicatorON();
ledManager.setMode(LED_ACTUATOR_ONOFF, 0, LEDManager::Mode::STATIC, LED_ACTUATOR_ONOFF_COLOR);
} else {
PowerIndicatorOFF();
ledManager.setMode(LED_ACTUATOR_ONOFF, 0, LEDManager::Mode::STATIC, LED_COLOR_BLACK);
}
# endif
// we acknowledge the sending by publishing the value to an acknowledgement topic
char b = ON;
pub(subjectGTWONOFFtoMQTT, &b);
@@ -246,7 +252,9 @@ void overLimitTemp(void* pvParameters) {
if (digitalRead(ACTUATOR_ONOFF_GPIO) == ACTUATOR_ON) { // This could be with the previous condition, but it is better to trigger the digitalRead only if the previous condition is met to avoid the digitalRead
Log.error(F("[ActuatorONOFF] OverTemperature detected ( %F > %F ) switching OFF Actuator" CR), internalTempc, MAX_TEMP_ACTUATOR);
ActuatorTrigger();
CriticalIndicatorON();
# ifdef LED_ACTUATOR_ONOFF
ledManager.setMode(LED_ACTUATOR_ONOFF, 0, LEDManager::Mode::STATIC, LED_ERROR_COLOR, -1);
# endif
}
}
previousInternalTempc = internalTempc;
@@ -266,7 +274,9 @@ void overLimitCurrent(float RN8209current) {
if (digitalRead(ACTUATOR_ONOFF_GPIO) == ACTUATOR_ON) { // This could be with the previous condition, but it is better to trigger the digitalRead only if the previous condition is met to avoid the digitalRead
Log.error(F("[ActuatorONOFF] OverCurrent detected ( %F > %F ) switching OFF Actuator" CR), RN8209current, MAX_CURRENT_ACTUATOR);
ActuatorTrigger();
CriticalIndicatorON();
# ifdef LED_ACTUATOR_ONOFF
ledManager.setMode(LED_ACTUATOR_ONOFF, 0, LEDManager::Mode::STATIC, LED_ERROR_COLOR, -1);
# endif
}
}
RN8209previousCurrent = RN8209current;
@@ -284,11 +294,13 @@ void ActuatorTrigger() {
uint8_t level = !digitalRead(ACTUATOR_ONOFF_GPIO);
Log.trace(F("Actuator triggered %d" CR), level);
digitalWrite(ACTUATOR_ONOFF_GPIO, level);
# ifdef LED_ACTUATOR_ONOFF
if (level == ACTUATOR_ON) {
PowerIndicatorON();
ledManager.setMode(LED_ACTUATOR_ONOFF, 0, LEDManager::Mode::STATIC, LED_ACTUATOR_ONOFF_COLOR);
} else {
PowerIndicatorOFF();
ledManager.setMode(LED_ACTUATOR_ONOFF, 0, LEDManager::Mode::STATIC, LED_COLOR_BLACK);
}
# endif
# ifdef ESP32
if (ONOFFConfig.useLastStateOnStart) {

View File

@@ -203,6 +203,5 @@ void M5Print(char* line1, char* line2, char* line3) {
M5.Lcd.drawString(line2, 5, M5.Lcd.height() * 0.8, 1);
M5.Lcd.drawString(line3, 5, M5.Lcd.height() * 0.9, 1);
delay(2000);
InfoIndicatorOFF(); // to switch off no need of condition
}
#endif

View File

@@ -53,8 +53,13 @@ void testDevice() {
void testLeds() {
Log.notice(F("LED Test" CR));
InfoIndicatorON();
SendReceiveIndicatorON();
ledManager.setMode(0, 0, LEDManager::Mode::STATIC, LED_NETWORK_OK_COLOR, -1);
delay(1000);
ledManager.setMode(0, 1, LEDManager::Mode::STATIC, LED_NETWORK_OK_COLOR, -1);
delay(1000);
ledManager.setMode(0, 2, LEDManager::Mode::STATIC, LED_NETWORK_OK_COLOR, -1);
delay(1000);
ledManager.setMode(0, 3, LEDManager::Mode::STATIC, LED_NETWORK_OK_COLOR, -1);
Log.notice(F("LED Test Finished" CR));
}

View File

@@ -557,7 +557,7 @@ void pubMqttDiscovery() {
stateClassNone, //State Class
"false", "true" //state_off, state_on
);
# ifdef RGB_INDICATORS
# ifdef LED_ADDRESSABLE
createDiscovery("number", //set Type
subjectSYStoMQTT, "SYS: LED Brightness", (char*)getUniqueId("rgbb", "").c_str(), //set state_topic,name,uniqueId
will_Topic, "", "{{ (value_json.rgbb/2.55) | round(0) }}", //set availability_topic,device_class,value_template,

View File

@@ -64,8 +64,6 @@ void MeasureGPIOInput() {
resetTime = millis();
} else if ((millis() - resetTime) > 3000) {
Log.trace(F("Button Held" CR));
InfoIndicatorOFF();
SendReceiveIndicatorOFF();
// Switching off the relay during reset or failsafe operations
# ifdef ZactuatorONOFF
uint8_t level = digitalRead(ACTUATOR_ONOFF_GPIO);

View File

@@ -1937,7 +1937,7 @@ void webUIPubPrint(const char* topicori, JsonObject& data) {
// Queue completed message
if (xQueueSend(webUIQueue, (void*)&message, 0) != pdTRUE) {
Log.error(F("[ WebUI ] webUIQueue full, discarding signal %s" CR), message->title);
Log.warning(F("[ WebUI ] webUIQueue full, discarding signal %s" CR), message->title);
free(message);
} else {
// Log.notice(F("[ WebUI ] Queued %s" CR), message->title);
@@ -2003,7 +2003,7 @@ void webUIPubPrint(const char* topicori, JsonObject& data) {
// Queue completed message
if (xQueueSend(webUIQueue, (void*)&message, 0) != pdTRUE) {
Log.error(F("[ WebUI ] webUIQueue full, discarding signal %s" CR), message->title);
Log.warning(F("[ WebUI ] webUIQueue full, discarding signal %s" CR), message->title);
free(message);
} else {
// Log.notice(F("[ WebUI ] Queued %s" CR), message->title);
@@ -2331,7 +2331,7 @@ void webUIPubPrint(const char* topicori, JsonObject& data) {
line4.toCharArray(message->line4, WEBUI_TEXT_WIDTH);
if (xQueueSend(webUIQueue, (void*)&message, 0) != pdTRUE) {
Log.error(F("[ WebUI ] webUIQueue full, discarding signal %s" CR), message->title);
Log.warning(F("[ WebUI ] webUIQueue full, discarding signal %s" CR), message->title);
free(message);
} else {
// Log.notice(F("[ WebUI ] Queued %s" CR), message->title);
@@ -2389,7 +2389,7 @@ void webUIPubPrint(const char* topicori, JsonObject& data) {
// Queue completed message
if (xQueueSend(webUIQueue, (void*)&message, 0) != pdTRUE) {
Log.error(F("[ WebUI ] webUIQueue full, discarding signal %s" CR), message->title);
Log.warning(F("[ WebUI ] webUIQueue full, discarding signal %s" CR), message->title);
free(message);
} else {
// Log.notice(F("[ WebUI ] Queued %s" CR), message->title);
@@ -2441,7 +2441,7 @@ void webUIPubPrint(const char* topicori, JsonObject& data) {
// Queue completed message
if (xQueueSend(webUIQueue, (void*)&message, 0) != pdTRUE) {
Log.error(F("[ WebUI ] webUIQueue full, discarding signal %s" CR), message->title);
Log.warning(F("[ WebUI ] webUIQueue full, discarding signal %s" CR), message->title);
free(message);
} else {
// Log.notice(F("[ WebUI ] Queued %s" CR), message->title);

View File

@@ -38,7 +38,8 @@ enum GatewayState {
BROKER_DISCONNECTED,
LOCAL_OTA_IN_PROGRESS,
REMOTE_OTA_IN_PROGRESS,
SLEEPING
SLEEPING,
ERROR
};
GatewayState gatewayState = GatewayState::WAITING_ONBOARDING;
@@ -86,8 +87,11 @@ bool ready_to_sleep = false;
#include <memory>
#include "LEDManager.h"
#include "TheengsUtils.h"
LEDManager ledManager;
struct JsonBundle {
StaticJsonDocument<JSON_MSG_BUFFER> doc;
};
@@ -382,6 +386,8 @@ void Config_update(JsonObject& data, const char* key, T& var) {
bool jsonDispatch(JsonObject& data) {
bool res = false;
if (data.containsKey("origin")) {
GatewayState previousGatewayState = gatewayState;
gatewayState = GatewayState::PROCESSING;
#if message_UTCtimestamp == true
data["UTCtime"] = TheengsUtils::UTCtimestamp();
#endif
@@ -405,8 +411,10 @@ bool jsonDispatch(JsonObject& data) {
res = true;
}
#endif
gatewayState = previousGatewayState; // restore the previous state
} else {
Log.error(F("No origin in JSON filtered" CR));
gatewayState = GatewayState::ERROR;
}
return res;
}
@@ -416,6 +424,7 @@ boolean enqueueJsonObject(const StaticJsonDocument<JSON_MSG_BUFFER>& jsonDoc, in
receivedMessages++;
if (jsonDoc.size() == 0) {
Log.error(F("Empty JSON, skipping" CR));
gatewayState = GatewayState::ERROR;
return true;
}
if (queueLength >= QueueSize) {
@@ -430,6 +439,7 @@ boolean enqueueJsonObject(const StaticJsonDocument<JSON_MSG_BUFFER>& jsonDoc, in
// Semaphore check before enqueueing a document
if (xSemaphoreTake(xQueueMutex, pdMS_TO_TICKS(timeout)) == pdFALSE) {
Log.error(F("xQueueMutex not taken" CR));
gatewayState = GatewayState::ERROR;
blockedMessages++;
return false;
}
@@ -474,6 +484,7 @@ std::string generateHash(const std::string& input) {
void buildTopicFromId(JsonObject& Jsondata, const char* origin) {
if (!Jsondata.containsKey("id")) {
Log.error(F("No id in Jsondata" CR));
gatewayState = GatewayState::ERROR;
return;
}
@@ -491,6 +502,7 @@ void buildTopicFromId(JsonObject& Jsondata, const char* origin) {
topic = Jsondata["uuid"].as<std::string>();
} else {
Log.error(F("No uuid in Jsondata" CR));
gatewayState = GatewayState::ERROR;
}
}
@@ -520,6 +532,7 @@ void emptyQueue() {
#ifdef ESP32
if (xSemaphoreTake(xQueueMutex, pdMS_TO_TICKS(QueueSemaphoreTimeOutTask)) == pdFALSE) {
Log.error(F("xQueueMutex not taken" CR));
gatewayState = GatewayState::ERROR;
return;
}
#endif
@@ -530,6 +543,7 @@ void emptyQueue() {
#endif
if (error) {
Log.error(F("deserialize jsonQueue.front() failed: %s, buffer capacity: %u" CR), error.c_str(), jsonBuffer.capacity());
gatewayState = GatewayState::ERROR;
} else {
if (jsonDispatch(obj))
queueLengthSum++;
@@ -566,6 +580,7 @@ bool pub(const char* topicori, JsonObject& data) {
}
if (data.size() == 0) {
Log.error(F("Empty JSON, not published" CR));
gatewayState = GatewayState::ERROR;
return res;
}
String topic = String(mqtt_topic) + String(gateway_name) + String(topicori);
@@ -662,11 +677,11 @@ bool pubMQTT(const char* topic, const char* payload, bool retainFlag) {
#ifdef ESP32
if (xSemaphoreTake(xMqttMutex, pdMS_TO_TICKS(QueueSemaphoreTimeOutTask)) == pdFALSE) {
Log.error(F("xMqttMutex not taken" CR));
gatewayState = GatewayState::ERROR;
return res;
}
#endif
if (mqtt && mqtt->connected()) {
SendReceiveIndicatorON();
Log.notice(F("[ OMG->MQTT ] topic: %s msg: %s " CR), topic, payload);
res = mqtt->publish(topic, payload, 0, retainFlag);
} else {
@@ -784,7 +799,7 @@ void SYSConfig_init() {
SYSConfig.discovery = DEFAULT_DISCOVERY;
SYSConfig.ohdiscovery = OpenHABDiscovery;
#endif
#ifdef RGB_INDICATORS
#ifdef LED_ADDRESSABLE
SYSConfig.rgbbrightness = DEFAULT_ADJ_BRIGHTNESS;
#endif
SYSConfig.powerMode = DEFAULT_LOW_POWER_MODE;
@@ -798,7 +813,7 @@ void SYSConfig_fromJson(JsonObject& SYSdata) {
Config_update(SYSdata, "disc", SYSConfig.discovery);
Config_update(SYSdata, "ohdisc", SYSConfig.ohdiscovery);
#endif
#ifdef RGB_INDICATORS
#ifdef LED_ADDRESSABLE
Config_update(SYSdata, "rgbb", SYSConfig.rgbbrightness);
#endif
Config_update(SYSdata, "powermode", SYSConfig.powerMode);
@@ -816,7 +831,7 @@ void SYSConfig_save() {
SYSdata["disc"] = SYSConfig.discovery;
SYSdata["ohdisc"] = SYSConfig.ohdiscovery;
# endif
# ifdef RGB_INDICATORS
# ifdef LED_ADDRESSABLE
SYSdata["rgbb"] = SYSConfig.rgbbrightness;
# endif
String conf = "";
@@ -855,6 +870,7 @@ void SYSConfig_load() {
preferences.end();
if (error) {
Log.error(F("SYS config deserialization failed: %s, buffer capacity: %u" CR), error.c_str(), jsonBuffer.capacity());
gatewayState = GatewayState::ERROR;
return;
}
if (jsonBuffer.isNull()) {
@@ -878,7 +894,7 @@ std::pair<String, uint16_t> discoverMQTTbroker() {
Log.trace(F("Browsing for MQTT service" CR));
int n = MDNS.queryService("mqtt", "tcp");
if (n == 0) {
Log.error(F("no services found" CR));
Log.warning(F("no services found" CR));
} else {
Log.trace(F("%d service(s) found" CR), n);
for (int i = 0; i < n; ++i) {
@@ -889,7 +905,7 @@ std::pair<String, uint16_t> discoverMQTTbroker() {
Log.trace(F("One MQTT server found setting parameters" CR));
return {MDNS.IP(0).toString(), uint16_t(MDNS.port(0))};
} else {
Log.error(F("Several MQTT servers found, please deactivate mDNS and set your default server" CR));
Log.warning(F("Several MQTT servers found, please deactivate mDNS and set your default server" CR));
}
}
return {"", 0};
@@ -1043,6 +1059,7 @@ void setupMQTT() {
if (cnt_parameters_backup) {
// this was the first attempt to connect to a new server and it failed, revert to old settings
Log.error(F("MQTT connection failed, reverting to previous settings" CR));
gatewayState = GatewayState::ERROR;
cnt_parameters_array[cnt_index] = cnt_parameters_backup->parameters;
cnt_index = cnt_parameters_backup->cnt_index;
mqttSetupPending = true;
@@ -1051,10 +1068,7 @@ void setupMQTT() {
return;
}
ErrorIndicatorON();
delayWithOTA(5000);
ErrorIndicatorOFF();
delayWithOTA(5000);
delayWithOTA(10000);
if (failure_number_mqtt > maxRetryWatchDog) {
# ifndef ESPWifiManualSetup
@@ -1114,12 +1128,14 @@ void setESPWifiProtocolTxPower() {
# if WifiGMode == true
if (esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G) != ESP_OK) {
Log.error(F("Failed to change WifiMode." CR));
gatewayState = GatewayState::ERROR;
}
# endif
# if WifiGMode == false
if (esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N) != ESP_OK) {
Log.error(F("Failed to change WifiMode." CR));
gatewayState = GatewayState::ERROR;
}
# endif
@@ -1153,12 +1169,14 @@ void setESPWifiProtocolTxPower() {
# if WifiGMode == true
if (!wifi_set_phy_mode(PHY_MODE_11G)) {
Log.error(F("Failed to change WifiMode." CR));
gatewayState = GatewayState::ERROR;
}
# endif
# if WifiGMode == false
if (!wifi_set_phy_mode(PHY_MODE_11N)) {
Log.error(F("Failed to change WifiMode." CR));
gatewayState = GatewayState::ERROR;
}
# endif
@@ -1190,6 +1208,88 @@ void setESPWifiProtocolTxPower() {
}
#endif
#ifdef ESP32
void updateAndHandleLEDsTask(void* pvParameters) {
for (;;) {
updateAndHandleLEDsTask();
vTaskDelay(pdMS_TO_TICKS(100));
}
}
#endif
void updateAndHandleLEDsTask() {
static GatewayState previousGatewayState;
if (previousGatewayState != gatewayState) {
#ifdef LED_POWER
ledManager.setMode(0, LED_POWER, LEDManager::STATIC, LED_POWER_COLOR, -1);
#endif
switch (gatewayState) {
case PROCESSING:
#ifdef LED_PROCESSING
ledManager.setMode(0, LED_PROCESSING, LEDManager::BLINK, LED_PROCESSING_COLOR, 3);
#endif
break;
case WAITING_ONBOARDING:
#ifdef LED_BROKER
ledManager.setMode(0, LED_BROKER, LEDManager::STATIC, LED_WAITING_ONBOARD_COLOR, -1);
#endif
break;
case ONBOARDING:
#ifdef LED_BROKER
ledManager.setMode(0, LED_BROKER, LEDManager::STATIC, LED_ONBOARD_COLOR, -1);
#endif
break;
case NTWK_CONNECTED:
#ifdef LED_NETWORK
ledManager.setMode(0, LED_NETWORK, LEDManager::STATIC, LED_NETWORK_OK_COLOR, -1);
#endif
break;
case BROKER_CONNECTED:
#ifdef LED_BROKER
ledManager.setMode(0, LED_BROKER, LEDManager::STATIC, LED_BROKER_OK_COLOR, -1);
#endif
break;
case NTWK_DISCONNECTED:
#ifdef LED_NETWORK
ledManager.setMode(0, LED_NETWORK, LEDManager::BLINK, LED_NETWORK_ERROR_COLOR, -1);
#endif
break;
case BROKER_DISCONNECTED:
#ifdef LED_BROKER
ledManager.setMode(0, LED_BROKER, LEDManager::BLINK, LED_BROKER_ERROR_COLOR, -1);
#endif
break;
case SLEEPING:
ledManager.setMode(0, -1, LEDManager::OFF, 0, -1);
break;
case OFFLINE:
#ifdef LED_NETWORK
ledManager.setMode(0, LED_NETWORK, LEDManager::BLINK, LED_OFFLINE_COLOR, -1);
#endif
break;
case LOCAL_OTA_IN_PROGRESS:
#ifdef LED_PROCESSING
ledManager.setMode(0, LED_PROCESSING, LEDManager::BLINK, LED_OTA_LOCAL_COLOR, -1);
#endif
break;
case REMOTE_OTA_IN_PROGRESS:
#ifdef LED_PROCESSING
ledManager.setMode(0, LED_PROCESSING, LEDManager::BLINK, LED_OTA_REMOTE_COLOR, -1);
#endif
break;
case ERROR:
#ifdef LED_ERROR
ledManager.setMode(0, LED_ERROR, LEDManager::BLINK, LED_ERROR_COLOR, 3);
#endif
break;
default:
break;
}
previousGatewayState = gatewayState;
}
ledManager.update();
}
void setup() {
//Launch serial for debugging purposes
Serial.begin(SERIAL_BAUD);
@@ -1208,12 +1308,17 @@ void setup() {
if (SYSConfig.offline)
gatewayState = GatewayState::OFFLINE;
//setup LED status
SetupIndicatorError();
SetupIndicatorSendReceive();
SetupIndicatorInfo();
SetupIndicators(); // For RGB Leds
ONIndicatorON();
#ifdef LED_ADDRESSABLE
# ifdef LED_ADDRESSABLE_PIN1
ledManager.addLEDStrip(LED_ADDRESSABLE_PIN1, LED_ADDRESSABLE_NUM);
# endif
# ifdef LED_ADDRESSABLE_PIN2
ledManager.addLEDStrip(LED_ADDRESSABLE_PIN2, LED_ADDRESSABLE_NUM);
# endif
ledManager.setBrightness(SYSConfig.rgbbrightness);
#elif LED_PIN
ledManager.addLEDStrip(LED_PIN, 1);
#endif
#ifdef ESP8266
# ifndef ZgatewaySRFB // if we are not in sonoff rf bridge case we apply the ESP8266 GPIO optimization
@@ -1221,6 +1326,7 @@ void setup() {
Serial.begin(SERIAL_BAUD, SERIAL_8N1, SERIAL_TX_ONLY); // enable on ESP8266 to free some pin
# endif
#elif ESP32
xTaskCreate(updateAndHandleLEDsTask, "updateAndHandleLEDsTask", 2500, NULL, 1, NULL);
xQueueMutex = xSemaphoreCreateMutex();
xMqttMutex = xSemaphoreCreateMutex();
# if defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5STACK) || defined(ZboardM5TOUGH)
@@ -1239,6 +1345,7 @@ void setup() {
gpio_num_t wake_pin0 = static_cast<gpio_num_t>(ESP32_EXT0_WAKE_PIN);
if (esp_sleep_enable_ext0_wakeup(wake_pin0, ESP32_EXT0_WAKE_PIN_STATE) != ESP_OK) {
Log.error(F("Failed to set deep sleep EXT0 Wakeup." CR));
gatewayState = GatewayState::ERROR;
}
#endif
#ifdef ESP32_EXT1_WAKE_PIN
@@ -1247,6 +1354,7 @@ void setup() {
esp_sleep_ext1_wakeup_mode_t wake_state1 = static_cast<esp_sleep_ext1_wakeup_mode_t>(ESP32_EXT1_WAKE_PIN_STATE);
if (esp_sleep_enable_ext1_wakeup(wake_pin_bitmask, wake_state1) != ESP_OK) {
Log.error(F("Failed to set deep sleep EXT1 Wakeup." CR));
gatewayState = GatewayState::ERROR;
}
#endif
#ifdef ESP32
@@ -1526,8 +1634,6 @@ void setOTA() {
ArduinoOTA.onStart([]() {
Log.trace(F("Start OTA, lock other functions" CR));
ErrorIndicatorON();
SendReceiveIndicatorON();
last_ota_activity_millis = millis();
#ifdef ESP32
ProcessLock = true;
@@ -1540,24 +1646,18 @@ void setOTA() {
ArduinoOTA.onEnd([]() {
Log.trace(F("\nOTA done" CR));
last_ota_activity_millis = 0;
ErrorIndicatorOFF();
SendReceiveIndicatorOFF();
lpDisplayPrint("OTA done");
ESPRestart(6);
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Log.trace(F("Progress: %u%%\r" CR), (progress / (total / 100)));
gatewayState = GatewayState::LOCAL_OTA_IN_PROGRESS;
#ifdef ESP32
//esp_task_wdt_reset();
#endif
last_ota_activity_millis = millis();
});
ArduinoOTA.onError([](ota_error_t error) {
last_ota_activity_millis = millis();
ErrorIndicatorOFF();
SendReceiveIndicatorOFF();
Serial.printf("Error[%u]: ", error);
gatewayState = GatewayState::ERROR;
if (error == OTA_AUTH_ERROR)
Log.error(F("Auth Failed" CR));
else if (error == OTA_BEGIN_ERROR)
@@ -1592,6 +1692,7 @@ void setupTLS(int index) {
Log.notice(F("Server cert found from ss_server_cert" CR));
} else {
Log.error(F("No server cert found" CR));
gatewayState = GatewayState::ERROR;
}
# if AWS_IOT
@@ -1609,6 +1710,7 @@ void setupTLS(int index) {
Log.notice(F("Client cert found from ss_client_cert" CR));
} else {
Log.error(F("No client cert found" CR));
gatewayState = GatewayState::ERROR;
}
if (cnt_parameters_array[index].client_key.length() > MIN_CERT_LENGTH) {
sClient->setPrivateKey(cnt_parameters_array[index].client_key.c_str());
@@ -1618,6 +1720,7 @@ void setupTLS(int index) {
Log.notice(F("Client key found from ss_client_key" CR));
} else {
Log.error(F("No client key found" CR));
gatewayState = GatewayState::ERROR;
}
# endif
# elif defined(ESP8266)
@@ -1696,6 +1799,7 @@ void setup_wifi() {
if (!WiFi.config(ip_adress, gateway_adress, subnet_adress, dns_adress)) {
Log.error(F("Wifi STA Failed to configure" CR));
gatewayState = GatewayState::ERROR;
}
# endif
@@ -1757,11 +1861,6 @@ void blockingWaitForReset() {
ActuatorTrigger();
}
# endif
# ifdef ESP32
//esp_task_wdt_delete(NULL);
# endif
InfoIndicatorOFF();
SendReceiveIndicatorOFF();
// Checking if the flash has already been erased to identify if we erase it or go into failsafe mode
// going to failsafe mode is done by doing a long button press from a state where the flash has already been erased
if (SPIFFS.begin()) {
@@ -1892,6 +1991,7 @@ void saveConfig() {
File configFile = SPIFFS.open("/config.json", "w");
if (!configFile) {
Log.error(F("failed to open config file for writing" CR));
gatewayState = GatewayState::ERROR;
}
serializeJson(json, configFile);
@@ -1920,6 +2020,7 @@ bool loadConfigFromFlash() {
auto error = deserializeJson(json, configFile);
if (error) {
Log.error(F("deserialize config failed: %s, buffer capacity: %u" CR), error.c_str(), json.capacity());
gatewayState = GatewayState::ERROR;
}
if (!json.isNull()) {
Log.trace(F("\nparsed json, size: %u" CR), json.memoryUsage());
@@ -2155,8 +2256,6 @@ void setupwifi(bool reset_settings) {
if (!SYSConfig.offline && !wifi_reconnect_bypass()) // if we didn't connect with saved credential we start Wifimanager web portal
{
InfoIndicatorON();
ErrorIndicatorON();
Log.notice(F("Connect your phone to WIFI AP: %s with PWD: %s" CR), WifiManager_ssid, ota_pass);
gatewayState = GatewayState::ONBOARDING;
//fetches ssid and pass and tries to connect
@@ -2189,11 +2288,10 @@ void setupwifi(bool reset_settings) {
ESPRestart(3);
}
}
InfoIndicatorOFF();
ErrorIndicatorOFF();
}
displayPrint("Network connected");
gatewayState = GatewayState::NTWK_CONNECTED;
if (shouldSaveConfig) {
//read updated parameters
@@ -2276,6 +2374,7 @@ void setup_ethernet_esp32() {
}
} else {
Log.error(F("Ethernet not started" CR));
gatewayState = GatewayState::ERROR;
}
}
@@ -2296,11 +2395,11 @@ void WiFiEvent(WiFiEvent_t event) {
ethConnected = true;
break;
case ARDUINO_EVENT_ETH_DISCONNECTED:
Log.error(F("Ethernet Disconnected" CR));
Log.warning(F("Ethernet Disconnected" CR));
ethConnected = false;
break;
case ARDUINO_EVENT_ETH_STOP:
Log.error(F("Ethernet Stopped" CR));
Log.warning(F("Ethernet Stopped" CR));
ethConnected = false;
break;
default:
@@ -2357,8 +2456,8 @@ void loop() {
checkButton(); // check if a reset of wifi/mqtt settings is asked
#endif
#ifdef ESP32
//esp_task_wdt_reset();
#ifdef ESP8266
updateAndHandleLEDsTask(); // With ESP8266 we need to update the LEDs in the loop
#endif
if (!SYSConfig.offline) {
if (mqttSetupPending) {
@@ -2372,8 +2471,6 @@ void loop() {
// Switch off of the LED after TimeLedON
if (now > (timer_led_measures + (TimeLedON * 1000))) {
timer_led_measures = millis();
InfoIndicatorOFF();
SendReceiveIndicatorOFF();
}
if (ethConnected || WiFi.status() == WL_CONNECTED) {
@@ -2387,7 +2484,6 @@ void loop() {
#endif
mqtt->loop();
if (mqtt->connected()) { // MQTT client is still connected
InfoIndicatorON();
failure_number_ntwk = 0;
#ifdef ZmqttDiscovery
@@ -2435,20 +2531,13 @@ void loop() {
}
}
} else if (!SYSConfig.offline) { // disconnected from network
#ifdef ESP32
//esp_task_wdt_reset();
#endif
Log.warning(F("Network disconnected" CR));
gatewayState = GatewayState::NTWK_DISCONNECTED;
ErrorIndicatorON();
delay(2000); // add a delay to avoid ESP32 crash and reset
#ifdef ESP32
//esp_task_wdt_reset();
#endif
ErrorIndicatorOFF();
delay(2000);
if (!wifi_reconnect_bypass())
if (!wifi_reconnect_bypass()) {
sleep();
} else {
gatewayState = GatewayState::NTWK_CONNECTED;
}
}
// Function that doesn't need an active connection
#if defined(ZboardM5STICKC) || defined(ZboardM5STICKCP) || defined(ZboardM5STACK) || defined(ZboardM5TOUGH)
@@ -2641,7 +2730,7 @@ String stateMeasures() {
SYSdata["uptime"] = uptime();
SYSdata["version"] = OMG_VERSION;
#ifdef RGB_INDICATORS
#ifdef LED_ADDRESSABLE
SYSdata["rgbb"] = SYSConfig.rgbbrightness;
#endif
#ifdef ZmqttDiscovery
@@ -2656,6 +2745,7 @@ String stateMeasures() {
// Some RTL_433 decoders have memory leak, this is a temporary workaround
if (freeMem < MinimumMemory) {
Log.error(F("Not enough memory %d, restarting" CR), freeMem);
gatewayState = GatewayState::ERROR;
ESPRestart(8);
}
#endif
@@ -2796,6 +2886,7 @@ void receivingMQTT(char* topicOri, char* datacallback) {
auto error = deserializeJson(jsonBuffer, datacallback);
if (error) {
Log.error(F("deserialize MQTT data failed: %s" CR), error.c_str());
gatewayState = GatewayState::ERROR;
return;
}
@@ -2873,7 +2964,6 @@ void receivingMQTT(char* topicOri, char* datacallback) {
MQTTtoWebUI(topicOri, jsondata);
# endif
#endif
SendReceiveIndicatorON();
MQTTtoSYS(topicOri, jsondata);
} else { // not a json object --> simple decoding
@@ -2950,11 +3040,13 @@ bool checkForUpdates() {
auto error = deserializeJson(jsonBuffer, payload);
if (error) {
Log.error(F("Deserialize MQTT data failed: %s" CR), error.c_str());
gatewayState = GatewayState::ERROR;
}
Log.trace(F("HttpCode %d" CR), httpCode);
Log.trace(F("Payload %s" CR), payload.c_str());
} else {
Log.error(F("Error on HTTP request"));
gatewayState = GatewayState::ERROR;
}
http.end(); //Free the resources
Log.notice(F("Update check done, free heap: %d"), ESP.getFreeHeap());
@@ -2994,6 +3086,7 @@ void MQTTHttpsFWUpdate(char* topicOri, JsonObject& HttpsFwUpdateData) {
if (url) {
if (!strstr((url + (strlen(url) - 5)), ".bin")) {
Log.error(F("Invalid firmware extension" CR));
gatewayState = GatewayState::ERROR;
return;
}
# if MQTT_HTTPS_FW_UPDATE_USE_PASSWORD > 0
@@ -3001,10 +3094,12 @@ void MQTTHttpsFWUpdate(char* topicOri, JsonObject& HttpsFwUpdateData) {
if (pwd) {
if (strcmp(pwd, ota_pass) != 0) {
Log.error(F("Invalid OTA password" CR));
gatewayState = GatewayState::ERROR;
return;
}
} else {
Log.error(F("No password sent" CR));
gatewayState = GatewayState::ERROR;
return;
}
# endif
@@ -3024,11 +3119,11 @@ void MQTTHttpsFWUpdate(char* topicOri, JsonObject& HttpsFwUpdateData) {
# endif
} else {
Log.error(F("Invalid URL" CR));
gatewayState = GatewayState::ERROR;
return;
}
# ifdef ESP32
ProcessLock = true;
//esp_task_wdt_delete(NULL); // Stop task watchdog during update
# ifdef ZgatewayBT
stopProcessing();
# endif
@@ -3036,8 +3131,6 @@ void MQTTHttpsFWUpdate(char* topicOri, JsonObject& HttpsFwUpdateData) {
Log.warning(F("Starting firmware update" CR));
gatewayState = GatewayState::REMOTE_OTA_IN_PROGRESS;
SendReceiveIndicatorON();
ErrorIndicatorON();
StaticJsonDocument<JSON_MSG_BUFFER> jsondata;
jsondata["release_summary"] = "Update in progress ...";
jsondata["origin"] = subjectRLStoMQTT;
@@ -3106,6 +3199,7 @@ void MQTTHttpsFWUpdate(char* topicOri, JsonObject& HttpsFwUpdateData) {
# elif ESP8266
Log.error(F("HTTP_UPDATE_FAILED Error (%d): %s\n" CR), ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
# endif
gatewayState = GatewayState::ERROR;
break;
case HTTP_UPDATE_NO_UPDATES:
@@ -3129,9 +3223,6 @@ void MQTTHttpsFWUpdate(char* topicOri, JsonObject& HttpsFwUpdateData) {
break;
}
SendReceiveIndicatorOFF();
ErrorIndicatorOFF();
ESPRestart(6);
}
}
@@ -3144,7 +3235,7 @@ void MQTTHttpsFWUpdate(char* topicOri, JsonObject& HttpsFwUpdateData) {
*/
void readCntParameters(int index) {
if (index < 0 || index > 2) {
Log.error(F("Invalid cnt index" CR));
Log.warning(F("Invalid cnt index" CR));
return;
}
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
@@ -3191,19 +3282,18 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding
stateMeasures();
}
}
#ifdef RGB_INDICATORS
#ifdef LED_ADDRESSABLE
if (SYSdata.containsKey("rgbb") && SYSdata["rgbb"].is<float>()) {
if (SYSdata["rgbb"] >= 0 && SYSdata["rgbb"] <= 255) {
SYSConfig.rgbbrightness = TheengsUtils::round2(SYSdata["rgbb"]);
leds.setBrightness(SYSConfig.rgbbrightness);
leds.show();
ledManager.setBrightness(SYSConfig.rgbbrightness);
# ifdef ZactuatorONOFF
updatePowerIndicator();
# endif
Log.notice(F("RGB brightness: %d" CR), SYSConfig.rgbbrightness);
stateMeasures();
} else {
Log.error(F("RGB brightness value invalid - ignoring command" CR));
Log.warning(F("RGB brightness value invalid - ignoring command" CR));
}
}
#endif
@@ -3234,7 +3324,7 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding
WiFi.waitForConnectResult(WiFi_TimeOut * 1000);
if (WiFi.status() != WL_CONNECTED) {
Log.error(F("Failed to connect to new AP; falling back" CR));
Log.warning(F("Failed to connect to new AP; falling back" CR));
WiFi.disconnect(true);
WiFi.begin(prev_ssid.c_str(), prev_pass.c_str());
#if defined(WifiGMode) || defined(WifiPower)
@@ -3290,7 +3380,7 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding
if (SYSdata.containsKey("cnt_index") && SYSdata["cnt_index"].is<int>()) {
if (SYSdata["cnt_index"].as<int>() < 0 || SYSdata["cnt_index"].as<int>() > 2) {
Log.error(F("Invalid cnt index provided - ignoring command" CR));
Log.warning(F("Invalid cnt index provided - ignoring command" CR));
return;
}
@@ -3413,7 +3503,7 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding
if (SYSConfig.discovery)
pubMqttDiscovery();
} else {
Log.error(F("Discovery command not a boolean" CR));
Log.warning(F("Discovery command not a boolean" CR));
}
Log.notice(F("Discovery state: %T" CR), SYSConfig.discovery);
}