/*
* Analog Radio Clock with AT Command
*
* ESP8266----------ATmega
* TX ----------RX(D10)
* RX ----------TX(D11)
*
*/
#include <SoftwareSerial.h>
#include <TimeLib.h> //
https://github.com/PaulStoffregen/Time
#define rxPin 10 //
D10
#define txPin 11 //
D11
SoftwareSerial Serial2(rxPin, txPin); // RX, TX
#include <avr/wdt.h>
#include "Adafruit_GFX.h"// Hardware-specific library
#include <MCUFRIEND_kbv.h> //
https://github.com/prenticedavid/MCUFRIEND_kbv
MCUFRIEND_kbv tft;
// Color definitions
#define BLACK
0x0000 /*
0, 0, 0 */
#define NAVY
0x000F /*
0, 0, 128 */
#define DARKGREEN
0x03E0 /* 0,
128, 0 */
#define DARKCYAN
0x03EF /* 0,
128, 128 */
#define MAROON
0x7800 /* 128,
0, 0 */
#define PURPLE
0x780F /* 128,
0, 128 */
#define OLIVE
0x7BE0 /* 128,
128, 0 */
#define LIGHTGRAY
0xC618 /* 192, 192, 192 */
#define DARKGRAY
0x7BEF /* 128, 128, 128 */
#define BLUE
0x001F /*
0, 0, 255 */
#define GREEN
0x07E0 /* 0,
255, 0 */
#define CYAN
0x07FF /* 0,
255, 255 */
#define
RED
0xF800 /* 255,
0, 0 */
#define MAGENTA
0xF81F /* 255,
0, 255 */
#define YELLOW
0xFFE0 /* 255,
255, 0 */
#define WHITE
0xFFFF /* 255, 255, 255 */
#define ORANGE
0xFD20 /* 255,
165, 0 */
#define GREENYELLOW 0xAFE5
/* 173, 255, 47 */
#define PINK
0xF81F
#define GRAY
0x5AEB
#define TIME_ZONE 9 // Change your time zone
#define _DEBUG_ 0
float sx = 0, sy = 1, mx = 1, my = 0, hx = -1, hy =
0; // Saved H, M, S x & y
multipliers
float sdeg=0, mdeg=0, hdeg=0;
uint16_t osx=120, osy=120, omx=120, omy=120, ohx=120,
ohy=120; // Saved H, M, S x & y coords
uint16_t x00=0, x11=0, y00=0, y11=0;
uint32_t targetTime =
0;
// for next 1 second timeout
boolean initial = 1;
time_t epoch;
char buf[64];
void reboot() {
wdt_disable();
wdt_enable(WDTO_15MS);
while (1) {}
}
void putChar(char c) {
char tmp[10];
if ( c == 0x0a) {
Serial.println();
} else if (c == 0x0d) {
} else if ( c < 0x20) {
uint8_t cc = c;
sprintf(tmp,"[0x%.2X]",cc);
Serial.print(tmp);
} else {
Serial.print(c);
}
}
//Wait for specific input string until timeout runs out
bool waitForString(char* input, int length, unsigned int
timeout) {
unsigned long end_time = millis() + timeout;
char current_byte = 0;
int index = 0;
while (end_time >= millis()) {
if(Serial2.available()) {
//Read one byte
from serial port
current_byte =
Serial2.read();
//
Serial.print(current_byte);
if (_DEBUG_)
putChar(current_byte);
if
(current_byte != -1) {
//Search one character at a time
if
(current_byte == input[index]) {
index++;
//Found the string
if (index == length)
{
return true;
}
//Restart position of character to look for
}
else {
index = 0;
}
}
}
}
//Timed out
return false;
}
//Wait for CIPSNTPTIME response
int getSNTPtime(char* buf, int szbuf, unsigned int
timeout) {
int len=0;
int pos=0;
char line[40];
Serial2.print("AT+CIPSNTPTIME?\r\n");
long int time = millis();
memset(line,0,sizeof(line));
while( (time+timeout) > millis()) {
while(Serial2.available()) {
char c = Serial2.read(); //
read the next character.
if (_DEBUG_)
Serial.print(c);
if (c == 0x0d) {
} else if (c == 0x0a) {
if (_DEBUG_) {
Serial.print("Read=[");
Serial.print(line);
Serial.println("]");
}
if
(strcmp(line,"OK") == 0) return len;
int offset;
for(offset=0;offset<pos;offset++) {
if(line[offset] == '+') break;
}
if
(strncmp(&line[offset],"+CIPSNTPTIME:",13) == 0) {
strcpy(buf,&line[13+offset]);
len
= strlen(buf);
buf[len] = 0;
}
pos=0;
line[pos]=0;
} else {
line[pos++]=c;
if (pos == 40)
return -1;
line[pos]=0;
}
}
}
return -1;
}
#define LEAP_YEAR(Y) (
((1970+Y)>0) && !((1970+Y)%4) && (
((1970+Y)%100) || !((1970+Y)%400) ) )
#define SECS_PER_MIN ((time_t)(60UL))
#define SECS_PER_HOUR ((time_t)(3600UL))
#define SECS_PER_DAY ((time_t)(SECS_PER_HOUR *
24UL))
#define DAYS_PER_WEEK ((time_t)(7UL))
#define SECS_PER_WEEK ((time_t)(SECS_PER_DAY *
DAYS_PER_WEEK))
#define SECS_PER_YEAR ((time_t)(SECS_PER_DAY * 365UL)) //
TODO: ought to handle leap years
#define SECS_YR_2000 ((time_t)(946684800UL)) // the
time at the start of y2k
// Convert Sat Jan 20 08:41:55 2018 to time_t
time_t makeTime(char* str) {
char c_dow[10];
char c_month[10];
int year,month,day,hour,minute,second,dow;
char *t_dow[] =
{"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
char *t_month[] =
{"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
sscanf(str,"%s %s %d %d:%d:%d
%d",c_dow,c_month,&day,&hour,&minute,&second,&year);
for(dow=0;dow<7;dow++) {
if (strcmp(c_dow,t_dow[dow]) == 0)
break;
}
for(month=1;month<13;month++) {
if (strcmp(c_month,t_month[month-1]) ==
0) break;
}
// API starts months from 1, this array starts from
0
static const uint8_t
monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31};
time_t seconds;
int i;
// seconds from 1970 till 1 jan 00:00:00 of the
given year
seconds= (year-1970)*(SECS_PER_DAY * 365);
for (i = 1970; i < year; i++) {
if (LEAP_YEAR(i)) {
seconds +=
SECS_PER_DAY; // add extra days for leap years
}
}
// add days for this year, months start from 1
for (i = 1; i < month; i++) {
if ( (i == 2) &&
LEAP_YEAR(year)) {
seconds += SECS_PER_DAY *
29;
} else {
seconds += SECS_PER_DAY *
monthDays[i-1]; //monthDay array starts from 0
}
}
seconds+= (day-1) * SECS_PER_DAY;
seconds+= hour * SECS_PER_HOUR;
seconds+= minute * SECS_PER_MIN;
seconds+= second;
return seconds;
}
//Send AT Command
void sendCommand(char* buff) {
if (_DEBUG_) {
Serial.println("");
Serial.print(buff);
Serial.println("-->");
}
Serial2.println(buff);
Serial2.flush();
}
//Print error
void errorDisplay(char* buff) {
Serial.print("Error:");
Serial.println(buff);
while(1) {}
}
void clearBuffer() {
while (Serial2.available())
Serial2.read();
// Serial.println();
}
static uint8_t conv2d(const char* p) {
uint8_t v = 0;
if ('0' <= *p && *p <= '9')
v = *p - '0';
return 10 * v + *++p - '0';
}
void drawWatch(char * dateStr, uint16_t frame) {
uint16_t wid = tft.width();
uint16_t ht = tft.height();
if (wid < ht) {
tft.setRotation(0);
} else {
tft.setRotation(1);
}
tft.fillScreen(DARKGRAY);
tft.setTextColor(WHITE, DARKGRAY); // Adding
a background colour erases previous text automatically
// Draw clock face
tft.fillCircle(120, 120, 118, frame);
tft.fillCircle(120, 120, 110, BLACK);
// Draw 12 lines
for(int i = 0; i<360; i+= 30) {
sx = cos((i-90)*0.0174532925);
sy = sin((i-90)*0.0174532925);
x00 = sx*114+120;
y00 = sy*114+120;
x11 = sx*100+120;
y11 = sy*100+120;
tft.drawLine(x00, y00, x11, y11,
GREEN);
}
// Draw 60 dots
for(int i = 0; i<360; i+= 6) {
sx = cos((i-90)*0.0174532925);
sy = sin((i-90)*0.0174532925);
x00 = sx*102+120;
y00 = sy*102+120;
// Draw minute markers
tft.drawPixel(x00, y00, WHITE);
// Draw main quadrant dots
if(i==0 || i==180) tft.fillCircle(x00,
y00, 2, WHITE);
if(i==90 || i==270) tft.fillCircle(x00,
y00, 2, WHITE);
}
tft.fillCircle(120, 121, 3, WHITE);
// tft.setCursor(20, 260);
tft.setCursor(30, 260);
tft.setTextSize(3);
tft.println(dateStr);
}
void drawTime(uint8_t hh, uint8_t mm, uint8_t ss) {
// Pre-compute hand degrees, x & y
coords for a fast screen update
sdeg =
ss*6;
// 0-59 -> 0-354
mdeg = mm*6+sdeg*0.01666667; //
0-59 -> 0-360 - includes seconds
hdeg = hh*30+mdeg*0.0833333; //
0-11 -> 0-360 - includes minutes and seconds
hx =
cos((hdeg-90)*0.0174532925);
hy = sin((hdeg-90)*0.0174532925);
mx =
cos((mdeg-90)*0.0174532925);
my = sin((mdeg-90)*0.0174532925);
sx =
cos((sdeg-90)*0.0174532925);
sy = sin((sdeg-90)*0.0174532925);
if (ss==0 || initial) {
initial = 0;
// Erase hour and minute
hand positions every minute
tft.drawLine(ohx, ohy, 120,
121, BLACK);
ohx =
hx*62+121;
ohy = hy*62+121;
tft.drawLine(omx, omy, 120,
121, BLACK);
omx =
mx*84+120;
omy = my*84+121;
}
// Redraw new hand
positions, hour and minute hands not erased here to avoid
flicker
tft.drawLine(osx, osy, 120,
121, BLACK);
osx =
sx*90+121;
osy = sy*90+121;
tft.drawLine(osx, osy, 120,
121, RED);
tft.drawLine(ohx, ohy, 120,
121, WHITE);
tft.drawLine(omx, omy, 120,
121, WHITE);
tft.drawLine(osx, osy, 120,
121, RED);
tft.fillCircle(120, 121, 3,
RED);
}
void setup(void)
{
delay(1000);
Serial.begin(9600);
//Make sure ESP8266 is set to 4800
Serial2.begin(4800);
//Enable autoconnect
sendCommand("AT+CWAUTOCONN=1");
if (!waitForString("OK", 2, 10000)) {
errorDisplay("AT+CWAUTOCONN Fail");
}
clearBuffer();
//Restarts the Module
sendCommand("AT+RST");
if (!waitForString("WIFI GOT IP", 11, 10000)) {
errorDisplay("ATE+RST Fail");
}
clearBuffer();
//Local echo off
sendCommand("ATE0");
if (!waitForString("OK", 2, 1000)) {
errorDisplay("ATE0 Fail");
}
clearBuffer();
if (_DEBUG_) {
//Get local IP address
sendCommand("AT+CIPSTA?");
if (!waitForString("OK", 2, 1000)) {
errorDisplay("AT+CIPSTA?
Fail");
}
clearBuffer();
}
//Sets the Configuration of SNTP
sprintf(buf,"AT+CIPSNTPCFG=1,%d\r\n",TIME_ZONE);
sendCommand(buf);
if (!waitForString("OK", 2, 1000)) {
errorDisplay("AT+CIPSNTPCFG Fail");
}
clearBuffer();
//Wait for SNTP response
while(1) {
if (getSNTPtime(buf, 64, 5000)) {
if (_DEBUG_)
Serial.println("SNTP Time is [" + String(buf) +"]");
epoch = makeTime(buf);
Serial.println("epoch = " +
String(epoch));
if (epoch != 0) break;
delay(1000);
} else {
errorDisplay("getSNTPtime Fail");
}
}
setTime(epoch);
Serial.print("now=" + String(year()) + "/" +
String(month()) + "/" + String(day()));
Serial.println(" " + String(hour()) + ":" +
String(minute()) + ":" + String(second()));
uint16_t ID = tft.readID();
Serial.print("Device ID: 0x"); Serial.println(ID,
HEX);
tft.begin(ID);
uint16_t wid = tft.width();
uint16_t ht = tft.height();
Serial.println("width:" + String(wid) + " height:"
+ String(ht));
char dateStr[11];
sprintf(dateStr,"%04d/%02d/%02d
%s",year(),month(),day());
if (hour() < 13) drawWatch(dateStr,ORANGE);
else drawWatch(dateStr,GREEN);
Serial.println("Wait for a moment");
uint8_t h2 = hour();
if (h2 > 13) h2 = h2 - 12;
for(int hhh=0;hhh<h2;hhh++) {
for(int mmm=0;mmm<60;mmm++) {
drawTime(hhh,mmm,0);
delay(10);
}
}
for(int mmm=0;mmm<=minute();mmm++) {
drawTime(hour(),mmm,0);
delay(10);
}
for(int sss=0;sss<=second();sss++) {
drawTime(hour(),minute(),sss);
delay(10);
}
targetTime = millis() + 1000;
}
void loop() {
char dateStr[11];
uint8_t hh,mm,ss;
if (targetTime < millis()) {
targetTime = millis()+1000;
hh = hour();
mm = minute();
ss = second();
if (hh == 12 && mm == 0
&& ss == 0) reboot();
if (hh == 0 && mm == 0
&& ss == 0) reboot();
drawTime(hh, mm, ss);
}
}
|