Status LED's: Implemented
They can be activated using device profiles.
This commit is contained in:
parent
df468086e4
commit
ae323cd26f
@ -103,3 +103,5 @@ The json file can contain multiple profiles. Each profile requires a name and di
|
||||
| display.clk | number | Clock Pin (e.g. SCL for i2c displays) required for SSD1306 and SH1106. Use 255 for not assigned pins. |
|
||||
| display.cs | number | Chip Select Pin required for PCD8544. Use 255 for not assigned pins. |
|
||||
| display.reset | number | Reset Pin required for PCD8544, optional for all other displays. Use 255 for not assigned pins. |
|
||||
| led.led0 | number | LED pin for network indication. Blinking = WLAN connected but NTP & MQTT (if enabled) disconnected. On = WLAN, NTP, MQTT connected. Off = Network not connected |
|
||||
| led.led1 | number | LED pin for inverter indication. On = All inverters reachable & producing. Blinking = All inverters reachable but not producing. Off = At least one inverter is not reachable. Only inverters with polling enabled are considered. |
|
||||
35
include/Led_Single.h
Normal file
35
include/Led_Single.h
Normal file
@ -0,0 +1,35 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include "PinMapping.h"
|
||||
#include <TimeoutHelper.h>
|
||||
|
||||
#define LEDSINGLE_UPDATE_INTERVAL 2000
|
||||
|
||||
enum eLedFunction {
|
||||
CONNECTED_NETWORK,
|
||||
CONNECTED_MQTT,
|
||||
INV_REACHABLE,
|
||||
INV_PRODUCING,
|
||||
};
|
||||
|
||||
class LedSingleClass {
|
||||
public:
|
||||
LedSingleClass();
|
||||
void init();
|
||||
void loop();
|
||||
|
||||
private:
|
||||
enum class LedState_t {
|
||||
On,
|
||||
Off,
|
||||
Blink,
|
||||
};
|
||||
|
||||
LedState_t _ledState[PINMAPPING_LED_COUNT];
|
||||
TimeoutHelper _updateTimeout;
|
||||
TimeoutHelper _blinkTimeout;
|
||||
uint8_t _ledActive = 0;
|
||||
};
|
||||
|
||||
extern LedSingleClass LedSingle;
|
||||
@ -6,6 +6,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define PINMAPPING_FILENAME "/pin_mapping.json"
|
||||
#define PINMAPPING_LED_COUNT 2
|
||||
|
||||
#define MAPPING_NAME_STRLEN 31
|
||||
|
||||
@ -29,6 +30,7 @@ struct PinMapping_t {
|
||||
uint8_t display_clk;
|
||||
uint8_t display_cs;
|
||||
uint8_t display_reset;
|
||||
int8_t led[PINMAPPING_LED_COUNT];
|
||||
};
|
||||
|
||||
class PinMappingClass {
|
||||
|
||||
110
src/Led_Single.cpp
Normal file
110
src/Led_Single.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2023 Thomas Basler and others
|
||||
*/
|
||||
#include "Led_Single.h"
|
||||
#include "Configuration.h"
|
||||
#include "MqttSettings.h"
|
||||
#include "NetworkSettings.h"
|
||||
#include "PinMapping.h"
|
||||
#include <Hoymiles.h>
|
||||
|
||||
LedSingleClass LedSingle;
|
||||
|
||||
LedSingleClass::LedSingleClass()
|
||||
{
|
||||
}
|
||||
|
||||
void LedSingleClass::init()
|
||||
{
|
||||
_blinkTimeout.set(500);
|
||||
_updateTimeout.set(LEDSINGLE_UPDATE_INTERVAL);
|
||||
|
||||
for (uint8_t i = 0; i < PINMAPPING_LED_COUNT; i++) {
|
||||
auto& pin = PinMapping.get();
|
||||
|
||||
if (pin.led[i] >= 0) {
|
||||
pinMode(pin.led[i], OUTPUT);
|
||||
digitalWrite(pin.led[i], LOW);
|
||||
_ledActive++;
|
||||
}
|
||||
|
||||
_ledState[i] = LedState_t::Off;
|
||||
}
|
||||
}
|
||||
|
||||
void LedSingleClass::loop()
|
||||
{
|
||||
if (_ledActive == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_updateTimeout.occured()) {
|
||||
const CONFIG_T& config = Configuration.get();
|
||||
|
||||
// Update network status
|
||||
_ledState[0] = LedState_t::Off;
|
||||
|
||||
if (NetworkSettings.isConnected()) {
|
||||
_ledState[0] = LedState_t::Blink;
|
||||
}
|
||||
|
||||
struct tm timeinfo;
|
||||
if (getLocalTime(&timeinfo, 5) && (!config.Mqtt_Enabled || (config.Mqtt_Enabled && MqttSettings.getConnected()))) {
|
||||
_ledState[0] = LedState_t::On;
|
||||
}
|
||||
|
||||
// Update inverter status
|
||||
_ledState[1] = LedState_t::Off;
|
||||
if (Hoymiles.getNumInverters()) {
|
||||
bool allReachable = true;
|
||||
bool allProducing = true;
|
||||
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
||||
auto inv = Hoymiles.getInverterByPos(i);
|
||||
if (inv == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (inv->getEnablePolling()) {
|
||||
if (!inv->isReachable()) {
|
||||
allReachable = false;
|
||||
}
|
||||
if (!inv->isProducing()) {
|
||||
allProducing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// set LED status
|
||||
if (allReachable && allProducing) {
|
||||
_ledState[1] = LedState_t::On;
|
||||
}
|
||||
if (allReachable && !allProducing) {
|
||||
_ledState[1] = LedState_t::Blink;
|
||||
}
|
||||
}
|
||||
|
||||
_updateTimeout.reset();
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < PINMAPPING_LED_COUNT; i++) {
|
||||
auto& pin = PinMapping.get();
|
||||
|
||||
if (pin.led[i] < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (_ledState[i]) {
|
||||
case LedState_t::Off:
|
||||
digitalWrite(pin.led[i], LOW);
|
||||
break;
|
||||
case LedState_t::On:
|
||||
digitalWrite(pin.led[i], HIGH);
|
||||
break;
|
||||
case LedState_t::Blink:
|
||||
if (_blinkTimeout.occured()) {
|
||||
digitalWrite(pin.led[i], !digitalRead(pin.led[i]));
|
||||
_blinkTimeout.reset();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -30,6 +30,14 @@
|
||||
#define DISPLAY_RESET 255
|
||||
#endif
|
||||
|
||||
#ifndef LED0
|
||||
#define LED0 -1
|
||||
#endif
|
||||
|
||||
#ifndef LED1
|
||||
#define LED1 -1
|
||||
#endif
|
||||
|
||||
PinMappingClass PinMapping;
|
||||
|
||||
PinMappingClass::PinMappingClass()
|
||||
@ -61,6 +69,8 @@ PinMappingClass::PinMappingClass()
|
||||
_pinMapping.display_cs = DISPLAY_CS;
|
||||
_pinMapping.display_reset = DISPLAY_RESET;
|
||||
|
||||
_pinMapping.led[0] = LED0;
|
||||
_pinMapping.led[1] = LED1;
|
||||
}
|
||||
|
||||
PinMapping_t& PinMappingClass::get()
|
||||
@ -113,6 +123,9 @@ bool PinMappingClass::init(const String& deviceMapping)
|
||||
_pinMapping.display_cs = doc[i]["display"]["cs"] | DISPLAY_CS;
|
||||
_pinMapping.display_reset = doc[i]["display"]["reset"] | DISPLAY_RESET;
|
||||
|
||||
_pinMapping.led[0] = doc[i]["led"]["led0"] | LED0;
|
||||
_pinMapping.led[1] = doc[i]["led"]["led1"] | LED1;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,6 +63,10 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request)
|
||||
displayPinObj["cs"] = pin.display_cs;
|
||||
displayPinObj["reset"] = pin.display_reset;
|
||||
|
||||
JsonObject ledPinObj = curPin.createNestedObject("led");
|
||||
ledPinObj["led0"] = pin.led[0];
|
||||
ledPinObj["led1"] = pin.led[1];
|
||||
|
||||
JsonObject display = root.createNestedObject("display");
|
||||
display["rotation"] = config.Display_Rotation;
|
||||
display["power_safe"] = config.Display_PowerSafe;
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "Configuration.h"
|
||||
#include "Display_Graphic.h"
|
||||
#include "InverterSettings.h"
|
||||
#include "Led_Single.h"
|
||||
#include "MessageOutput.h"
|
||||
#include "MqttHandleDtu.h"
|
||||
#include "MqttHandleHass.h"
|
||||
@ -114,6 +115,11 @@ void setup()
|
||||
Display.setStartupDisplay();
|
||||
MessageOutput.println("done");
|
||||
|
||||
// Initialize Single LEDs
|
||||
MessageOutput.print("Initialize LEDs... ");
|
||||
LedSingle.init();
|
||||
MessageOutput.println("done");
|
||||
|
||||
// Check for default DTU serial
|
||||
MessageOutput.print("Check for default DTU serial... ");
|
||||
if (config.Dtu_Serial == DTU_SERIAL) {
|
||||
@ -150,4 +156,6 @@ void loop()
|
||||
yield();
|
||||
MessageOutput.loop();
|
||||
yield();
|
||||
LedSingle.loop();
|
||||
yield();
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user