Add HA MQTT
This commit is contained in:
@@ -12,3 +12,4 @@ lib_deps =
|
||||
https://github.com/PaulStoffregen/Time
|
||||
TimerOne
|
||||
Ethernet
|
||||
PubSubClient3
|
||||
|
150
src/fooclock.ino
150
src/fooclock.ino
@@ -2,11 +2,38 @@
|
||||
#include <Ethernet.h>
|
||||
#include <SPI.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 _B 1
|
||||
#define _C 2
|
||||
#define _D 3
|
||||
#define _E 4
|
||||
#define _F 5
|
||||
#define _G 6
|
||||
#define _H 7
|
||||
#define _I 8
|
||||
@@ -28,11 +55,11 @@
|
||||
#define _Y 24
|
||||
#define _Z 25
|
||||
|
||||
#define UP 1
|
||||
#define DOWN 2
|
||||
#define UP 1
|
||||
#define DOWN 2
|
||||
|
||||
#define light_lvl_standard 60
|
||||
#define light_lvl_risen 255
|
||||
#define light_lvl_standard 60
|
||||
#define light_lvl_risen 255
|
||||
|
||||
// ---------------------------------- Definition of Global Variables -------------------------- //
|
||||
|
||||
@@ -58,9 +85,9 @@ bool second_changed = false;
|
||||
bool init_done = false;
|
||||
bool transition_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;
|
||||
unsigned int shift_state = 0;
|
||||
int shift_state = 0;
|
||||
int update_counter = 0;
|
||||
int spinner_pos = 0;
|
||||
int animation = 0;
|
||||
@@ -143,6 +170,92 @@ int today[7] = {
|
||||
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 ---------------------------------------------- //
|
||||
void setup() {
|
||||
pinMode(OutputEnable, OUTPUT);
|
||||
@@ -164,10 +277,20 @@ void setup() {
|
||||
setSyncProvider(getNtpTime);
|
||||
update_counter = 0;
|
||||
init_done = true;
|
||||
|
||||
// <<< MQTT init >>>
|
||||
client.setServer(mqtt_server, mqtt_port);
|
||||
client.setCallback(mqttCallback);
|
||||
}
|
||||
|
||||
// -------------------------------------- Main Loop ------------------------------------------------- //
|
||||
void loop() {
|
||||
// <<< MQTT >>>
|
||||
if (!client.connected()) {
|
||||
reconnect();
|
||||
}
|
||||
client.loop();
|
||||
|
||||
time_t timestamp = now();
|
||||
// Sync blinking with second change
|
||||
if (cur_time != timestamp && !second_changed) {
|
||||
@@ -216,7 +339,7 @@ void loop() {
|
||||
shift_state = 0;
|
||||
updateDate(timestamp);
|
||||
|
||||
animation = rand() % 6;
|
||||
animation = (int) (rand() % 6);
|
||||
}
|
||||
|
||||
// Blinkenfoo - comment to remove pulsating light
|
||||
@@ -233,10 +356,19 @@ void loop() {
|
||||
|
||||
// ---------------------- Interrupt Handler (Timer1) ------------------- //
|
||||
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
|
||||
// the LEDs don't flicker while you're sending in bits:
|
||||
digitalWrite(latchPin, LOW);
|
||||
|
||||
for (int digitCount = 5; digitCount >= 0; digitCount--) {
|
||||
shiftOut(dataPin, clockPin, MSBFIRST, frame[digitCount]);
|
||||
}
|
||||
@@ -244,7 +376,6 @@ void updateDisplay() {
|
||||
digitalWrite(latchPin, HIGH);
|
||||
|
||||
update_counter++;
|
||||
|
||||
if (update_counter == 1000) {
|
||||
update_counter = 0;
|
||||
}
|
||||
@@ -256,6 +387,7 @@ void updateDisplay() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------- Date Functions ---------------------- //
|
||||
void updateDate(time_t t) {
|
||||
today[0] = digits[(day(t) / 10)];
|
||||
|
Reference in New Issue
Block a user