Version 0.9
This commit is contained in:
140
src/Scroller.cpp
Normal file
140
src/Scroller.cpp
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
#include "Scroller.h"
|
||||||
|
|
||||||
|
Scroller::Scroller(int max_loops)
|
||||||
|
{
|
||||||
|
_max_loops = max_loops;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scroller::SetMatrix(Adafruit_NeoMatrix *matrix)
|
||||||
|
{
|
||||||
|
this->_matrix = matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Scroller::GetNumberOfLines()
|
||||||
|
{
|
||||||
|
return this->_nlines;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Scroller::AddLine(String line)
|
||||||
|
{
|
||||||
|
this->_Lines[this->_nlines] = line;
|
||||||
|
return _nlines++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Scroller::AddLines(String* lines,int nlines)
|
||||||
|
{
|
||||||
|
for (int i=0; i < nlines; i++) {
|
||||||
|
_Lines[i] = lines[i];
|
||||||
|
}
|
||||||
|
_nlines = nlines;
|
||||||
|
|
||||||
|
return _nlines;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Scroller::ReplaceLine(int number,String line)
|
||||||
|
{
|
||||||
|
_Lines[number] = line;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scroller::DeleteLines()
|
||||||
|
{
|
||||||
|
_nlines = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Scroller::Scroll(int tick)
|
||||||
|
{
|
||||||
|
int mx = 32;
|
||||||
|
String line;
|
||||||
|
|
||||||
|
line = _Lines[_lp];
|
||||||
|
|
||||||
|
if (line.length() * 6 > mx)
|
||||||
|
{
|
||||||
|
if (_x < line.length() * 6 - mx)
|
||||||
|
{
|
||||||
|
_matrix->fillScreen(0);
|
||||||
|
_matrix->setCursor(-_x, _y);
|
||||||
|
_matrix->setTextColor(_colors[1]);
|
||||||
|
_matrix->print(line);
|
||||||
|
_matrix->show();
|
||||||
|
if (_x++ == 0) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_lp++;
|
||||||
|
_x = 0;
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_matrix->fillScreen(0);
|
||||||
|
_matrix->setCursor(_x, _y);
|
||||||
|
_matrix->setTextColor(_colors[1]);
|
||||||
|
_matrix->print(line);
|
||||||
|
_matrix->show();
|
||||||
|
_lp++;
|
||||||
|
return 30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Scroller::TurnOn()
|
||||||
|
{
|
||||||
|
_off = false;
|
||||||
|
_lp = 0;
|
||||||
|
_x = 0;
|
||||||
|
_y = 0;
|
||||||
|
_nscrolled = 0;
|
||||||
|
_delayTicks = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scroller::TurnOff()
|
||||||
|
{
|
||||||
|
_matrix->fillScreen(0);
|
||||||
|
_matrix->print("");
|
||||||
|
_matrix->show();
|
||||||
|
_off = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scroller::SetColors(uint16_t *colors)
|
||||||
|
{
|
||||||
|
_colors = colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scroller::loop(int tick)
|
||||||
|
{
|
||||||
|
if (_off) return;
|
||||||
|
|
||||||
|
int delta = tick - _tick;
|
||||||
|
|
||||||
|
if (_lp == _nlines) {
|
||||||
|
_lp =0;
|
||||||
|
_nscrolled++;
|
||||||
|
_delayTicks = 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TimesScrolled() == _max_loops) {
|
||||||
|
TurnOff();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_delayTicks - delta <= 0) _delayTicks = Scroll(tick);
|
||||||
|
else _delayTicks -= delta;
|
||||||
|
|
||||||
|
if (_delayTicks < 0) _delayTicks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Scroller::TimesScrolled()
|
||||||
|
{
|
||||||
|
return _nscrolled;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scroller::~Scroller()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
44
src/Scroller.h
Normal file
44
src/Scroller.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#ifndef SCROLLER_H
|
||||||
|
#define SCROLLER_H
|
||||||
|
#include <Adafruit_GFX.h>
|
||||||
|
#include <Adafruit_NeoMatrix.h>
|
||||||
|
#include <Adafruit_NeoPixel.h>
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <ESP32Ticker.h>
|
||||||
|
|
||||||
|
#define SCROLLER_TICK_TIME 100 //ms
|
||||||
|
|
||||||
|
class Scroller
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/* data */
|
||||||
|
const static int MAX_LINES = 10;
|
||||||
|
String _Lines[MAX_LINES];
|
||||||
|
int _nlines = 0;
|
||||||
|
int _lp = 0;
|
||||||
|
int _tick=0;
|
||||||
|
int _delayTicks = 0;
|
||||||
|
int _nscrolled = 0;
|
||||||
|
int _x = 0, _y = 0;
|
||||||
|
Adafruit_NeoMatrix *_matrix;
|
||||||
|
uint16_t *_colors;
|
||||||
|
int _max_loops;
|
||||||
|
bool _off = true;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Scroller(int max_loops);
|
||||||
|
bool TurnOn();
|
||||||
|
void SetColors(uint16_t *colors);
|
||||||
|
void SetMatrix(Adafruit_NeoMatrix *matrix);
|
||||||
|
int AddLine(String line);
|
||||||
|
int AddLines(String* lines,int nlines);
|
||||||
|
void DeleteLines();
|
||||||
|
bool ReplaceLine(int number,String line);
|
||||||
|
int GetNumberOfLines();
|
||||||
|
int Scroll(int tick);
|
||||||
|
int TimesScrolled();
|
||||||
|
void TurnOff();
|
||||||
|
void loop(int tick);
|
||||||
|
~Scroller();
|
||||||
|
};
|
||||||
|
#endif
|
||||||
209
src/TimeZone.cpp
Normal file
209
src/TimeZone.cpp
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
#include "TimeZone.h"
|
||||||
|
|
||||||
|
void TimeZone::ruleDST(const char* tzName, int8_t week, int8_t wday, int8_t month, int8_t hour, int tzOffset) {
|
||||||
|
strcpy(dstStart.tzName, tzName);
|
||||||
|
dstStart.week = week;
|
||||||
|
dstStart.wday = wday;
|
||||||
|
dstStart.month = month;
|
||||||
|
dstStart.hour = hour;
|
||||||
|
dstStart.tzOffset = tzOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* TimeZone::ruleDST() {
|
||||||
|
if(dstZone) {
|
||||||
|
return ctime(&dstTime);
|
||||||
|
}
|
||||||
|
else return RULE_DST_MESSAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeZone::ruleSTD(const char* tzName, int8_t week, int8_t wday, int8_t month, int8_t hour, int tzOffset) {
|
||||||
|
strcpy(dstEnd.tzName, tzName);
|
||||||
|
dstEnd.week = week;
|
||||||
|
dstEnd.wday = wday;
|
||||||
|
dstEnd.month = month;
|
||||||
|
dstEnd.hour = hour;
|
||||||
|
dstEnd.tzOffset = tzOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* TimeZone::ruleSTD() {
|
||||||
|
if(dstZone) {
|
||||||
|
return ctime(&stdTime);
|
||||||
|
}
|
||||||
|
else return RULE_STD_MESSAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* TimeZone::tzName() {
|
||||||
|
if (dstZone) {
|
||||||
|
if (summerTime()) return dstStart.tzName;
|
||||||
|
else return dstEnd.tzName;
|
||||||
|
}
|
||||||
|
return GMT_MESSAGE; // TODO add timeZoneOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeZone::timeZone(int8_t tzHours, int8_t tzMinutes) {
|
||||||
|
this->tzHours = tzHours;
|
||||||
|
this->tzMinutes = tzMinutes;
|
||||||
|
timezoneOffset = tzHours * 3600;
|
||||||
|
if (tzHours < 0) {
|
||||||
|
timezoneOffset -= tzMinutes * 60;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
timezoneOffset += tzMinutes * 60;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeZone::isDST(bool dstZone) {
|
||||||
|
this->dstZone = dstZone;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimeZone::isDST() {
|
||||||
|
return summerTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t TimeZone::epoch() {
|
||||||
|
currentTime();
|
||||||
|
return utcCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeZone::currentTime() {
|
||||||
|
utcCurrent = utcTime;
|
||||||
|
if (dstZone) {
|
||||||
|
if (summerTime()) {
|
||||||
|
local = utcCurrent + dstOffset + timezoneOffset;
|
||||||
|
current = gmtime(&local);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
local = utcCurrent + timezoneOffset;
|
||||||
|
current = gmtime(&local);
|
||||||
|
}
|
||||||
|
if ((current->tm_year + 1900) > yearDST) beginDST();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
local = utcCurrent + timezoneOffset;
|
||||||
|
current = gmtime(&local);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t TimeZone::year() {
|
||||||
|
currentTime();
|
||||||
|
return current->tm_year + 1900;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t TimeZone::month() {
|
||||||
|
currentTime();
|
||||||
|
return current->tm_mon + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t TimeZone::day() {
|
||||||
|
currentTime();
|
||||||
|
return current->tm_mday;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t TimeZone::weekDay() {
|
||||||
|
currentTime();
|
||||||
|
return current->tm_wday;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t TimeZone::hours() {
|
||||||
|
currentTime();
|
||||||
|
return current->tm_hour;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t TimeZone::minutes() {
|
||||||
|
currentTime();
|
||||||
|
return current->tm_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t TimeZone::seconds() {
|
||||||
|
currentTime();
|
||||||
|
return current->tm_sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeZone::begin() {
|
||||||
|
if (dstZone) {
|
||||||
|
timezoneOffset = dstEnd.tzOffset * SECS_PER_MINUTES;
|
||||||
|
dstOffset = (dstStart.tzOffset - dstEnd.tzOffset) * SECS_PER_MINUTES;
|
||||||
|
currentTime();
|
||||||
|
beginDST();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeZone& TimeZone::setUTCTime(time_t t) {
|
||||||
|
utcTime = t;
|
||||||
|
begin();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeZone& TimeZone::setLocalTime(time_t t) {
|
||||||
|
utcTime = t;
|
||||||
|
begin();
|
||||||
|
if (dstZone) {
|
||||||
|
if ((t > utcDST) && (t <= utcSTD)) {
|
||||||
|
t -= dstOffset + timezoneOffset;;
|
||||||
|
} else {
|
||||||
|
t -= timezoneOffset;
|
||||||
|
}
|
||||||
|
utcTime = t;
|
||||||
|
currentTime();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t TimeZone::getLocalTime() {
|
||||||
|
currentTime();
|
||||||
|
return local;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t TimeZone::getUTCTime() {
|
||||||
|
currentTime();
|
||||||
|
return utcTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* TimeZone::formattedTime(const char *format) {
|
||||||
|
currentTime();
|
||||||
|
memset(timeString, 0, sizeof(timeString));
|
||||||
|
strftime(timeString, sizeof(timeString), format, current);
|
||||||
|
return timeString;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeZone::beginDST() {
|
||||||
|
dstTime = calcDateDST(dstStart, current->tm_year + 1900);
|
||||||
|
utcDST = dstTime - (dstEnd.tzOffset * SECS_PER_MINUTES);
|
||||||
|
stdTime = calcDateDST(dstEnd, current->tm_year + 1900);
|
||||||
|
utcSTD = stdTime - (dstStart.tzOffset * SECS_PER_MINUTES);
|
||||||
|
yearDST = current->tm_year + 1900;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t TimeZone::calcDateDST(struct ruleDST rule, int year) {
|
||||||
|
uint8_t month = rule.month;
|
||||||
|
uint8_t week = rule.week;
|
||||||
|
if (week == 0) {
|
||||||
|
if (month++ > 11) {
|
||||||
|
month = 0;
|
||||||
|
year++;
|
||||||
|
}
|
||||||
|
week = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tm tm;
|
||||||
|
tm.tm_hour = rule.hour;
|
||||||
|
tm.tm_min = 0;
|
||||||
|
tm.tm_sec = 0;
|
||||||
|
tm.tm_mday = 1;
|
||||||
|
tm.tm_mon = month;
|
||||||
|
tm.tm_year = year - 1900;
|
||||||
|
time_t t = mktime(&tm);
|
||||||
|
|
||||||
|
t += ((rule.wday - tm.tm_wday + 7) % 7 + (week - 1) * 7 ) * SECS_PER_DAY;
|
||||||
|
if (rule.week == 0) t -= 7 * SECS_PER_DAY;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimeZone::summerTime() {
|
||||||
|
if ((utcCurrent > utcDST) && (utcCurrent <= utcSTD)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
206
src/TimeZone.h
Normal file
206
src/TimeZone.h
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
#ifndef TIMEZONE_H
|
||||||
|
#define TIMEZONE_H
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#ifndef NTP_H
|
||||||
|
#define SEVENTYYEARS 2208988800UL
|
||||||
|
#define NTP_PACKET_SIZE 48
|
||||||
|
#define NTP_DEFAULT_LOCAL_PORT 123
|
||||||
|
#define SECS_PER_MINUTES 60
|
||||||
|
#define SECS_PER_DAY 86400
|
||||||
|
|
||||||
|
#define GMT_MESSAGE "GMT +/- offset"
|
||||||
|
#define RULE_DST_MESSAGE "no DST rule"
|
||||||
|
#define RULE_STD_MESSAGE "no STD rule"
|
||||||
|
|
||||||
|
enum week_t {Last, First, Second, Third, Fourth};
|
||||||
|
enum dow_t {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
|
||||||
|
enum month_t {Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class TimeZone {
|
||||||
|
public:
|
||||||
|
|
||||||
|
struct ruleDST {
|
||||||
|
char tzName[6]; // five chars max
|
||||||
|
int8_t week; // First, Second, Third, Fourth, or Last week of the month
|
||||||
|
int8_t wday; // day of week, 0 = Sun, 2 = Mon, ... 6 = Sat
|
||||||
|
int8_t month; // 0 = Jan, 1 = Feb, ... 11=Dec
|
||||||
|
int8_t hour; // 0 - 23
|
||||||
|
int tzOffset; // offset from UTC in minutes
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set the rule for DST (daylight saving time)
|
||||||
|
* start date of DST
|
||||||
|
*
|
||||||
|
* @param tzName name of the time zone
|
||||||
|
* @param week Last, First, Second, Third, Fourth (0 - 4)
|
||||||
|
* @param wday Sun, Mon, Tue, Wed, Thu, Fri, Sat (0 - 7)
|
||||||
|
* @param month Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec (0 -11)
|
||||||
|
* @param hour the local hour when rule chages
|
||||||
|
* @param tzOffset sum of summertime and timezone offset
|
||||||
|
*/
|
||||||
|
void ruleDST(const char* tzName, int8_t week, int8_t wday, int8_t month, int8_t hour, int tzOffset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the DST time as a ctime string
|
||||||
|
*
|
||||||
|
* @return char* time string
|
||||||
|
*/
|
||||||
|
const char* ruleDST();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set the rule for STD (standard day)
|
||||||
|
* end date of DST
|
||||||
|
*
|
||||||
|
* @param tzName name of the time zone
|
||||||
|
* @param week Last, First, Second, Third, Fourth (0 - 4)
|
||||||
|
* @param wday Sun, Mon, Tue, Wed, Thu, Fri, Sat (0 - 7)
|
||||||
|
* @param month Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec (0 -11)
|
||||||
|
* @param hour the local hour when rule chages
|
||||||
|
* @param tzOffset timezone offset
|
||||||
|
*/
|
||||||
|
void ruleSTD(const char* tzName, int8_t week, int8_t wday, int8_t month, int8_t hour, int tzOffset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the STD time as a ctime string
|
||||||
|
*
|
||||||
|
* @return char* time string
|
||||||
|
*/
|
||||||
|
const char* ruleSTD();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the name of the timezone
|
||||||
|
*
|
||||||
|
* @return char* name of the timezone
|
||||||
|
*/
|
||||||
|
const char* tzName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set the timezone manually
|
||||||
|
* this should used if there is no DST!
|
||||||
|
*
|
||||||
|
* @param tzHours
|
||||||
|
* @param tzMinutes
|
||||||
|
*/
|
||||||
|
void timeZone(int8_t tzHours, int8_t tzMinutes = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set daylight saving manually!
|
||||||
|
* use in conjunction with timeZone, when there is no DST!
|
||||||
|
*
|
||||||
|
* @param dstZone
|
||||||
|
*/
|
||||||
|
void isDST(bool dstZone);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief returns the DST state
|
||||||
|
*
|
||||||
|
* @return int 1 if summertime, 0 no summertime
|
||||||
|
*/
|
||||||
|
bool isDST();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the Unix epoch timestamp
|
||||||
|
*
|
||||||
|
* @return time_t timestamp
|
||||||
|
*/
|
||||||
|
time_t epoch();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the year
|
||||||
|
*
|
||||||
|
* @return int year
|
||||||
|
*/
|
||||||
|
int16_t year();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the month
|
||||||
|
*
|
||||||
|
* @return int month, 1 = january
|
||||||
|
*/
|
||||||
|
int8_t month();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the day of a month
|
||||||
|
*
|
||||||
|
* @return int day
|
||||||
|
*/
|
||||||
|
int8_t day();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the day of a week
|
||||||
|
*
|
||||||
|
* @return int day of the week, 0 = sunday
|
||||||
|
*/
|
||||||
|
int8_t weekDay();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the hour of the day
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
int8_t hours();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the minutes of the hour
|
||||||
|
*
|
||||||
|
* @return int minutes
|
||||||
|
*/
|
||||||
|
int8_t minutes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the seconds of a minute
|
||||||
|
*
|
||||||
|
* @return int seconds
|
||||||
|
*/
|
||||||
|
int8_t seconds();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief returns a formatted string
|
||||||
|
*
|
||||||
|
* @param format for strftime
|
||||||
|
* @return char* formated time string
|
||||||
|
*/
|
||||||
|
|
||||||
|
time_t fromUTC(time_t t);
|
||||||
|
time_t toUTC(time_t t);
|
||||||
|
time_t toLocalTime(time_t t);
|
||||||
|
|
||||||
|
time_t calcDateDST(struct ruleDST rule, int year);
|
||||||
|
bool summerTime(time_t t);
|
||||||
|
bool summerTime();
|
||||||
|
|
||||||
|
TimeZone& setUTCTime(time_t t);
|
||||||
|
TimeZone& setLocalTime(time_t t);
|
||||||
|
time_t getLocalTime();
|
||||||
|
time_t getUTCTime();
|
||||||
|
void begin();
|
||||||
|
char* formattedTime(const char *format);
|
||||||
|
|
||||||
|
private:
|
||||||
|
time_t utcCurrent = 0;
|
||||||
|
time_t local = 0;
|
||||||
|
struct tm *current;
|
||||||
|
uint32_t interval = 60000;
|
||||||
|
uint32_t lastUpdate = 0;
|
||||||
|
uint8_t tzHours = 0;
|
||||||
|
uint8_t tzMinutes = 0;
|
||||||
|
int32_t timezoneOffset;
|
||||||
|
int16_t dstOffset = 0;
|
||||||
|
bool dstZone = true;
|
||||||
|
uint32_t utcTime = 0;
|
||||||
|
time_t utcSTD, utcDST;
|
||||||
|
time_t dstTime, stdTime;
|
||||||
|
uint16_t yearDST;
|
||||||
|
char timeString[64];
|
||||||
|
struct ruleDST dstStart, dstEnd;
|
||||||
|
|
||||||
|
void currentTime();
|
||||||
|
void beginDST();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
211
src/main.cpp
211
src/main.cpp
@@ -1,4 +1,3 @@
|
|||||||
// change next line to use with another board/shield
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#include <Adafruit_GFX.h>
|
#include <Adafruit_GFX.h>
|
||||||
@@ -9,19 +8,22 @@
|
|||||||
|
|
||||||
#include <HTTPClient.h>
|
#include <HTTPClient.h>
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <DateTime.h>
|
|
||||||
#include <IotWebConf.h>
|
#include <IotWebConf.h>
|
||||||
#include <NTP.h>
|
#include <NTP.h>
|
||||||
#include <SPIFFS.h>
|
#include <SPIFFS.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <DateTime.h>
|
||||||
|
|
||||||
|
#include "ESP32TimerInterrupt.h"
|
||||||
|
#include "Scroller.h"
|
||||||
#include "calendar.h"
|
#include "calendar.h"
|
||||||
|
#include "TimeZone.h"
|
||||||
#ifndef PSTR
|
#ifndef PSTR
|
||||||
#define PSTR // Make Arduino Due happy
|
#define PSTR // Make Arduino Due happy
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define COMMAND_PARAMETER_LENGTH 30
|
#define COMMAND_PARAMETER_LENGTH 30
|
||||||
|
#define MAX_TIMES_SCROLLED 5
|
||||||
#define PIN 15
|
#define PIN 15
|
||||||
|
|
||||||
#include <WiFiUdp.h>
|
#include <WiFiUdp.h>
|
||||||
@@ -49,7 +51,7 @@ enum Lines_names
|
|||||||
String Lines[LAST_LINE];
|
String Lines[LAST_LINE];
|
||||||
|
|
||||||
Adafruit_NeoMatrix *matrix;
|
Adafruit_NeoMatrix *matrix;
|
||||||
const uint16_t colors[] = {
|
uint16_t colors[] = {
|
||||||
Adafruit_NeoMatrix::Color(255, 0, 0), Adafruit_NeoMatrix::Color(0, 255, 0), Adafruit_NeoMatrix::Color(0, 0, 255)};
|
Adafruit_NeoMatrix::Color(255, 0, 0), Adafruit_NeoMatrix::Color(0, 255, 0), Adafruit_NeoMatrix::Color(0, 0, 255)};
|
||||||
|
|
||||||
WiFiUDP ntpUDP;
|
WiFiUDP ntpUDP;
|
||||||
@@ -74,10 +76,53 @@ struct timer_def {
|
|||||||
int when; int h; int m; int d; int mh; int y;
|
int when; int h; int m; int d; int mh; int y;
|
||||||
};
|
};
|
||||||
|
|
||||||
int ntimers;
|
int ntimers,nextTimer = -1;
|
||||||
|
int nts;
|
||||||
|
|
||||||
|
DateTimeClass nextAlarmDateTime;
|
||||||
#define MAX_TIMERS 10
|
#define MAX_TIMERS 10
|
||||||
timer_def Timers[MAX_TIMERS];
|
timer_def Timers[MAX_TIMERS];
|
||||||
|
|
||||||
|
Scroller scroller(MAX_TIMES_SCROLLED);
|
||||||
|
|
||||||
|
unsigned long last_millis;
|
||||||
|
bool showText = false;
|
||||||
|
int scrolledTicker = 0;
|
||||||
|
bool updateNtpTime = false;
|
||||||
|
|
||||||
|
ESP32Timer ITimer0(0);
|
||||||
|
ESP32Timer ITimer1(1);
|
||||||
|
ESP32Timer ITimer2(2);
|
||||||
|
|
||||||
|
#define TIMER0_INTERVAL_MS 1000
|
||||||
|
#define TIMER1_INTERVAL_MS 100
|
||||||
|
#define TIMER2_INTERVAL_MS 60000
|
||||||
|
|
||||||
|
void IRAM_ATTR TimerCheckTime0(void)
|
||||||
|
{
|
||||||
|
unsigned long m = millis(), delta;
|
||||||
|
|
||||||
|
delta = (m - last_millis)/1000;
|
||||||
|
|
||||||
|
DateTime += delta;
|
||||||
|
|
||||||
|
if (nextAlarmDateTime <= DateTime && nextTimer != -1) {
|
||||||
|
showText = true;
|
||||||
|
scroller.TurnOn();
|
||||||
|
}
|
||||||
|
|
||||||
|
last_millis = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR TimerScrollTime1(void)
|
||||||
|
{
|
||||||
|
scrolledTicker++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR TimerUpdateNTP2(void)
|
||||||
|
{
|
||||||
|
updateNtpTime = true;
|
||||||
|
}
|
||||||
|
|
||||||
String getValue(String data, char separator, int index)
|
String getValue(String data, char separator, int index)
|
||||||
{
|
{
|
||||||
@@ -212,7 +257,7 @@ void read_config()
|
|||||||
{
|
{
|
||||||
s += (char)file.read();
|
s += (char)file.read();
|
||||||
}
|
}
|
||||||
Serial.print(s);
|
Serial.println(s);
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
@@ -258,7 +303,16 @@ void read_config()
|
|||||||
void calculate_timers()
|
void calculate_timers()
|
||||||
{
|
{
|
||||||
timer_def *t;
|
timer_def *t;
|
||||||
|
int timer = -1;
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
|
DateTimeClass AlarmTime,NextAlarm;
|
||||||
|
time_t alarm;
|
||||||
|
TimeZone TZ;
|
||||||
|
|
||||||
|
Serial.println("---CALC TIMERS---");
|
||||||
|
TZ.ruleDST("CEST", Last, Sun, Mar, 2, 120); // last sunday in march 2:00, timetone +120min (+1 GMT + 1h summertime offset)
|
||||||
|
TZ.ruleSTD("CET", Last, Sun, Oct, 3, 60); // last sunday in october 3:00, timezone +60min (+1 GMT)
|
||||||
|
|
||||||
for (int i=0; i<ntimers ; i++)
|
for (int i=0; i<ntimers ; i++)
|
||||||
{
|
{
|
||||||
t = &Timers[i];
|
t = &Timers[i];
|
||||||
@@ -269,8 +323,8 @@ void calculate_timers()
|
|||||||
|
|
||||||
if (t->d !=0) {
|
if (t->d !=0) {
|
||||||
tm.tm_mday = t->d;
|
tm.tm_mday = t->d;
|
||||||
tm.tm_mon = t->mh;
|
tm.tm_mon = t->mh - 1;
|
||||||
tm.tm_year = t->y;
|
tm.tm_year = t->y - 1900;
|
||||||
} else {
|
} else {
|
||||||
tm.tm_mday = 0;
|
tm.tm_mday = 0;
|
||||||
tm.tm_mon = 0;
|
tm.tm_mon = 0;
|
||||||
@@ -279,15 +333,67 @@ void calculate_timers()
|
|||||||
|
|
||||||
if (t->d == 0) {
|
if (t->d == 0) {
|
||||||
if (t->when == WORK_DAYS) {
|
if (t->when == WORK_DAYS) {
|
||||||
|
int offset=24*3600;
|
||||||
|
int wday;
|
||||||
|
|
||||||
|
tm.tm_mday = DateTime.getParts().getMonthDay();
|
||||||
|
tm.tm_mon = DateTime.getParts().getMonth();
|
||||||
|
tm.tm_year = DateTime.getParts().getYear() - 1900;
|
||||||
|
wday = DateTime.getParts().getWeekDay();
|
||||||
|
|
||||||
|
if (wday == 0) offset = 3600*24;
|
||||||
|
if (wday == 6) offset = 2*3600*24;
|
||||||
|
|
||||||
|
alarm = mktime(&tm);
|
||||||
|
TZ.setLocalTime(alarm);
|
||||||
|
|
||||||
|
AlarmTime.setTime(TZ.getUTCTime());
|
||||||
|
|
||||||
|
if (AlarmTime > DateTime && wday == 5 ) offset = 3*3600*24;
|
||||||
|
|
||||||
|
TZ.setLocalTime(alarm + offset);
|
||||||
|
AlarmTime.setTime(TZ.getUTCTime());
|
||||||
|
|
||||||
} else if (t->when == WEEKENDS) {
|
} else if (t->when == WEEKENDS) {
|
||||||
|
int offset=24*3600;
|
||||||
|
int wday;
|
||||||
|
|
||||||
} else if (t->when == TOMOROW ) {
|
tm.tm_mday = DateTime.getParts().getMonthDay();
|
||||||
|
tm.tm_mon = DateTime.getParts().getMonth();
|
||||||
|
tm.tm_year = DateTime.getParts().getYear() - 1900;
|
||||||
|
wday = DateTime.getParts().getWeekDay();
|
||||||
|
|
||||||
|
if (wday >= 1 && wday <= 5) offset = (7-wday) *3600*24;
|
||||||
|
|
||||||
|
alarm = mktime(&tm);
|
||||||
|
TZ.setLocalTime(alarm);
|
||||||
|
AlarmTime.setTime(TZ.getUTCTime());
|
||||||
|
|
||||||
|
if (AlarmTime > DateTime && wday == 5 ) offset = 3*3600*24;
|
||||||
|
|
||||||
|
TZ.setLocalTime(alarm + offset);
|
||||||
|
AlarmTime.setTime(TZ.getUTCTime());
|
||||||
|
|
||||||
|
} else if (t->when == ONCE ) {
|
||||||
|
alarm = mktime(&tm);
|
||||||
|
TZ.setLocalTime(alarm);
|
||||||
|
AlarmTime.setTime(TZ.getUTCTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AlarmTime > DateTime && (AlarmTime < NextAlarm || timer == -1)) {
|
||||||
|
timer = i;
|
||||||
|
NextAlarm = AlarmTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (timer != -1) {
|
||||||
|
nextTimer = timer;
|
||||||
|
nextAlarmDateTime = NextAlarm;
|
||||||
|
Serial.println(DateTime.toString());
|
||||||
|
Serial.println(nextAlarmDateTime.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
@@ -304,6 +410,22 @@ void setup()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerCheckTime0))
|
||||||
|
Serial.println("Starting ITimer0 OK, millis() = " + String(millis()));
|
||||||
|
else
|
||||||
|
Serial.println("Can't set ITimer0. Select another freq. or timer");
|
||||||
|
|
||||||
|
// Interval in microsecs
|
||||||
|
if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerScrollTime1))
|
||||||
|
Serial.println("Starting ITimer1 OK, millis() = " + String(millis()));
|
||||||
|
else
|
||||||
|
Serial.println("Can't set ITimer1. Select another freq. or timer");
|
||||||
|
|
||||||
|
if (ITimer2.attachInterruptInterval(TIMER2_INTERVAL_MS * 1000, TimerUpdateNTP2))
|
||||||
|
Serial.println("Starting ITimer2 OK, millis() = " + String(millis()));
|
||||||
|
else
|
||||||
|
Serial.println("Can't set ITimer2. Select another freq. or timer");
|
||||||
|
|
||||||
|
|
||||||
// -- Set up required URL handlers on the web server.
|
// -- Set up required URL handlers on the web server.
|
||||||
server.on("/", handleRoot);
|
server.on("/", handleRoot);
|
||||||
@@ -313,41 +435,10 @@ void setup()
|
|||||||
|
|
||||||
setup_matrix();
|
setup_matrix();
|
||||||
read_config();
|
read_config();
|
||||||
}
|
|
||||||
|
|
||||||
void scroll_line(String line)
|
scroller.SetColors(colors);
|
||||||
{
|
scroller.SetMatrix(matrix);
|
||||||
int x = 0, mx = 32;
|
|
||||||
int y = 0;
|
|
||||||
|
|
||||||
if (line.length() * 6 > mx)
|
|
||||||
{
|
|
||||||
for (x = 0; x < line.length() * 6 - mx; x++)
|
|
||||||
{
|
|
||||||
matrix->fillScreen(0);
|
|
||||||
matrix->setCursor(-x, y);
|
|
||||||
matrix->setTextColor(colors[1]);
|
|
||||||
matrix->print(line);
|
|
||||||
matrix->show();
|
|
||||||
if (x == 0)
|
|
||||||
delay(300);
|
|
||||||
else
|
|
||||||
delay(100);
|
|
||||||
}
|
}
|
||||||
delay(1000);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
matrix->fillScreen(0);
|
|
||||||
matrix->setCursor(x, y);
|
|
||||||
matrix->setTextColor(colors[1]);
|
|
||||||
matrix->print(line);
|
|
||||||
matrix->show();
|
|
||||||
delay(3000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void handleRoot()
|
void handleRoot()
|
||||||
{
|
{
|
||||||
@@ -385,32 +476,48 @@ void loop()
|
|||||||
unsigned long n = 0;
|
unsigned long n = 0;
|
||||||
|
|
||||||
// -- doLoop should be called as frequently as possible.
|
// -- doLoop should be called as frequently as possible.
|
||||||
iotWebConf.doLoop();
|
|
||||||
|
|
||||||
if (WiFi.status() == WL_CONNECTED)
|
if (WiFi.status() == WL_CONNECTED)
|
||||||
{
|
{
|
||||||
if (initialized == false)
|
if (initialized == false)
|
||||||
{
|
{
|
||||||
|
Serial.println("---INIT---");
|
||||||
ntp.ruleDST("CEST", Last, Sun, Mar, 2, 120); // last sunday in march 2:00, timetone +120min (+1 GMT + 1h summertime offset)
|
ntp.ruleDST("CEST", Last, Sun, Mar, 2, 120); // last sunday in march 2:00, timetone +120min (+1 GMT + 1h summertime offset)
|
||||||
ntp.ruleSTD("CET", Last, Sun, Oct, 3, 60); // last sunday in october 3:00, timezone +60min (+1 GMT)
|
ntp.ruleSTD("CET", Last, Sun, Oct, 3, 60); // last sunday in october 3:00, timezone +60min (+1 GMT)
|
||||||
ntp.begin();
|
ntp.begin();
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
sec = ntp.epoch();
|
sec = ntp.epoch();
|
||||||
DateTime.setTime(sec);
|
DateTime.setTime(sec);
|
||||||
|
|
||||||
if (n++ % 25 == 0)
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateNtpTime) {
|
||||||
|
Serial.println("---NTP UPDATE---");
|
||||||
|
ntp.update();
|
||||||
|
sec = ntp.epoch();
|
||||||
|
DateTime.setTime(sec);
|
||||||
|
calculate_timers();
|
||||||
|
updateNtpTime = false;
|
||||||
|
|
||||||
|
|
||||||
|
if (n++ % 10 == 0)
|
||||||
Lines[WEATHER_LINE] = get_weather_line();
|
Lines[WEATHER_LINE] = get_weather_line();
|
||||||
|
|
||||||
Lines[TIME_LINE] = get_time_line();
|
Lines[TIME_LINE] = get_time_line();
|
||||||
Lines[DATE_LINE] = get_date_line();
|
Lines[DATE_LINE] = get_date_line();
|
||||||
Lines[NAMES_LINE] = get_names_line();
|
Lines[NAMES_LINE] = get_names_line();
|
||||||
|
|
||||||
for (int i = 0; i < LAST_LINE; i++)
|
scroller.AddLines(Lines,LAST_LINE);
|
||||||
{
|
|
||||||
Serial.println(Lines[i]);
|
}
|
||||||
scroll_line(Lines[i]);
|
|
||||||
|
if (showText) {
|
||||||
|
Serial.println("---SHOW TEXT----");
|
||||||
|
scroller.loop(scrolledTicker);
|
||||||
|
|
||||||
|
if (scroller.TimesScrolled() > MAX_TIMES_SCROLLED) showText = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
iotWebConf.doLoop();
|
iotWebConf.doLoop();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user