Add HA MQTT
This commit is contained in:
@@ -12,3 +12,4 @@ lib_deps =
|
|||||||
https://github.com/PaulStoffregen/Time
|
https://github.com/PaulStoffregen/Time
|
||||||
TimerOne
|
TimerOne
|
||||||
Ethernet
|
Ethernet
|
||||||
|
PubSubClient3
|
||||||
|
142
src/fooclock.ino
142
src/fooclock.ino
@@ -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
|
||||||
@@ -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)];
|
||||||
|
Reference in New Issue
Block a user