Add HA MQTT

This commit is contained in:
T
2025-09-11 19:29:08 +02:00
parent f0c9056cdc
commit 82d7ec6a09
2 changed files with 142 additions and 9 deletions

View File

@@ -12,3 +12,4 @@ lib_deps =
https://github.com/PaulStoffregen/Time https://github.com/PaulStoffregen/Time
TimerOne TimerOne
Ethernet Ethernet
PubSubClient3

View File

@@ -2,11 +2,38 @@
#include <Ethernet.h> #include <Ethernet.h>
#include <SPI.h> #include <SPI.h>
#include <TimerOne.h> #include <TimerOne.h>
#include <PubSubClient.h>
// ---------------- MQTT Settings ------------------
const char *mqtt_server = "mqtt.chaospott.de"; // <<< anpassen!
const int mqtt_port = 1883;
const char *mqtt_client = "fooclock";
// Eindeutige ID für die Uhr in Home Assistant
const char *device_id = "fooclock_01";
// Topics für Home Assistant
const char *mqtt_command_topic = "fooclock/display/set"; // Topic zum Senden von Befehlen (ON/OFF)
const char *mqtt_state_topic = "fooclock/display/state"; // Topic zum Melden des Status (ON/OFF)
const char *mqtt_discovery_topic = "homeassistant/switch/fooclock/display/config"; // HA Auto-Discovery Topic
EthernetClient ethClient;
PubSubClient client(ethClient);
bool displayEnabled = true; // Steuerflag für Anzeige
// Forward declaration der neuen Funktionen
void publishState();
void publishDiscoveryMessage();
// -------------------------------------------------
#define _A 0 #define _A 0
#define _B 1 #define _B 1
#define _C 2 #define _C 2
#define _D 3
#define _E 4 #define _E 4
#define _F 5
#define _G 6 #define _G 6
#define _H 7 #define _H 7
#define _I 8 #define _I 8
@@ -28,11 +55,11 @@
#define _Y 24 #define _Y 24
#define _Z 25 #define _Z 25
#define UP 1 #define UP 1
#define DOWN 2 #define DOWN 2
#define light_lvl_standard 60 #define light_lvl_standard 60
#define light_lvl_risen 255 #define light_lvl_risen 255
// ---------------------------------- Definition of Global Variables -------------------------- // // ---------------------------------- Definition of Global Variables -------------------------- //
@@ -58,9 +85,9 @@ bool second_changed = false;
bool init_done = false; bool init_done = false;
bool transition_active = false; bool transition_active = false;
bool swipe_active = false; bool swipe_active = false;
bool shrink_active = false; // Maybe we should move them to a single variable and set or unset bits inside the variable bool shrink_active = false;
int cur_update = 0; int cur_update = 0;
unsigned int shift_state = 0; int shift_state = 0;
int update_counter = 0; int update_counter = 0;
int spinner_pos = 0; int spinner_pos = 0;
int animation = 0; int animation = 0;
@@ -143,6 +170,92 @@ int today[7] = {
184, 220, 200, 200, 240, 0, 0 // Display "Hello" 184, 220, 200, 200, 240, 0, 0 // Display "Hello"
}; };
// ---------------- MQTT Callback ------------------
void mqttCallback(char *topic, byte *payload, unsigned int length) {
payload[length] = '\0'; // String terminieren
String message = String((char *) payload);
Serial.print("Nachricht empfangen [");
Serial.print(topic);
Serial.print("] ");
Serial.println(message);
if (String(topic) == mqtt_command_topic) {
if (message == "ON") {
displayEnabled = true;
Serial.println("MQTT: Display eingeschaltet");
} else if (message == "OFF") {
displayEnabled = false;
Serial.println("MQTT: Display ausgeschaltet");
}
// Sende den neuen Status sofort zurück
publishState();
}
}
// ---------------- MQTT Publish State ------------------
void publishState() {
if (displayEnabled) {
client.publish(mqtt_state_topic, "ON", true); // true = retain message
} else {
client.publish(mqtt_state_topic, "OFF", true); // true = retain message
}
}
// ---------------- MQTT Publish Home Assistant Discovery Message ------------------
void publishDiscoveryMessage() {
// Use a fixed-size buffer to create the JSON payload. This is much more
// memory-efficient than using the Arduino String class for concatenation.
char discoveryPayload[400];
// Create the JSON payload using snprintf to prevent buffer overflows
snprintf(discoveryPayload, sizeof(discoveryPayload),
"{"
"\"name\":\"FooClock Display\","
"\"unique_id\":\"%s_display\","
"\"cmd_t\":\"%s\","
"\"stat_t\":\"%s\","
"\"pl_on\":\"ON\","
"\"pl_off\":\"OFF\","
"\"icon\":\"mdi:clock-digital\","
"\"device\":{"
"\"identifiers\":[\"%s\"],"
"\"name\":\"FooClock\","
"\"manufacturer\":\"DIY\""
"}"
"}",
device_id,
mqtt_command_topic,
mqtt_state_topic,
device_id
);
// Nachricht mit Retain-Flag publishen, damit HA sie auch nach einem Neustart findet
client.publish(mqtt_discovery_topic, discoveryPayload, true);
}
// ---------------- MQTT Reconnect ------------------
void reconnect() {
while (!client.connected()) {
Serial.print("MQTT Verbindung herstellen...");
if (client.connect(mqtt_client)) {
Serial.println("verbunden.");
// Sobald verbunden, Befehls-Topic abonnieren
client.subscribe(mqtt_command_topic);
// Discovery-Nachricht und initialen Status senden
publishDiscoveryMessage();
publishState();
} else {
Serial.print("Fehler, rc=");
Serial.print(client.state());
Serial.println(" -> neuer Versuch in 5s");
delay(5000);
}
}
}
// ----------------------------------- Setup Code ---------------------------------------------- // // ----------------------------------- Setup Code ---------------------------------------------- //
void setup() { void setup() {
pinMode(OutputEnable, OUTPUT); pinMode(OutputEnable, OUTPUT);
@@ -164,10 +277,20 @@ void setup() {
setSyncProvider(getNtpTime); setSyncProvider(getNtpTime);
update_counter = 0; update_counter = 0;
init_done = true; init_done = true;
// <<< MQTT init >>>
client.setServer(mqtt_server, mqtt_port);
client.setCallback(mqttCallback);
} }
// -------------------------------------- Main Loop ------------------------------------------------- // // -------------------------------------- Main Loop ------------------------------------------------- //
void loop() { void loop() {
// <<< MQTT >>>
if (!client.connected()) {
reconnect();
}
client.loop();
time_t timestamp = now(); time_t timestamp = now();
// Sync blinking with second change // Sync blinking with second change
if (cur_time != timestamp && !second_changed) { if (cur_time != timestamp && !second_changed) {
@@ -216,7 +339,7 @@ void loop() {
shift_state = 0; shift_state = 0;
updateDate(timestamp); updateDate(timestamp);
animation = rand() % 6; animation = (int) (rand() % 6);
} }
// Blinkenfoo - comment to remove pulsating light // Blinkenfoo - comment to remove pulsating light
@@ -233,10 +356,19 @@ void loop() {
// ---------------------- Interrupt Handler (Timer1) ------------------- // // ---------------------- Interrupt Handler (Timer1) ------------------- //
void updateDisplay() { void updateDisplay() {
if (!displayEnabled) {
// Anzeige aus: alles dunkel
digitalWrite(latchPin, LOW);
for (int digitCount = 5; digitCount >= 0; digitCount--) {
shiftOut(dataPin, clockPin, MSBFIRST, 0);
}
digitalWrite(latchPin, HIGH);
return;
}
// take the latchPin low so // take the latchPin low so
// the LEDs don't flicker while you're sending in bits: // the LEDs don't flicker while you're sending in bits:
digitalWrite(latchPin, LOW); digitalWrite(latchPin, LOW);
for (int digitCount = 5; digitCount >= 0; digitCount--) { for (int digitCount = 5; digitCount >= 0; digitCount--) {
shiftOut(dataPin, clockPin, MSBFIRST, frame[digitCount]); shiftOut(dataPin, clockPin, MSBFIRST, frame[digitCount]);
} }
@@ -244,7 +376,6 @@ void updateDisplay() {
digitalWrite(latchPin, HIGH); digitalWrite(latchPin, HIGH);
update_counter++; update_counter++;
if (update_counter == 1000) { if (update_counter == 1000) {
update_counter = 0; update_counter = 0;
} }
@@ -256,6 +387,7 @@ void updateDisplay() {
} }
} }
// -------------------------------- Date Functions ---------------------- // // -------------------------------- Date Functions ---------------------- //
void updateDate(time_t t) { void updateDate(time_t t) {
today[0] = digits[(day(t) / 10)]; today[0] = digits[(day(t) / 10)];