733 lines
20 KiB
C++
733 lines
20 KiB
C++
#include <TimeLib.h>
|
|
#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
|
|
#define _J 9
|
|
#define _K 10
|
|
#define _L 11
|
|
#define _M 12
|
|
#define _N 13
|
|
#define _O 14
|
|
#define _P 15
|
|
#define _Q 16
|
|
#define _R 17
|
|
#define _S 18
|
|
#define _T 19
|
|
#define _U 20
|
|
#define _V 21
|
|
#define _W 22
|
|
#define _X 23
|
|
#define _Y 24
|
|
#define _Z 25
|
|
|
|
#define UP 1
|
|
#define DOWN 2
|
|
|
|
#define light_lvl_standard 60
|
|
#define light_lvl_risen 255
|
|
|
|
// ---------------------------------- Definition of Global Variables -------------------------- //
|
|
|
|
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
|
|
// NTP Servers:
|
|
IPAddress timeServer(132, 163, 96, 1); // time-a.timefreq.bldrdoc.gov
|
|
// IPAddress timeServer(132, 163, 96, 2); // time-b.timefreq.bldrdoc.gov
|
|
// IPAddress timeServer(132, 163, 96, 3); // time-c.timefreq.bldrdoc.gov
|
|
|
|
|
|
//const int timeZone = 1; // Central European Time
|
|
const int timeZone = 2; // Central European Time (summertime)
|
|
|
|
//const int timeZone = -5; // Eastern Standard Time (USA)
|
|
//const int timeZone = -4; // Eastern Daylight Time (USA)
|
|
//const int timeZone = -8; // Pacific Standard Time (USA)
|
|
//const int timeZone = -7; // Pacific Daylight Time (USA)
|
|
|
|
time_t cur_time = 0;
|
|
time_t alarm_goal = 0;
|
|
bool update_done = false;
|
|
bool second_changed = false;
|
|
bool init_done = false;
|
|
bool transition_active = false;
|
|
bool swipe_active = false;
|
|
bool shrink_active = false;
|
|
int cur_update = 0;
|
|
int shift_state = 0;
|
|
int update_counter = 0;
|
|
int spinner_pos = 0;
|
|
int animation = 0;
|
|
|
|
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
|
|
|
|
int OutputEnable = 3;
|
|
|
|
//Pin connected to ST_CP of 74HC595
|
|
int latchPin = 4;
|
|
|
|
//Pin connected to SH_CP of 74HC595
|
|
int clockPin = 2;
|
|
|
|
//Pin connected to DS of 74HC595
|
|
int dataPin = 5;
|
|
|
|
// 4
|
|
// /======\
|
|
// || ||
|
|
// 8 || || 2
|
|
// || 16 ||
|
|
// >======<
|
|
// || ||
|
|
// 128 || || 32
|
|
// || 64 ||
|
|
// \======/ O 1
|
|
|
|
int duration = 10;
|
|
|
|
int digits[10] = {
|
|
238, // 0 0xEE
|
|
34, // 1 0x22
|
|
214, // 2 0xD6
|
|
118, // 3 0x76
|
|
58, // 4 0x3A
|
|
124, // 5 0x7C
|
|
252, // 6 0xFC
|
|
38, // 7 0x26
|
|
254, // 8 0xFE
|
|
126 // 9 0x7E
|
|
};
|
|
|
|
int letter[26] = {
|
|
191, // A
|
|
248, // b
|
|
204, // C
|
|
242, // d
|
|
220, // E
|
|
156, // F
|
|
126, // g
|
|
184, // h
|
|
32, // i
|
|
230, // J
|
|
190, // k
|
|
200, // L
|
|
176, // m
|
|
176, // n
|
|
240, // o
|
|
158, // P
|
|
238, // Q
|
|
144, // r
|
|
124, // S
|
|
216, // t
|
|
224, // u
|
|
224, // v
|
|
26, // w
|
|
186, // X
|
|
58, // y
|
|
214, // Z
|
|
};
|
|
|
|
int frame[6] = {
|
|
0, letter[_T], letter[_R], letter[_A], letter[_T], letter[_S] // Display "Start" (write from right to left into the array)
|
|
};
|
|
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);
|
|
pinMode(latchPin, OUTPUT);
|
|
pinMode(clockPin, OUTPUT);
|
|
pinMode(dataPin, OUTPUT);
|
|
|
|
analogWrite(OutputEnable,light_lvl_standard);
|
|
|
|
Timer1.initialize(1000); // initialize timer1, and set a 1 millisecond period
|
|
Timer1.attachInterrupt(updateDisplay); // attaches callback() as a timer overflow interrupt
|
|
|
|
Serial.begin(9600);
|
|
|
|
while (Ethernet.begin(mac) == 0) {
|
|
delay(5000); // Wait for a valid IP-Address
|
|
}
|
|
Udp.begin(localPort);
|
|
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) {
|
|
update_counter = 0;
|
|
cur_time = timestamp;
|
|
second_changed = true;
|
|
}
|
|
|
|
int intervalpos = timestamp % 70;
|
|
if (intervalpos == 0) {
|
|
update_done = false;
|
|
}
|
|
if (intervalpos < 10) {
|
|
switch (animation) {
|
|
case 0: transition(today);
|
|
break;
|
|
case 1: combine(today);
|
|
break;
|
|
case 2: swipe(UP, today);
|
|
break;
|
|
case 3: swipe(DOWN, today);
|
|
break;
|
|
case 4: shrink(UP, today);
|
|
break;
|
|
case 5: shrink(DOWN, today);
|
|
break;
|
|
default: displayDate(timestamp);
|
|
break;
|
|
}
|
|
// shrink(DOWN,today);
|
|
// transition(today);
|
|
// combine(today);
|
|
// swipe(UP,today);
|
|
// displayDate(timestamp);
|
|
} else if (intervalpos > 20 && intervalpos < 30) {
|
|
displayBinaryTime(timestamp);
|
|
} else {
|
|
displayTime(timestamp);
|
|
}
|
|
|
|
if (intervalpos == 50 && !update_done) {
|
|
update_done = true;
|
|
transition_active = false;
|
|
swipe_active = false;
|
|
shrink_active = false;
|
|
shift_state = 0;
|
|
updateDate(timestamp);
|
|
|
|
animation = (int) (rand() % 6);
|
|
}
|
|
|
|
// Blinkenfoo - comment to remove pulsating light
|
|
if (update_counter < (light_lvl_risen - light_lvl_standard) && timestamp % 600 == 0) {
|
|
dim(UP,light_lvl_standard,light_lvl_risen);
|
|
}
|
|
if (update_counter > (1000 - (light_lvl_risen - light_lvl_standard)) && timestamp % 600 == 0) {
|
|
dim(DOWN,light_lvl_standard,light_lvl_risen);
|
|
}
|
|
if (update_counter == 900) {
|
|
second_changed = true;
|
|
}
|
|
}
|
|
|
|
// ---------------------- 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]);
|
|
}
|
|
//take the latch pin high so the LEDs will light up again:
|
|
digitalWrite(latchPin, HIGH);
|
|
|
|
update_counter++;
|
|
if (update_counter == 1000) {
|
|
update_counter = 0;
|
|
}
|
|
|
|
if (!init_done) {
|
|
if (update_counter % 100 == 0) {
|
|
spin(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// -------------------------------- Date Functions ---------------------- //
|
|
void updateDate(time_t t) {
|
|
today[0] = digits[(day(t) / 10)];
|
|
today[1] = digits[(day(t) % 10)] + 1;
|
|
|
|
today[2] = digits[(month(t) / 10)];
|
|
today[3] = digits[(month(t) % 10)] + 1;
|
|
|
|
today[4] = digits[((year(t) - 2000) / 10)];
|
|
today[5] = digits[((year(t) - 2000) % 10)];
|
|
}
|
|
|
|
void displayDate(time_t t) {
|
|
frame[5] = digits[(day(t) / 10)];
|
|
frame[4] = digits[(day(t) % 10)] + 1;
|
|
|
|
frame[3] = digits[(month(t) / 10)];
|
|
frame[2] = digits[(month(t) % 10)] + 1;
|
|
|
|
frame[1] = digits[((year(t) - 2000) / 10)];
|
|
frame[0] = digits[((year(t) - 2000) % 10)];
|
|
}
|
|
|
|
// ------------------------------- Time Functions -------------------- //
|
|
void displayTime(time_t t) {
|
|
frame[5] = digits[(hour(t) / 10)];
|
|
frame[4] = digits[(hour(t) % 10)];
|
|
|
|
frame[3] = digits[(minute(t) / 10)];
|
|
frame[2] = digits[(minute(t) % 10)];
|
|
|
|
frame[1] = digits[(second(t) / 10)];
|
|
frame[0] = digits[(second(t) % 10)];
|
|
}
|
|
|
|
void displayBinaryTime(time_t t) {
|
|
int digit;
|
|
|
|
for (int digitCount = 5; digitCount >= 0; digitCount--) {
|
|
// digit zusammenbauen und dann invertieren
|
|
digit = 0;
|
|
|
|
digit |= ((hour(t) & (1 << digitCount)) >> digitCount) << 2;
|
|
digit |= ((minute(t) & (1 << digitCount)) >> digitCount) << 4;
|
|
digit |= ((second(t) & (1 << digitCount)) >> digitCount) << 6;
|
|
|
|
// bitWrite(digit,2,(bitRead(hour(t), digitCount)) );
|
|
// bitWrite(digit,4,(bitRead(minute(t), digitCount)) );
|
|
// bitWrite(digit,6,(bitRead(second(t), digitCount)) );
|
|
frame[digitCount] = digit;
|
|
}
|
|
}
|
|
|
|
|
|
// ----------------------------------- System Functions ----------------------------------- //
|
|
void dim(int direction, int lower_limit, int upper_limit) {
|
|
int range = upper_limit - lower_limit;
|
|
int shift_start = 1000 - range;
|
|
int write_out = 0;
|
|
int local_counter = 0;
|
|
|
|
if (update_counter > range) {
|
|
local_counter = update_counter - shift_start;
|
|
} else {
|
|
local_counter = update_counter;
|
|
}
|
|
|
|
if (direction == DOWN && local_counter % range <= range) {
|
|
write_out = 255 - (upper_limit - (local_counter) % range);
|
|
analogWrite(OutputEnable, write_out);
|
|
Serial.println("Down ->");
|
|
Serial.println(write_out);
|
|
} else {
|
|
write_out = 255 - (lower_limit + (local_counter % range));
|
|
analogWrite(OutputEnable, write_out);
|
|
Serial.println("UP ->");
|
|
Serial.println(write_out);
|
|
}
|
|
}
|
|
|
|
void spin(int digit) {
|
|
if (spinner_pos >= 6)spinner_pos = 0;
|
|
switch (spinner_pos) {
|
|
case 0: frame[digit] = 4;
|
|
break;
|
|
case 1: frame[digit] = 2;
|
|
break;
|
|
case 2: frame[digit] = 32;
|
|
break;
|
|
case 3: frame[digit] = 64;
|
|
break;
|
|
case 4: frame[digit] = 128;
|
|
break;
|
|
case 5: frame[digit] = 8;
|
|
break;
|
|
default: frame[digit] = 0;
|
|
break;
|
|
}
|
|
spinner_pos++;
|
|
};
|
|
|
|
void shrink(int direction, int *new_data) {
|
|
static int j = 0;
|
|
static int height = 0;
|
|
int bitmask = 0;
|
|
|
|
if (shrink_active == false) {
|
|
shrink_active = true;
|
|
j = 0;
|
|
if (direction == UP) {
|
|
height = 2;
|
|
} else {
|
|
height = 0;
|
|
}
|
|
}
|
|
|
|
switch (height) {
|
|
case 0: bitmask = 0x44;
|
|
break;
|
|
case 1: bitmask = 0xAA;
|
|
break;
|
|
case 2: bitmask = 0x10;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (update_counter % 100 == 0 && j < 7) {
|
|
if (j < 3) {
|
|
for (int digit = 0; digit < 6; digit++) {
|
|
frame[digit] &= ~bitmask;
|
|
}
|
|
|
|
if (direction == DOWN) {
|
|
height++;
|
|
} else {
|
|
height--;
|
|
}
|
|
Serial.print("Shrink.J = ");
|
|
Serial.println(j);
|
|
} else {
|
|
for (int digit = 0; digit < 6; digit++) {
|
|
frame[5 - digit] |= new_data[digit] & bitmask;
|
|
}
|
|
|
|
if (direction == DOWN) {
|
|
height--;
|
|
} else {
|
|
height++;
|
|
}
|
|
Serial.print("Shrink.J = ");
|
|
Serial.println(j);
|
|
}
|
|
|
|
j++;
|
|
}
|
|
}
|
|
|
|
void swipe(int direction, int *new_data) {
|
|
static int j = 0;
|
|
static int height = 0;
|
|
int bitmask = 0;
|
|
|
|
if (swipe_active == false) {
|
|
swipe_active = true;
|
|
j = 0;
|
|
if (direction == UP) {
|
|
height = 4;
|
|
} else {
|
|
height = 0;
|
|
}
|
|
}
|
|
|
|
switch (height) {
|
|
case 0: bitmask = 0x04;
|
|
break;
|
|
case 1: bitmask = 0x0A;
|
|
break;
|
|
case 2: bitmask = 0x10;
|
|
break;
|
|
case 3: bitmask = 0xA0;
|
|
break;
|
|
case 4: bitmask = 0x40;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
if (update_counter % 60 == 0 && j < 11) {
|
|
if (j < 5) {
|
|
for (int digit = 0; digit < 6; digit++) {
|
|
frame[digit] &= ~bitmask;
|
|
}
|
|
|
|
if (direction == DOWN) {
|
|
height++;
|
|
} else {
|
|
height--;
|
|
}
|
|
Serial.print("Swipe. J = ");
|
|
Serial.println(j);
|
|
} else {
|
|
for (int digit = 0; digit < 6; digit++) {
|
|
frame[5 - digit] |= new_data[digit] & bitmask;
|
|
}
|
|
|
|
if (direction == DOWN) {
|
|
height--;
|
|
} else {
|
|
height++;
|
|
}
|
|
Serial.print("Swipe. J = ");
|
|
Serial.println(j);
|
|
}
|
|
|
|
j++;
|
|
}
|
|
};
|
|
|
|
void combine(int *a) {
|
|
static int i = 0;
|
|
static int j = 0;
|
|
int current[6];
|
|
|
|
if (transition_active == false) {
|
|
transition_active = true;
|
|
memcpy(current, frame, 6 * sizeof(int));
|
|
j = 0;
|
|
}
|
|
|
|
if (update_counter % 33 == 0 && j < 18) {
|
|
Serial.print("i : ");
|
|
Serial.print(i);
|
|
Serial.print(" j : ");
|
|
Serial.println(j);
|
|
|
|
if (j % 3 == 0) {
|
|
frame[5 - i] |= a[i];
|
|
} else if (j % 3 == 1) {
|
|
frame[5 - i] &= ~current[i];
|
|
} else {
|
|
frame[5 - i] = a[i];
|
|
i++;
|
|
}
|
|
|
|
if (i == 6) { i = 0; }
|
|
|
|
j++;
|
|
}
|
|
}
|
|
|
|
|
|
void shift_right(int neu) {
|
|
for (int i = 0; i < 5; i++) {
|
|
frame[i] = frame[i + 1];
|
|
}
|
|
frame[5] = neu;
|
|
}
|
|
|
|
void transition(int *a) {
|
|
if (update_counter % 150 == 0 && cur_update != update_counter && shift_state < sizeof(today) / 2) {
|
|
//assuming the Array contains only ints,
|
|
//which have a sizeof 2 on this Arduino
|
|
Serial.println(sizeof(a));
|
|
cur_update = update_counter;
|
|
shift_right(a[6 - shift_state]);
|
|
shift_state++;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------- 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 ----------*/
|
|
|
|
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
|
|
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets
|
|
|
|
time_t getNtpTime() {
|
|
while (Udp.parsePacket() > 0); // discard any previously received packets
|
|
//Serial.println("Transmit NTP Request");
|
|
sendNTPpacket(timeServer);
|
|
uint32_t beginWait = millis();
|
|
while (millis() - beginWait < 1500) {
|
|
int size = Udp.parsePacket();
|
|
if (size >= NTP_PACKET_SIZE) {
|
|
Serial.println("Receive NTP Response");
|
|
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
|
|
unsigned long secsSince1900;
|
|
// convert four bytes starting at location 40 to a long integer
|
|
secsSince1900 = (unsigned long) packetBuffer[40] << 24;
|
|
secsSince1900 |= (unsigned long) packetBuffer[41] << 16;
|
|
secsSince1900 |= (unsigned long) packetBuffer[42] << 8;
|
|
secsSince1900 |= (unsigned long) packetBuffer[43];
|
|
return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
|
|
}
|
|
}
|
|
//Serial.println("No NTP Response :-(");
|
|
return 0; // return 0 if unable to get the time
|
|
}
|
|
|
|
// send an NTP request to the time server at the given address
|
|
void sendNTPpacket(IPAddress &address) {
|
|
// set all bytes in the buffer to 0
|
|
memset(packetBuffer, 0, NTP_PACKET_SIZE);
|
|
// Initialize values needed to form NTP request
|
|
// (see URL above for details on the packets)
|
|
packetBuffer[0] = 0b11100011; // LI, Version, Mode
|
|
packetBuffer[1] = 0; // Stratum, or type of clock
|
|
packetBuffer[2] = 6; // Polling Interval
|
|
packetBuffer[3] = 0xEC; // Peer Clock Precision
|
|
// 8 bytes of zero for Root Delay & Root Dispersion
|
|
packetBuffer[12] = 49;
|
|
packetBuffer[13] = 0x4E;
|
|
packetBuffer[14] = 49;
|
|
packetBuffer[15] = 52;
|
|
// all NTP fields have been given values, now
|
|
// you can send a packet requesting a timestamp:
|
|
Udp.beginPacket(address, 123); //NTP requests are to port 123
|
|
Udp.write(packetBuffer, NTP_PACKET_SIZE);
|
|
Udp.endPacket();
|
|
}
|