Optimize memory usage and fix MQTT HA discovery payload
This commit is contained in:
160
src/fooclock.ino
160
src/fooclock.ino
@@ -3,11 +3,12 @@
|
|||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#include <TimerOne.h>
|
#include <TimerOne.h>
|
||||||
#include <PubSubClient.h>
|
#include <PubSubClient.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
|
||||||
// ---------------- MQTT Settings ------------------
|
// ---------------- MQTT Settings ------------------
|
||||||
const char *mqtt_server = "mqtt.chaospott.de"; // <<< anpassen!
|
const char *mqtt_server = "mqtt.chaospott.de"; // <<< anpassen!
|
||||||
const int mqtt_port = 1883;
|
const int mqtt_port = 1883;
|
||||||
const char *mqtt_client = "fooclock";
|
const char *mqtt_client = "fooclock7";
|
||||||
|
|
||||||
// Eindeutige ID für die Uhr in Home Assistant
|
// Eindeutige ID für die Uhr in Home Assistant
|
||||||
const char *device_id = "fooclock_01";
|
const char *device_id = "fooclock_01";
|
||||||
@@ -79,7 +80,6 @@ const int timeZone = 2; // Central European Time (summertime)
|
|||||||
//const int timeZone = -7; // Pacific Daylight Time (USA)
|
//const int timeZone = -7; // Pacific Daylight Time (USA)
|
||||||
|
|
||||||
time_t cur_time = 0;
|
time_t cur_time = 0;
|
||||||
time_t alarm_goal = 0;
|
|
||||||
bool update_done = false;
|
bool update_done = false;
|
||||||
bool second_changed = false;
|
bool second_changed = false;
|
||||||
bool init_done = false;
|
bool init_done = false;
|
||||||
@@ -87,26 +87,24 @@ bool transition_active = false;
|
|||||||
bool swipe_active = false;
|
bool swipe_active = false;
|
||||||
bool shrink_active = false;
|
bool shrink_active = false;
|
||||||
int cur_update = 0;
|
int cur_update = 0;
|
||||||
int shift_state = 0;
|
uint8_t shift_state = 0;
|
||||||
int update_counter = 0;
|
int update_counter = 0;
|
||||||
int spinner_pos = 0;
|
uint8_t spinner_pos = 0;
|
||||||
int animation = 0;
|
uint8_t animation = 0;
|
||||||
|
|
||||||
EthernetUDP Udp;
|
EthernetUDP Udp;
|
||||||
EthernetUDP AlarmClock;
|
|
||||||
unsigned int alarmClockPort = 123; // local port to listen for custom AlarmClock packets
|
|
||||||
unsigned int localPort = 8888; // local port to listen for UDP packets
|
unsigned int localPort = 8888; // local port to listen for UDP packets
|
||||||
|
|
||||||
int OutputEnable = 3;
|
const uint8_t OutputEnable = 3;
|
||||||
|
|
||||||
//Pin connected to ST_CP of 74HC595
|
//Pin connected to ST_CP of 74HC595
|
||||||
int latchPin = 4;
|
const uint8_t latchPin = 4;
|
||||||
|
|
||||||
//Pin connected to SH_CP of 74HC595
|
//Pin connected to SH_CP of 74HC595
|
||||||
int clockPin = 2;
|
const uint8_t clockPin = 2;
|
||||||
|
|
||||||
//Pin connected to DS of 74HC595
|
//Pin connected to DS of 74HC595
|
||||||
int dataPin = 5;
|
const uint8_t dataPin = 5;
|
||||||
|
|
||||||
// 4
|
// 4
|
||||||
// /======\
|
// /======\
|
||||||
@@ -119,9 +117,9 @@ int dataPin = 5;
|
|||||||
// || 64 ||
|
// || 64 ||
|
||||||
// \======/ O 1
|
// \======/ O 1
|
||||||
|
|
||||||
int duration = 10;
|
const uint8_t duration = 10;
|
||||||
|
|
||||||
int digits[10] = {
|
const uint8_t digits[10] = {
|
||||||
238, // 0 0xEE
|
238, // 0 0xEE
|
||||||
34, // 1 0x22
|
34, // 1 0x22
|
||||||
214, // 2 0xD6
|
214, // 2 0xD6
|
||||||
@@ -134,7 +132,7 @@ int digits[10] = {
|
|||||||
126 // 9 0x7E
|
126 // 9 0x7E
|
||||||
};
|
};
|
||||||
|
|
||||||
int letter[26] = {
|
const uint8_t letter[26] = {
|
||||||
191, // A
|
191, // A
|
||||||
248, // b
|
248, // b
|
||||||
204, // C
|
204, // C
|
||||||
@@ -163,30 +161,31 @@ int letter[26] = {
|
|||||||
214, // Z
|
214, // Z
|
||||||
};
|
};
|
||||||
|
|
||||||
int frame[6] = {
|
uint8_t frame[6] = {
|
||||||
0, letter[_T], letter[_R], letter[_A], letter[_T], letter[_S] // Display "Start" (write from right to left into the array)
|
0, letter[_T], letter[_R], letter[_A], letter[_T], letter[_S] // Display "Start" (write from right to left into the array)
|
||||||
};
|
};
|
||||||
int today[7] = {
|
uint8_t today[7] = {
|
||||||
184, 220, 200, 200, 240, 0, 0 // Display "Hello"
|
184, 220, 200, 200, 240, 0, 0 // Display "Hello"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// ---------------- MQTT Callback ------------------
|
// ---------------- MQTT Callback ------------------
|
||||||
void mqttCallback(char *topic, byte *payload, unsigned int length) {
|
void mqttCallback(char *topic, byte *payload, unsigned int length) {
|
||||||
payload[length] = '\0'; // String terminieren
|
Serial.print(F("Nachricht empfangen ["));
|
||||||
String message = String((char *) payload);
|
|
||||||
Serial.print("Nachricht empfangen [");
|
|
||||||
Serial.print(topic);
|
Serial.print(topic);
|
||||||
Serial.print("] ");
|
Serial.print(F("] "));
|
||||||
Serial.println(message);
|
for (unsigned int i = 0; i < length; i++) {
|
||||||
|
Serial.write(payload[i]);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
if (String(topic) == mqtt_command_topic) {
|
if (strcmp(topic, mqtt_command_topic) == 0) {
|
||||||
if (message == "ON") {
|
if (length == 2 && payload[0] == 'O' && payload[1] == 'N') {
|
||||||
displayEnabled = true;
|
displayEnabled = true;
|
||||||
Serial.println("MQTT: Display eingeschaltet");
|
Serial.println(F("MQTT: Display eingeschaltet"));
|
||||||
} else if (message == "OFF") {
|
} else if (length == 3 && payload[0] == 'O' && payload[1] == 'F' && payload[2] == 'F') {
|
||||||
displayEnabled = false;
|
displayEnabled = false;
|
||||||
Serial.println("MQTT: Display ausgeschaltet");
|
Serial.println(F("MQTT: Display ausgeschaltet"));
|
||||||
}
|
}
|
||||||
// Sende den neuen Status sofort zurück
|
// Sende den neuen Status sofort zurück
|
||||||
publishState();
|
publishState();
|
||||||
@@ -204,52 +203,52 @@ void publishState() {
|
|||||||
|
|
||||||
// ---------------- MQTT Publish Home Assistant Discovery Message ------------------
|
// ---------------- MQTT Publish Home Assistant Discovery Message ------------------
|
||||||
void publishDiscoveryMessage() {
|
void publishDiscoveryMessage() {
|
||||||
// Use a fixed-size buffer to create the JSON payload. This is much more
|
// Home Assistant Discovery-JSON im Flash halten und aus PROGMEM formatieren.
|
||||||
// memory-efficient than using the Arduino String class for concatenation.
|
char discoveryPayload[320];
|
||||||
char discoveryPayload[400];
|
int payloadLen = snprintf_P(discoveryPayload, sizeof(discoveryPayload),
|
||||||
|
PSTR("{\"name\":\"7FooClock\",\"unique_id\":\"%s_display\",\"cmd_t\":\"%s\",\"stat_t\":\"%s\",\"pl_on\":\"ON\",\"pl_off\":\"OFF\",\"icon\":\"mdi:clock-digital\",\"device\":{\"identifiers\":[\"%s\"],\"name\":\"7FooClock\",\"manufacturer\":\"DIY\"}}"),
|
||||||
// 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,
|
device_id,
|
||||||
mqtt_command_topic,
|
mqtt_command_topic,
|
||||||
mqtt_state_topic,
|
mqtt_state_topic,
|
||||||
device_id
|
device_id);
|
||||||
);
|
|
||||||
|
if (payloadLen < 0) {
|
||||||
|
Serial.println(F("HA discovery build failed"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((size_t)payloadLen >= sizeof(discoveryPayload)) {
|
||||||
|
Serial.print(F("HA discovery truncated, len="));
|
||||||
|
Serial.println(payloadLen);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Nachricht mit Retain-Flag publishen, damit HA sie auch nach einem Neustart findet
|
// Nachricht mit Retain-Flag publishen, damit HA sie auch nach einem Neustart findet
|
||||||
client.publish(mqtt_discovery_topic, discoveryPayload, true);
|
bool ok = client.publish(mqtt_discovery_topic, discoveryPayload, true);
|
||||||
|
if (!ok) {
|
||||||
|
Serial.print(F("HA discovery publish failed, len="));
|
||||||
|
Serial.println(payloadLen);
|
||||||
|
} else {
|
||||||
|
Serial.print(F("HA discovery published, len="));
|
||||||
|
Serial.println(payloadLen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ---------------- MQTT Reconnect ------------------
|
// ---------------- MQTT Reconnect ------------------
|
||||||
void reconnect() {
|
void reconnect() {
|
||||||
while (!client.connected()) {
|
while (!client.connected()) {
|
||||||
Serial.print("MQTT Verbindung herstellen...");
|
Serial.print(F("MQTT Verbindung herstellen..."));
|
||||||
if (client.connect(mqtt_client)) {
|
if (client.connect(mqtt_client)) {
|
||||||
Serial.println("verbunden.");
|
Serial.println(F("verbunden."));
|
||||||
// Sobald verbunden, Befehls-Topic abonnieren
|
// Sobald verbunden, Befehls-Topic abonnieren
|
||||||
client.subscribe(mqtt_command_topic);
|
client.subscribe(mqtt_command_topic);
|
||||||
// Discovery-Nachricht und initialen Status senden
|
// Discovery-Nachricht und initialen Status senden
|
||||||
publishDiscoveryMessage();
|
publishDiscoveryMessage();
|
||||||
publishState();
|
publishState();
|
||||||
} else {
|
} else {
|
||||||
Serial.print("Fehler, rc=");
|
Serial.print(F("Fehler, rc="));
|
||||||
Serial.print(client.state());
|
Serial.print(client.state());
|
||||||
Serial.println(" -> neuer Versuch in 5s");
|
Serial.println(F(" -> neuer Versuch in 5s"));
|
||||||
delay(5000);
|
delay(5000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -280,6 +279,7 @@ void setup() {
|
|||||||
|
|
||||||
// <<< MQTT init >>>
|
// <<< MQTT init >>>
|
||||||
client.setServer(mqtt_server, mqtt_port);
|
client.setServer(mqtt_server, mqtt_port);
|
||||||
|
client.setBufferSize(384);
|
||||||
client.setCallback(mqttCallback);
|
client.setCallback(mqttCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,12 +458,12 @@ void dim(int direction, int lower_limit, int upper_limit) {
|
|||||||
if (direction == DOWN && local_counter % range <= range) {
|
if (direction == DOWN && local_counter % range <= range) {
|
||||||
write_out = 255 - (upper_limit - (local_counter) % range);
|
write_out = 255 - (upper_limit - (local_counter) % range);
|
||||||
analogWrite(OutputEnable, write_out);
|
analogWrite(OutputEnable, write_out);
|
||||||
Serial.println("Down ->");
|
Serial.println(F("Down ->"));
|
||||||
Serial.println(write_out);
|
Serial.println(write_out);
|
||||||
} else {
|
} else {
|
||||||
write_out = 255 - (lower_limit + (local_counter % range));
|
write_out = 255 - (lower_limit + (local_counter % range));
|
||||||
analogWrite(OutputEnable, write_out);
|
analogWrite(OutputEnable, write_out);
|
||||||
Serial.println("UP ->");
|
Serial.println(F("UP ->"));
|
||||||
Serial.println(write_out);
|
Serial.println(write_out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -489,7 +489,7 @@ void spin(int digit) {
|
|||||||
spinner_pos++;
|
spinner_pos++;
|
||||||
};
|
};
|
||||||
|
|
||||||
void shrink(int direction, int *new_data) {
|
void shrink(int direction, uint8_t *new_data) {
|
||||||
static int j = 0;
|
static int j = 0;
|
||||||
static int height = 0;
|
static int height = 0;
|
||||||
int bitmask = 0;
|
int bitmask = 0;
|
||||||
@@ -526,7 +526,7 @@ void shrink(int direction, int *new_data) {
|
|||||||
} else {
|
} else {
|
||||||
height--;
|
height--;
|
||||||
}
|
}
|
||||||
Serial.print("Shrink.J = ");
|
Serial.print(F("Shrink.J = "));
|
||||||
Serial.println(j);
|
Serial.println(j);
|
||||||
} else {
|
} else {
|
||||||
for (int digit = 0; digit < 6; digit++) {
|
for (int digit = 0; digit < 6; digit++) {
|
||||||
@@ -538,7 +538,7 @@ void shrink(int direction, int *new_data) {
|
|||||||
} else {
|
} else {
|
||||||
height++;
|
height++;
|
||||||
}
|
}
|
||||||
Serial.print("Shrink.J = ");
|
Serial.print(F("Shrink.J = "));
|
||||||
Serial.println(j);
|
Serial.println(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,7 +546,7 @@ void shrink(int direction, int *new_data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void swipe(int direction, int *new_data) {
|
void swipe(int direction, uint8_t *new_data) {
|
||||||
static int j = 0;
|
static int j = 0;
|
||||||
static int height = 0;
|
static int height = 0;
|
||||||
int bitmask = 0;
|
int bitmask = 0;
|
||||||
@@ -588,7 +588,7 @@ void swipe(int direction, int *new_data) {
|
|||||||
} else {
|
} else {
|
||||||
height--;
|
height--;
|
||||||
}
|
}
|
||||||
Serial.print("Swipe. J = ");
|
Serial.print(F("Swipe. J = "));
|
||||||
Serial.println(j);
|
Serial.println(j);
|
||||||
} else {
|
} else {
|
||||||
for (int digit = 0; digit < 6; digit++) {
|
for (int digit = 0; digit < 6; digit++) {
|
||||||
@@ -600,7 +600,7 @@ void swipe(int direction, int *new_data) {
|
|||||||
} else {
|
} else {
|
||||||
height++;
|
height++;
|
||||||
}
|
}
|
||||||
Serial.print("Swipe. J = ");
|
Serial.print(F("Swipe. J = "));
|
||||||
Serial.println(j);
|
Serial.println(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -608,21 +608,21 @@ void swipe(int direction, int *new_data) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void combine(int *a) {
|
void combine(uint8_t *a) {
|
||||||
static int i = 0;
|
static int i = 0;
|
||||||
static int j = 0;
|
static int j = 0;
|
||||||
int current[6];
|
uint8_t current[6];
|
||||||
|
|
||||||
if (transition_active == false) {
|
if (transition_active == false) {
|
||||||
transition_active = true;
|
transition_active = true;
|
||||||
memcpy(current, frame, 6 * sizeof(int));
|
memcpy(current, frame, sizeof(current));
|
||||||
j = 0;
|
j = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update_counter % 33 == 0 && j < 18) {
|
if (update_counter % 33 == 0 && j < 18) {
|
||||||
Serial.print("i : ");
|
Serial.print(F("i : "));
|
||||||
Serial.print(i);
|
Serial.print(i);
|
||||||
Serial.print(" j : ");
|
Serial.print(F(" j : "));
|
||||||
Serial.println(j);
|
Serial.println(j);
|
||||||
|
|
||||||
if (j % 3 == 0) {
|
if (j % 3 == 0) {
|
||||||
@@ -648,8 +648,8 @@ void shift_right(int neu) {
|
|||||||
frame[5] = neu;
|
frame[5] = neu;
|
||||||
}
|
}
|
||||||
|
|
||||||
void transition(int *a) {
|
void transition(uint8_t *a) {
|
||||||
if (update_counter % 150 == 0 && cur_update != update_counter && shift_state < sizeof(today) / 2) {
|
if (update_counter % 150 == 0 && cur_update != update_counter && shift_state < (sizeof(today) / sizeof(today[0]))) {
|
||||||
//assuming the Array contains only ints,
|
//assuming the Array contains only ints,
|
||||||
//which have a sizeof 2 on this Arduino
|
//which have a sizeof 2 on this Arduino
|
||||||
Serial.println(sizeof(a));
|
Serial.println(sizeof(a));
|
||||||
@@ -659,28 +659,6 @@ void transition(int *a) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*-------- Alarm Clock code ---------*/
|
|
||||||
const int AlarmClockPacketSize = 256;
|
|
||||||
byte AlarmBuffer[AlarmClockPacketSize];
|
|
||||||
|
|
||||||
int listenForAlarm() {
|
|
||||||
while (AlarmClock.parsePacket() > 0);
|
|
||||||
Serial.println("Any Alarm imminent?");
|
|
||||||
uint32_t packageBegin = millis();
|
|
||||||
while (millis() - packageBegin < 1500) {
|
|
||||||
int size = AlarmClock.parsePacket();
|
|
||||||
if (size >= AlarmClockPacketSize) {
|
|
||||||
Serial.println("Alarm seems to be imminent.");
|
|
||||||
AlarmClock.read(AlarmBuffer, AlarmClockPacketSize);
|
|
||||||
alarm_goal = (unsigned long) AlarmBuffer;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Serial.println("No Alarm present!");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-------- NTP code ----------*/
|
/*-------- NTP code ----------*/
|
||||||
|
|
||||||
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
|
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
|
||||||
@@ -694,7 +672,7 @@ time_t getNtpTime() {
|
|||||||
while (millis() - beginWait < 1500) {
|
while (millis() - beginWait < 1500) {
|
||||||
int size = Udp.parsePacket();
|
int size = Udp.parsePacket();
|
||||||
if (size >= NTP_PACKET_SIZE) {
|
if (size >= NTP_PACKET_SIZE) {
|
||||||
Serial.println("Receive NTP Response");
|
Serial.println(F("Receive NTP Response"));
|
||||||
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
|
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
|
||||||
unsigned long secsSince1900;
|
unsigned long secsSince1900;
|
||||||
// convert four bytes starting at location 40 to a long integer
|
// convert four bytes starting at location 40 to a long integer
|
||||||
|
|||||||
Reference in New Issue
Block a user