Compare commits
2 Commits
13104d84e8
...
73aa168152
| Author | SHA1 | Date | |
|---|---|---|---|
| 73aa168152 | |||
| 52c7794d59 |
@@ -1,90 +0,0 @@
|
||||
#ifndef NTPCLIENTPLUS_H
|
||||
#define NTPCLIENTPLUS_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFiUdp.h>
|
||||
|
||||
#define UNIX_TIMESTAMP_1900 2208988800UL // careful: positive value
|
||||
#define NTP_PACKET_SIZE 48
|
||||
#define NTP_DEFAULT_LOCAL_PORT 1337
|
||||
#define MAX_NTP_CONN_TRIES 50 // 50 * NTP_RECEIVE_WAIT_TIME_MS => 500ms
|
||||
#define NTP_RECEIVE_WAIT_TIME_MS 10 // 10ms
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NTP_UPDATE_TIMEOUT = -1,
|
||||
NTP_UPDATE_SUCCESS = 0,
|
||||
NTP_UPDATE_DIFFTOOHIGH = 1,
|
||||
NTP_UPDATE_TIME_INVALID = 2
|
||||
} NtpReturnValue;
|
||||
|
||||
/**
|
||||
* @brief Own NTP Client library for Arduino with code from:
|
||||
* - https://github.com/arduino-libraries/NTPClient
|
||||
* - SPS&Technik - Projekt WordClock v1.02
|
||||
*
|
||||
*/
|
||||
class NTPClientPlus
|
||||
{
|
||||
public:
|
||||
NTPClientPlus(UDP &udp, const char *pool_server_name, int utcx, bool sw_change);
|
||||
bool is_leap_year(unsigned int year);
|
||||
bool check_daylight_saving_time();
|
||||
int get_hours_12() const;
|
||||
int get_hours_24() const;
|
||||
int get_minutes() const;
|
||||
int get_month(int dayOfYear);
|
||||
int get_seconds() const;
|
||||
int update_ntp();
|
||||
long get_time_offset();
|
||||
String get_formatted_date();
|
||||
String get_formatted_time() const;
|
||||
unsigned int get_day_of_week();
|
||||
unsigned int get_year();
|
||||
unsigned long get_epoch_time() const;
|
||||
unsigned long get_secs_since_1900() const;
|
||||
void calc_date();
|
||||
void end();
|
||||
void set_pool_server_name(const char *pool_server_name);
|
||||
void set_time_offset(int time_offset);
|
||||
void setup_ntp_client();
|
||||
|
||||
private:
|
||||
UDP *_udp;
|
||||
bool _udp_setup = false;
|
||||
|
||||
bool _sw_change = 1;
|
||||
const char *_pool_server_name = "pool.ntp.org"; // Default time server
|
||||
int _utcx = 0;
|
||||
IPAddress _pool_server_ip;
|
||||
long _time_offset = 0;
|
||||
unsigned int _port = NTP_DEFAULT_LOCAL_PORT;
|
||||
|
||||
unsigned long _update_interval = 60000; // In ms
|
||||
|
||||
unsigned int _date_day = 0;
|
||||
unsigned int _date_month = 0;
|
||||
unsigned int _date_year = 0;
|
||||
unsigned int _day_of_week = 0;
|
||||
unsigned long _current_epoc = 0; // In s
|
||||
unsigned long _last_secs_since_1900 = 0;
|
||||
unsigned long _last_update = 0; // In ms
|
||||
unsigned long _secs_since_1900 = 0; // seconds since 1. Januar 1900, 00:00:00
|
||||
|
||||
unsigned char _packet_buffer[NTP_PACKET_SIZE] = {0};
|
||||
void send_ntp_packet();
|
||||
void set_summertime(bool summertime);
|
||||
|
||||
static const unsigned long milliseconds_per_second = 1000;
|
||||
static const unsigned long minutes_per_hour = 60;
|
||||
static const unsigned long seconds_per_day = 86400;
|
||||
static const unsigned long seconds_per_hour = 3600;
|
||||
static const unsigned long seconds_per_minute = 60;
|
||||
|
||||
// number of days in months
|
||||
unsigned int _days_per_month[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
};
|
||||
|
||||
void wait(unsigned long time_ms);
|
||||
|
||||
#endif /* NTPCLIENTPLUS_H */
|
||||
@@ -6,8 +6,10 @@
|
||||
// ----------------------------------------------------------------------------------
|
||||
// CONSTANTS
|
||||
// ----------------------------------------------------------------------------------
|
||||
#define AP_SSID "WordclockAP" // SSID name of Access Point
|
||||
#define NTP_SERVER_URL "de.pool.ntp.org" // NTP server address
|
||||
#define AP_SSID "WordclockAP" // SSID name of Access Point
|
||||
#define NTP_SERVER_URL "de.pool.ntp.org" // NTP server address
|
||||
#define MY_TZ "CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00" // Timezone
|
||||
|
||||
#define HOSTNAME (String("wordclock")) // Local hostname
|
||||
#define LOGGER_MULTICAST_IP (IPAddress(230, 120, 10, 2)) // IP for UDP server
|
||||
#define LOGGER_MULTICAST_PORT (8123) // Port for UDP server
|
||||
|
||||
@@ -66,6 +66,8 @@ void handle_current_state(void);
|
||||
void handle_data_request(void);
|
||||
void handle_led_direct(void);
|
||||
void limit_value_ranges(void);
|
||||
void log_time(tm local_time);
|
||||
void ntp_time_update(uint32 *last_ntp_update_us);
|
||||
void ntp_time_update(uint32 *last_ntp_update_us);
|
||||
void on_state_entry(uint8_t state);
|
||||
void read_settings_from_EEPROM(void);
|
||||
|
||||
@@ -16,6 +16,7 @@ platform = espressif8266
|
||||
board = nodemcuv2
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
adafruit/Adafruit BusIO@^1.15.0
|
||||
adafruit/Adafruit NeoMatrix@^1.3.0
|
||||
adafruit/Adafruit NeoPixel@^1.11.0
|
||||
tzapu/WiFiManager@^0.16.0
|
||||
|
||||
@@ -1,658 +0,0 @@
|
||||
#include <Arduino.h>
|
||||
#include "ntp_client_plus.h"
|
||||
|
||||
/**
|
||||
* @brief Construct a new NTPClientPlus::NTPClientPlus object
|
||||
*
|
||||
* @param udp UDP client
|
||||
* @param pool_server_name time server name
|
||||
* @param utcx UTC offset (in 1h)
|
||||
* @param sw_change should summer/winter time be considered
|
||||
*/
|
||||
NTPClientPlus::NTPClientPlus(UDP &udp, const char *pool_server_name, int utcx, bool sw_change)
|
||||
{
|
||||
this->_udp = &udp;
|
||||
this->_utcx = utcx;
|
||||
this->_time_offset = this->seconds_per_hour * this->_utcx;
|
||||
this->_pool_server_name = pool_server_name;
|
||||
this->_sw_change = sw_change;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts the underlying UDP client, get first NTP timestamp and calc date
|
||||
*
|
||||
*/
|
||||
void NTPClientPlus::setup_ntp_client()
|
||||
{
|
||||
this->_udp->begin(this->_port);
|
||||
this->_udp_setup = true;
|
||||
this->update_ntp();
|
||||
this->calc_date();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get new update from NTP
|
||||
*
|
||||
* @return NTP_UPDATE_TIMEOUT timeout after 500 ms
|
||||
* @return NTP_UPDATE_SUCCESS after successful update
|
||||
* @return NTP_UPDATE_DIFFTOOHIGH too much difference to previous received time (try again)
|
||||
* @return NTP_UPDATE_TIME_INVALID time value is invalid
|
||||
*/
|
||||
int NTPClientPlus::update_ntp()
|
||||
{
|
||||
// flush any existing packets
|
||||
while (this->_udp->parsePacket() != 0)
|
||||
{
|
||||
this->_udp->flush();
|
||||
}
|
||||
|
||||
this->send_ntp_packet();
|
||||
|
||||
// Wait till data is there or timeout...
|
||||
uint8_t conn_tries = 0;
|
||||
int received_bytes = 0;
|
||||
|
||||
while ((received_bytes == 0) && (conn_tries++ <= MAX_NTP_CONN_TRIES))
|
||||
{
|
||||
received_bytes = this->_udp->parsePacket();
|
||||
wait(NTP_RECEIVE_WAIT_TIME_MS);
|
||||
}
|
||||
|
||||
if (conn_tries >= MAX_NTP_CONN_TRIES)
|
||||
{
|
||||
return NTP_UPDATE_TIMEOUT;
|
||||
}
|
||||
|
||||
this->_udp->read(this->_packet_buffer, NTP_PACKET_SIZE);
|
||||
|
||||
unsigned long high_word = word(this->_packet_buffer[40], this->_packet_buffer[41]);
|
||||
unsigned long low_word = word(this->_packet_buffer[42], this->_packet_buffer[43]);
|
||||
// combine the four bytes (two words) into a long integer
|
||||
// this is NTP time (seconds since Jan 1 1900):
|
||||
unsigned long temp_secs_since_1900 = high_word << 16 | low_word;
|
||||
|
||||
if (temp_secs_since_1900 < UNIX_TIMESTAMP_1900) // NTP time is not valid
|
||||
{
|
||||
return NTP_UPDATE_TIME_INVALID;
|
||||
}
|
||||
|
||||
// check if time off last ntp update is roughly in the same range: 100sec apart (validation check)
|
||||
if (this->_last_secs_since_1900 == 0 || temp_secs_since_1900 - this->_last_secs_since_1900 < 100000)
|
||||
{
|
||||
// Only update time then account for delay in reading the time
|
||||
this->_last_update = (system_get_time() / 1000) - (NTP_RECEIVE_WAIT_TIME_MS * (conn_tries + 1));
|
||||
this->_secs_since_1900 = temp_secs_since_1900;
|
||||
this->_current_epoc = this->_secs_since_1900 - UNIX_TIMESTAMP_1900;
|
||||
|
||||
// Remember time of last update
|
||||
this->_last_secs_since_1900 = temp_secs_since_1900;
|
||||
return NTP_UPDATE_SUCCESS; // return 0 after successful update
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remember time of last update
|
||||
this->_last_secs_since_1900 = temp_secs_since_1900;
|
||||
return NTP_UPDATE_DIFFTOOHIGH;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops the underlying UDP client
|
||||
*
|
||||
*/
|
||||
void NTPClientPlus::end()
|
||||
{
|
||||
this->_udp->stop();
|
||||
this->_udp_setup = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Setter TimeOffset
|
||||
*
|
||||
* @param time_offset offset from UTC in seconds
|
||||
*/
|
||||
void NTPClientPlus::set_time_offset(int time_offset)
|
||||
{
|
||||
this->_time_offset = time_offset;
|
||||
}
|
||||
|
||||
long NTPClientPlus::get_time_offset()
|
||||
{
|
||||
return this->_time_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set time server name
|
||||
*
|
||||
* @param pool_server_name
|
||||
*/
|
||||
void NTPClientPlus::set_pool_server_name(const char *pool_server_name)
|
||||
{
|
||||
this->_pool_server_name = pool_server_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calc seconds since 1. Jan. 1900
|
||||
*
|
||||
* @return unsigned long seconds since 1. Jan. 1900
|
||||
*/
|
||||
unsigned long NTPClientPlus::get_secs_since_1900() const
|
||||
{
|
||||
return this->_time_offset + // User offset
|
||||
this->_secs_since_1900 + // seconds returned by the NTP server
|
||||
(((system_get_time() / 1000) - this->_last_update) / 1000); // Time since last update
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get UNIX Epoch time since 1. Jan. 1970
|
||||
*
|
||||
* @return unsigned long UNIX Epoch time since 1. Jan. 1970 in seconds
|
||||
*/
|
||||
unsigned long NTPClientPlus::get_epoch_time() const
|
||||
{
|
||||
return this->get_secs_since_1900() - UNIX_TIMESTAMP_1900;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get current hours in 24h format
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int NTPClientPlus::get_hours_24() const
|
||||
{
|
||||
int hours = ((this->get_epoch_time() % 86400L) / 3600);
|
||||
return hours;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get current hours in 12h format
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int NTPClientPlus::get_hours_12() const
|
||||
{
|
||||
return this->get_hours_24() % 12;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get current minutes
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int NTPClientPlus::get_minutes() const
|
||||
{
|
||||
return ((this->get_epoch_time() % 3600) / 60);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get current seconds
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int NTPClientPlus::get_seconds() const
|
||||
{
|
||||
return this->get_epoch_time() % 60;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return String time formatted like `hh:mm:ss`
|
||||
*/
|
||||
String NTPClientPlus::get_formatted_time() const
|
||||
{
|
||||
unsigned long raw_time = this->get_epoch_time();
|
||||
unsigned long hours = (raw_time % 86400L) / 3600;
|
||||
String hours_str = hours < 10 ? "0" + String(hours) : String(hours);
|
||||
|
||||
unsigned long minutes = (raw_time % 3600) / 60;
|
||||
String minute_str = minutes < 10 ? "0" + String(minutes) : String(minutes);
|
||||
|
||||
unsigned long seconds = raw_time % 60;
|
||||
String second_str = seconds < 10 ? "0" + String(seconds) : String(seconds);
|
||||
|
||||
return hours_str + ":" + minute_str + ":" + second_str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return String date formatted like `dd.mm.yyyy`
|
||||
*/
|
||||
String NTPClientPlus::get_formatted_date()
|
||||
{
|
||||
this->calc_date();
|
||||
unsigned int dateDay = this->_date_day;
|
||||
unsigned int dateMonth = this->_date_month;
|
||||
unsigned int dateYear = this->_date_year;
|
||||
|
||||
String dayStr = dateDay < 10 ? "0" + String(dateDay) : String(dateDay);
|
||||
String monthStr = dateMonth < 10 ? "0" + String(dateMonth) : String(dateMonth);
|
||||
String yearStr = dateYear < 10 ? "0" + String(dateYear) : String(dateYear);
|
||||
|
||||
return dayStr + "." + monthStr + "." + yearStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calc date from seconds since 1900
|
||||
*
|
||||
*/
|
||||
void NTPClientPlus::calc_date()
|
||||
{
|
||||
// get days since 1900
|
||||
unsigned long days1900 = this->get_secs_since_1900() / seconds_per_day;
|
||||
|
||||
// calc current year
|
||||
this->_date_year = this->get_year();
|
||||
|
||||
// calc how many leap days since 1.Jan 1900
|
||||
int leap_days = 0;
|
||||
for (unsigned int i = 1900; i < this->_date_year; i++)
|
||||
{
|
||||
// check if leap year
|
||||
if (this->is_leap_year(i))
|
||||
{
|
||||
leap_days++;
|
||||
}
|
||||
}
|
||||
leap_days = leap_days - 1;
|
||||
|
||||
// check if current year is leap year
|
||||
if (this->is_leap_year(this->_date_year))
|
||||
{
|
||||
_days_per_month[2] = 29;
|
||||
}
|
||||
else
|
||||
{
|
||||
_days_per_month[2] = 28;
|
||||
}
|
||||
|
||||
unsigned int day_of_year = (days1900 - ((this->_date_year - 1900) * 365) - leap_days);
|
||||
|
||||
// calc current month
|
||||
this->_date_month = this->get_month(day_of_year);
|
||||
|
||||
this->_date_day = 0;
|
||||
|
||||
// calc day of month
|
||||
for (unsigned int i = 0; i < this->_date_month; i++)
|
||||
{
|
||||
this->_date_day = this->_date_day + _days_per_month[i];
|
||||
}
|
||||
this->_date_day = day_of_year - this->_date_day;
|
||||
|
||||
// calc day of week:
|
||||
// Monday = 1, Tuesday = 2, Wednesday = 3, Thursday = 4, Friday = 5, Saturday = 6, Sunday = 7
|
||||
// 1. Januar 1900 was a monday
|
||||
this->_day_of_week = 1;
|
||||
|
||||
for (unsigned int i = 0; i < days1900; i++)
|
||||
{
|
||||
if (this->_day_of_week < 7)
|
||||
{
|
||||
this->_day_of_week = this->_day_of_week + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->_day_of_week = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// End: Calc date (dateDay, dateMonth, dateYear)
|
||||
|
||||
// calc if summer time active
|
||||
|
||||
this->check_daylight_saving_time();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter for day of the week
|
||||
*
|
||||
* @return unsigned int
|
||||
*/
|
||||
unsigned int NTPClientPlus::get_day_of_week()
|
||||
{
|
||||
return this->_day_of_week;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to calc current year
|
||||
*
|
||||
* @return unsigned int
|
||||
*/
|
||||
unsigned int NTPClientPlus::get_year()
|
||||
{
|
||||
unsigned long secs_since_1900 = this->get_secs_since_1900();
|
||||
|
||||
// NTP starts at 1. Jan 1900
|
||||
unsigned int result = 1900;
|
||||
unsigned int days_in_year = 0;
|
||||
unsigned int days = 0;
|
||||
unsigned int days_since_1900 = 0;
|
||||
|
||||
unsigned int for_i = 0;
|
||||
bool leap_year = false;
|
||||
|
||||
days_since_1900 = secs_since_1900 / this->seconds_per_day;
|
||||
|
||||
for (for_i = 0; for_i < days_since_1900; for_i++)
|
||||
{
|
||||
leap_year = this->is_leap_year(result);
|
||||
|
||||
if (leap_year)
|
||||
{
|
||||
days_in_year = 366;
|
||||
}
|
||||
else
|
||||
{
|
||||
days_in_year = 365;
|
||||
}
|
||||
days++;
|
||||
|
||||
if (days >= days_in_year)
|
||||
{
|
||||
result++;
|
||||
days = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to check if given year is leap year
|
||||
*
|
||||
* @param year
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool NTPClientPlus::is_leap_year(unsigned int year)
|
||||
{
|
||||
|
||||
bool result = false;
|
||||
|
||||
// check for leap year
|
||||
if ((year % 4) == 0)
|
||||
{
|
||||
result = true;
|
||||
|
||||
if ((year % 100) == 0)
|
||||
{
|
||||
result = false;
|
||||
|
||||
if ((year % 400) == 0)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get Month of given day of year
|
||||
*
|
||||
* @param day_of_year
|
||||
* @return int
|
||||
*/
|
||||
int NTPClientPlus::get_month(int day_of_year)
|
||||
{
|
||||
bool leap_year = this->is_leap_year(this->get_year());
|
||||
|
||||
// Month beginnings
|
||||
int month_min[13] = {0, 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335};
|
||||
// Month endings
|
||||
int month_max[13] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
|
||||
int month = 0;
|
||||
int y = 0;
|
||||
|
||||
// Calculation of the beginning and end of each month in the leap year
|
||||
if (leap_year == true)
|
||||
{
|
||||
for (y = 3; y < 13; y++)
|
||||
{
|
||||
++month_min[y];
|
||||
}
|
||||
|
||||
for (y = 2; y < 13; y++)
|
||||
{
|
||||
++month_max[y];
|
||||
}
|
||||
}
|
||||
|
||||
// January
|
||||
if (day_of_year >= month_min[1] && day_of_year <= month_max[1])
|
||||
{
|
||||
month = 1;
|
||||
}
|
||||
|
||||
// February
|
||||
if (day_of_year >= month_min[2] && day_of_year <= month_max[2])
|
||||
{
|
||||
month = 2;
|
||||
}
|
||||
|
||||
// March
|
||||
if (day_of_year >= month_min[3] && day_of_year <= month_max[3])
|
||||
{
|
||||
month = 3;
|
||||
}
|
||||
|
||||
// April
|
||||
if (day_of_year >= month_min[4] && day_of_year <= month_max[4])
|
||||
{
|
||||
month = 4;
|
||||
}
|
||||
|
||||
// May
|
||||
if (day_of_year >= month_min[5] && day_of_year <= month_max[5])
|
||||
{
|
||||
month = 5;
|
||||
}
|
||||
|
||||
// June
|
||||
if (day_of_year >= month_min[6] && day_of_year <= month_max[6])
|
||||
{
|
||||
month = 6;
|
||||
}
|
||||
|
||||
// July
|
||||
if (day_of_year >= month_min[7] && day_of_year <= month_max[7])
|
||||
{
|
||||
month = 7;
|
||||
}
|
||||
|
||||
// August
|
||||
if (day_of_year >= month_min[8] && day_of_year <= month_max[8])
|
||||
{
|
||||
month = 8;
|
||||
}
|
||||
|
||||
// September
|
||||
if (day_of_year >= month_min[9] && day_of_year <= month_max[9])
|
||||
{
|
||||
month = 9;
|
||||
}
|
||||
|
||||
// October
|
||||
if (day_of_year >= month_min[10] && day_of_year <= month_max[10])
|
||||
{
|
||||
month = 10;
|
||||
}
|
||||
|
||||
// November
|
||||
if (day_of_year >= month_min[11] && day_of_year <= month_max[11])
|
||||
{
|
||||
month = 11;
|
||||
}
|
||||
|
||||
// December
|
||||
if (day_of_year >= month_min[12] && day_of_year <= month_max[12])
|
||||
{
|
||||
month = 12;
|
||||
}
|
||||
|
||||
return month;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief (private) Send NTP Packet to NTP server
|
||||
*
|
||||
*/
|
||||
void NTPClientPlus::send_ntp_packet()
|
||||
{
|
||||
// set all bytes in the buffer to 0
|
||||
memset(this->_packet_buffer, 0, NTP_PACKET_SIZE);
|
||||
// Initialize values needed to form NTP request
|
||||
this->_packet_buffer[0] = 0b11100011; // LI, Version, Mode
|
||||
this->_packet_buffer[1] = 0; // Stratum, or type of clock
|
||||
this->_packet_buffer[2] = 6; // Polling Interval
|
||||
this->_packet_buffer[3] = 0xEC; // Peer Clock Precision
|
||||
// 8 bytes of zero for Root Delay & Root Dispersion
|
||||
this->_packet_buffer[12] = 49;
|
||||
this->_packet_buffer[13] = 0x4E;
|
||||
this->_packet_buffer[14] = 49;
|
||||
this->_packet_buffer[15] = 52;
|
||||
|
||||
// all NTP fields have been given values, now
|
||||
// you can send a packet requesting a timestamp:
|
||||
if (this->_pool_server_name)
|
||||
{
|
||||
this->_udp->beginPacket(this->_pool_server_name, 123);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->_udp->beginPacket(this->_pool_server_ip, 123);
|
||||
}
|
||||
this->_udp->write(this->_packet_buffer, NTP_PACKET_SIZE);
|
||||
this->_udp->endPacket();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief (private) Set time offset accordance to summer time
|
||||
*
|
||||
* @param summertime
|
||||
*/
|
||||
void NTPClientPlus::set_summertime(bool summertime)
|
||||
{
|
||||
if (summertime)
|
||||
{
|
||||
this->_time_offset = this->seconds_per_hour * (this->_utcx + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->_time_offset = this->seconds_per_hour * (this->_utcx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief (private) Update Summer/Winter time change
|
||||
*
|
||||
* @returns bool summertime active
|
||||
*/
|
||||
bool NTPClientPlus::check_daylight_saving_time()
|
||||
{
|
||||
unsigned int day_of_week = this->_day_of_week;
|
||||
unsigned int date_day = this->_date_day;
|
||||
unsigned int date_month = this->_date_month;
|
||||
|
||||
bool summertime_active = false;
|
||||
|
||||
if (this->_sw_change)
|
||||
{
|
||||
// Start: Set summer-/ winter time
|
||||
// current month is march
|
||||
if (date_month == 3)
|
||||
{
|
||||
|
||||
// it is last week in march
|
||||
if ((this->_days_per_month[3] - date_day) < 7)
|
||||
{
|
||||
// Example year 2020: March 31 days; Restart March 26, 2020 (Thursday = weekday = 4); 5 days remaining; Last Sunday March 29, 2020
|
||||
// Calculation: 31 - 26 = 5; 5 + 4 = 9;
|
||||
// Result: Last day in March is a Tuesday. There folfalses another Sunday in October => set winter time
|
||||
|
||||
// Example year 2021: March 31 days; Restart March 30, 2021 (Tuesday = weekday = 2); 1 days remaining; Last Sunday March 28, 2021
|
||||
// Calculation: 31 - 30 = 1; 1 + 2 = 3;
|
||||
// Result: Last day in March is a Wednesday. Changeover to summer time already done => set summer time
|
||||
|
||||
// There folfalses within the last week in March one more Sunday => set winter time
|
||||
if (((this->_days_per_month[3] - date_day) + day_of_week) >= 7)
|
||||
{
|
||||
this->set_summertime(0);
|
||||
summertime_active = false;
|
||||
}
|
||||
else // last sunday in march already over -> summer time
|
||||
{
|
||||
this->set_summertime(1);
|
||||
summertime_active = true;
|
||||
}
|
||||
}
|
||||
else // restart in first three weeks of march -> winter time
|
||||
{
|
||||
this->set_summertime(0);
|
||||
summertime_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
// current month is october
|
||||
else if (date_month == 10)
|
||||
{
|
||||
// restart last week of october
|
||||
if ((this->_days_per_month[10] - date_day) < 7)
|
||||
{
|
||||
|
||||
// Example year 2020: October 31 days; restart October 26, 2020 (Monday = weekday = 1); 5 days remaining; last Sunday October 25, 2020
|
||||
// Calculation: 31 - 26 = 5; 5 + 1 = 6;
|
||||
// Result: Last day in October is a Saturday. Changeover to winter time already done => set winter time
|
||||
|
||||
// Example year 2021: October 31 days; Restart 26. October 2021 (Tuesday = weekday = 2); 5 days remaining; Last Sunday 31. October 2021
|
||||
// Calculation: 31 - 26 = 5; 5 + 2 = 7;
|
||||
// Result: Last day in October is a Sunday. There folfalses another Sunday in October => set summer time
|
||||
|
||||
// There folfalses within the last week in October one more Sunday => summer time
|
||||
if (((this->_days_per_month[10] - date_day) + day_of_week) >= 7)
|
||||
{
|
||||
this->set_summertime(1);
|
||||
summertime_active = true;
|
||||
}
|
||||
else // last sunday in october already over -> winter time
|
||||
{
|
||||
this->set_summertime(0);
|
||||
summertime_active = false;
|
||||
}
|
||||
}
|
||||
else // restart in first three weeks of october -> summer time
|
||||
{
|
||||
this->set_summertime(1);
|
||||
summertime_active = true;
|
||||
}
|
||||
}
|
||||
else if (date_month > 3 && date_month < 10) // restart in summer time
|
||||
{
|
||||
this->set_summertime(1);
|
||||
summertime_active = true;
|
||||
}
|
||||
else if (date_month < 3 || date_month > 10) // restart in winter time
|
||||
{
|
||||
this->set_summertime(0);
|
||||
summertime_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
return summertime_active;
|
||||
}
|
||||
|
||||
void wait(unsigned long time_ms)
|
||||
{
|
||||
unsigned long start = (system_get_time() / 1000); // in ms
|
||||
while (((system_get_time() / 1000) - start) < time_ms)
|
||||
{
|
||||
yield();
|
||||
};
|
||||
}
|
||||
@@ -29,15 +29,14 @@
|
||||
#include <EEPROM.h> //from ESP8266 Arduino Core (automatically installed when ESP8266 was installed via Boardmanager)
|
||||
#include <ESP8266WebServer.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager WiFi Configuration Magic
|
||||
#include <WiFiUdp.h>
|
||||
#include <time.h>
|
||||
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager WiFi Configuration Magic
|
||||
|
||||
// own libraries
|
||||
#include "animation_functions.h"
|
||||
#include "base64_wrapper.h" // copied from https://github.com/Xander-Electronics/Base64
|
||||
#include "led_matrix.h"
|
||||
#include "littlefs_wrapper.h"
|
||||
#include "ntp_client_plus.h"
|
||||
#include "ota_functions.h"
|
||||
#include "pong.h"
|
||||
#include "render_functions.h"
|
||||
@@ -49,14 +48,15 @@
|
||||
// ----------------------------------------------------------------------------------
|
||||
// GLOBAL VARIABLES
|
||||
// ----------------------------------------------------------------------------------
|
||||
UDPLogger logger; // Logger
|
||||
Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(MATRIX_WIDTH, MATRIX_HEIGHT + 1, NEOPIXEL_PIN,
|
||||
NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_ZIGZAG,
|
||||
NEO_GRB + NEO_KHZ800); // NeoMatrix
|
||||
UDPLogger logger; // Logger
|
||||
char strftime_buf[64]; // Time string buffer
|
||||
ESP8266WebServer webserver(HTTP_PORT); // Webserver
|
||||
LEDMatrix led_matrix = LEDMatrix(&matrix, DEFAULT_BRIGHTNESS, &logger); // NeoMatrix wrapper
|
||||
WiFiUDP wifi_udp;
|
||||
NTPClientPlus ntp_client = NTPClientPlus(wifi_udp, NTP_SERVER_URL, 1, true);
|
||||
struct tm timeinfo; // Structure tm holds time information
|
||||
time_t now; // Seconds since Epoch (1970) - UTC
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// STATIC VARIABLES
|
||||
@@ -70,6 +70,8 @@ static Pong pong = Pong(&led_matrix, &logger);
|
||||
static Snake snake = Snake(&led_matrix, &logger);
|
||||
static Tetris tetris = Tetris(&led_matrix, &logger);
|
||||
|
||||
static uint32 last_ntp_update_us = 0; // time of last NTP update
|
||||
|
||||
static bool flg_night_mode = false; // state of nightmode
|
||||
static bool flg_reset_wifi_creds = false; // used to reset stored wifi credentials
|
||||
static bool spiral_direction = false;
|
||||
@@ -87,7 +89,7 @@ static const uint32_t period_timings[NUM_STATES] = {PERIOD_CLOCK_UPDATE_US, PERI
|
||||
PERIOD_ANIMATION_US, PERIOD_TETRIS_US, PERIOD_SNAKE_US,
|
||||
PERIOD_PONG_US, PERIOD_ANIMATION_US};
|
||||
|
||||
// Quarterly brightness factor for dynamic brightness
|
||||
// Quarterly brightness factor for dynamic brightness (4 quarters a 24 hours)
|
||||
static const float qtly_brightness_factor[96] = {
|
||||
0.0f, 0.0f, 0.0f, 0.001f, 0.003f, 0.007f, 0.014f, 0.026f, 0.044f, 0.069f, 0.101f, 0.143f, 0.194f, 0.253f, 0.32f,
|
||||
0.392f, 0.468f, 0.545f, 0.62f, 0.691f, 0.755f, 0.811f, 0.858f, 0.896f, 0.927f, 0.949f, 0.966f, 0.978f, 0.986f,
|
||||
@@ -212,17 +214,13 @@ void setup()
|
||||
}
|
||||
|
||||
// setup NTP
|
||||
ntp_client.setup_ntp_client();
|
||||
logger.log_string("NTP running");
|
||||
logger.log_string("Time: " + ntp_client.get_formatted_time());
|
||||
logger.log_string("TimeOffset (seconds): " + String(ntp_client.get_time_offset()));
|
||||
configTime(MY_TZ, NTP_SERVER_URL);
|
||||
ntp_time_update(&last_ntp_update_us); // NTP time update
|
||||
|
||||
// show the current time for short time in words
|
||||
int hours = ntp_client.get_hours_24();
|
||||
int minutes = ntp_client.get_minutes();
|
||||
String timeMessage = time_to_string(hours, minutes);
|
||||
String timeMessage = time_to_string(timeinfo.tm_hour, timeinfo.tm_min);
|
||||
show_string_on_clock(timeMessage, main_color_clock);
|
||||
draw_minute_indicator(minutes, main_color_clock);
|
||||
draw_minute_indicator(timeinfo.tm_min, main_color_clock);
|
||||
led_matrix.draw_on_matrix_smooth(filter_factor);
|
||||
|
||||
// init all animation modes
|
||||
@@ -233,7 +231,7 @@ void setup()
|
||||
// init random tetris
|
||||
random_tetris(true);
|
||||
|
||||
// Range limits
|
||||
// Set range limits
|
||||
limit_value_ranges();
|
||||
|
||||
logger.log_string("Nightmode starts at: " + String(night_mode_times_ps->start_hour) + ":" + String(night_mode_times_ps->start_min));
|
||||
@@ -256,7 +254,6 @@ void loop()
|
||||
static uint32 last_matrix_update_us = 0; // time of last Matrix update
|
||||
static uint32 last_heartbeat_us = 0; // time of last heartbeat sending
|
||||
static uint32 last_nightmode_check_us = 0; // time of last nightmode check
|
||||
static uint32 last_ntp_update_us = 0; // time of last NTP update
|
||||
|
||||
handleOTA(); // handle OTA
|
||||
|
||||
@@ -313,69 +310,95 @@ void loop()
|
||||
// OTHER FUNCTIONS
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Updates the NTP time
|
||||
*
|
||||
* @return boolean - true if NTP update was successful, false otherwise
|
||||
*/
|
||||
bool get_ntp_time(uint32 sec)
|
||||
{
|
||||
uint32 start = system_get_time() / 1000; // ms
|
||||
do
|
||||
{
|
||||
time(&now);
|
||||
localtime_r(&now, &timeinfo);
|
||||
delay(10);
|
||||
} while (((system_get_time() / 1000 - start) <= (1000 * sec)) && (timeinfo.tm_year < (2023 - 1900)));
|
||||
|
||||
if (timeinfo.tm_year <= (2023 - 1900))
|
||||
{
|
||||
return false; // the NTP call was not successful
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void log_time(tm local_time)
|
||||
{
|
||||
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
|
||||
logger.log_string(String(strftime_buf));
|
||||
}
|
||||
|
||||
void handle_current_state()
|
||||
{
|
||||
switch (current_state)
|
||||
{
|
||||
case ST_CLOCK: // state clock
|
||||
{
|
||||
int hours = ntp_client.get_hours_24();
|
||||
int minutes = ntp_client.get_minutes();
|
||||
|
||||
(void)show_string_on_clock(time_to_string((uint8_t)hours, (uint8_t)minutes), main_color_clock);
|
||||
draw_minute_indicator((uint8_t)minutes, main_color_clock);
|
||||
break;
|
||||
}
|
||||
case ST_DICLOCK: // state diclock
|
||||
{
|
||||
int hours = ntp_client.get_hours_24();
|
||||
int minutes = ntp_client.get_minutes();
|
||||
show_digital_clock((uint8_t)hours, (uint8_t)minutes, main_color_clock);
|
||||
break;
|
||||
}
|
||||
case ST_SPIRAL: // state spiral
|
||||
{
|
||||
int res = draw_spiral(false, spiral_direction, MATRIX_WIDTH - 2);
|
||||
if ((bool)res && spiral_direction == 0)
|
||||
case ST_CLOCK: // state clock
|
||||
{
|
||||
// change spiral direction to closing (draw empty leds)
|
||||
spiral_direction = true;
|
||||
// init spiral with new spiral direction
|
||||
draw_spiral(true, spiral_direction, MATRIX_WIDTH - 1);
|
||||
(void)show_string_on_clock(time_to_string((uint8_t)timeinfo.tm_hour, (uint8_t)timeinfo.tm_min), main_color_clock);
|
||||
draw_minute_indicator((uint8_t)timeinfo.tm_min, main_color_clock);
|
||||
break;
|
||||
}
|
||||
else if (res && spiral_direction == 1)
|
||||
case ST_DICLOCK: // state diclock
|
||||
{
|
||||
// reset spiral direction to normal drawing leds
|
||||
spiral_direction = false;
|
||||
// init spiral with new spiral direction
|
||||
draw_spiral(true, spiral_direction, MATRIX_WIDTH - 1);
|
||||
show_digital_clock((uint8_t)timeinfo.tm_hour, (uint8_t)timeinfo.tm_min, main_color_clock);
|
||||
break;
|
||||
}
|
||||
case ST_SPIRAL: // state spiral
|
||||
{
|
||||
int res = draw_spiral(false, spiral_direction, MATRIX_WIDTH - 2);
|
||||
if ((bool)res && spiral_direction == 0)
|
||||
{
|
||||
// change spiral direction to closing (draw empty leds)
|
||||
spiral_direction = true;
|
||||
// init spiral with new spiral direction
|
||||
draw_spiral(true, spiral_direction, MATRIX_WIDTH - 1);
|
||||
}
|
||||
else if (res && spiral_direction == 1)
|
||||
{
|
||||
// reset spiral direction to normal drawing leds
|
||||
spiral_direction = false;
|
||||
// init spiral with new spiral direction
|
||||
draw_spiral(true, spiral_direction, MATRIX_WIDTH - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ST_TETRIS: // state tetris
|
||||
{
|
||||
tetris.loopCycle();
|
||||
break;
|
||||
}
|
||||
case ST_SNAKE: // state snake
|
||||
{
|
||||
snake.loopCycle();
|
||||
break;
|
||||
}
|
||||
case ST_PINGPONG: // state ping pong
|
||||
{
|
||||
pong.loopCycle();
|
||||
break;
|
||||
}
|
||||
case ST_HEARTS:
|
||||
{
|
||||
draw_heart_animation();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ST_TETRIS: // state tetris
|
||||
{
|
||||
tetris.loopCycle();
|
||||
break;
|
||||
}
|
||||
case ST_SNAKE: // state snake
|
||||
{
|
||||
snake.loopCycle();
|
||||
break;
|
||||
}
|
||||
case ST_PINGPONG: // state ping pong
|
||||
{
|
||||
pong.loopCycle();
|
||||
break;
|
||||
}
|
||||
case ST_HEARTS:
|
||||
{
|
||||
draw_heart_animation();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,8 +447,8 @@ void check_wifi_status()
|
||||
void check_night_mode()
|
||||
{
|
||||
// check if nightmode need to be activated
|
||||
int hours = ntp_client.get_hours_24();
|
||||
int minutes = ntp_client.get_minutes();
|
||||
int hours = timeinfo.tm_hour;
|
||||
int minutes = timeinfo.tm_min;
|
||||
|
||||
if ((hours == night_mode_times_ps->start_hour) && (minutes == night_mode_times_ps->start_min))
|
||||
{
|
||||
@@ -445,44 +468,19 @@ void check_night_mode()
|
||||
void ntp_time_update(uint32 *last_ntp_update_us)
|
||||
{
|
||||
// NTP time update
|
||||
int ntp_retval = ntp_client.update_ntp();
|
||||
bool ntp_retval = get_ntp_time(*last_ntp_update_us / 10000000);
|
||||
|
||||
switch (ntp_retval)
|
||||
if (ntp_retval == true)
|
||||
{
|
||||
case NTP_UPDATE_SUCCESS:
|
||||
{
|
||||
ntp_client.calc_date();
|
||||
logger.log_string("NTP-Update successful, Time: " + ntp_client.get_formatted_time());
|
||||
log_time(timeinfo);
|
||||
*last_ntp_update_us = system_get_time();
|
||||
watchdog_counter = 30;
|
||||
break;
|
||||
}
|
||||
case NTP_UPDATE_TIMEOUT:
|
||||
else
|
||||
{
|
||||
logger.log_string("NTP-Update not successful. Reason: Timeout");
|
||||
logger.log_string("NTP-Update was not successful.");
|
||||
*last_ntp_update_us += 10000000;
|
||||
watchdog_counter--;
|
||||
break;
|
||||
}
|
||||
case NTP_UPDATE_DIFFTOOHIGH:
|
||||
{
|
||||
logger.log_string("NTP-Update not successful. Reason: Too large time difference");
|
||||
logger.log_string("Time: " + ntp_client.get_formatted_time());
|
||||
logger.log_string("Date: " + ntp_client.get_formatted_date());
|
||||
logger.log_string("TimeOffset (seconds): " + String(ntp_client.get_time_offset()));
|
||||
logger.log_string("Summertime: " + String(ntp_client.check_daylight_saving_time()));
|
||||
*last_ntp_update_us += 10000000;
|
||||
watchdog_counter--;
|
||||
break;
|
||||
}
|
||||
case NTP_UPDATE_TIME_INVALID:
|
||||
default:
|
||||
{
|
||||
logger.log_string("NTP-Update not successful. Reason: NTP time not valid (<1970)");
|
||||
*last_ntp_update_us += 10000000;
|
||||
watchdog_counter--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
logger.log_string("Watchdog counter: " + String(watchdog_counter));
|
||||
@@ -504,34 +502,34 @@ void on_state_entry(uint8_t state)
|
||||
filter_factor = 0.5f;
|
||||
switch (state)
|
||||
{
|
||||
case ST_SPIRAL:
|
||||
{
|
||||
spiral_direction = 0; // Init spiral with normal drawing mode
|
||||
draw_spiral(true, spiral_direction, MATRIX_WIDTH - 1);
|
||||
break;
|
||||
}
|
||||
case ST_TETRIS:
|
||||
{
|
||||
filter_factor = 1.0f; // no smoothing
|
||||
tetris.ctrlStart();
|
||||
break;
|
||||
}
|
||||
case ST_SNAKE:
|
||||
{
|
||||
filter_factor = 1.0f; // no smoothing
|
||||
snake.initGame();
|
||||
break;
|
||||
}
|
||||
case ST_PINGPONG:
|
||||
{
|
||||
filter_factor = 1.0f; // no smoothing
|
||||
pong.initGame(1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case ST_SPIRAL:
|
||||
{
|
||||
spiral_direction = 0; // Init spiral with normal drawing mode
|
||||
draw_spiral(true, spiral_direction, MATRIX_WIDTH - 1);
|
||||
break;
|
||||
}
|
||||
case ST_TETRIS:
|
||||
{
|
||||
filter_factor = 1.0f; // no smoothing
|
||||
tetris.ctrlStart();
|
||||
break;
|
||||
}
|
||||
case ST_SNAKE:
|
||||
{
|
||||
filter_factor = 1.0f; // no smoothing
|
||||
snake.initGame();
|
||||
break;
|
||||
}
|
||||
case ST_PINGPONG:
|
||||
{
|
||||
filter_factor = 1.0f; // no smoothing
|
||||
pong.initGame(1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1032,9 +1030,9 @@ uint8_t update_brightness()
|
||||
{
|
||||
new_brightness = calculate_dynamic_brightness(brightness_ps->dyn_brightness_min,
|
||||
brightness_ps->dyn_brightness_max,
|
||||
ntp_client.get_hours_24(),
|
||||
ntp_client.get_minutes(),
|
||||
ntp_client.check_daylight_saving_time());
|
||||
timeinfo.tm_hour,
|
||||
timeinfo.tm_min,
|
||||
timeinfo.tm_isdst);
|
||||
}
|
||||
else // use static brightness
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user