esp_clock: refactor to use ntp client library and multi wifi
This commit is contained in:
parent
180320593f
commit
d2b0bc4fd6
365
esp_clock.ino
365
esp_clock.ino
@ -1,45 +1,27 @@
|
||||
//##########################################################################
|
||||
// FeatherClock - Use the Adafruit seven segment LED FeatherWing to display
|
||||
// the current time, which we fetch from the Internet using NTP. This
|
||||
// program assumes the seven segment display is attached to a Feather M0
|
||||
// WiFi (WINC1500).
|
||||
//
|
||||
// At the top of every hour, re-sync with NTP to correct for any drift.
|
||||
//
|
||||
// Credit: This is based heavily on the work by Tony DiCola from Adafruit.
|
||||
// Suggest (strongly) you go to adafruit.com and buy some product from
|
||||
// them. WINC1500 code modified from example code provided by Michael
|
||||
// Margolis and Tom Igoe.
|
||||
//
|
||||
// Philip R. Moyer
|
||||
// Adafruit
|
||||
//
|
||||
// This source code is released under the BSD license.
|
||||
// Any further redistribution must include this header.
|
||||
//##########################################################################
|
||||
|
||||
//##########################################################################
|
||||
// Includes and defines
|
||||
//##########################################################################
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <SPI.h> // SPI interface API
|
||||
#include <Wire.h> // Wire support library
|
||||
#include <WiFiUdp.h> // UDP support
|
||||
#include <ESP8266WiFiMulti.h>
|
||||
#include <NTPClient.h>
|
||||
#include <ESP8266mDNS.h>
|
||||
#include <WiFiUdp.h>
|
||||
#include <ArduinoOTA.h>
|
||||
#include <Adafruit_LEDBackpack.h> // Support for the Backpack FeatherWing
|
||||
#include <Adafruit_GFX.h> // Adafruit's graphics library
|
||||
|
||||
//##########################################################################
|
||||
// Globals
|
||||
//##########################################################################
|
||||
|
||||
#define STASSID "Miracle"
|
||||
#define STAPSK "***REMOVED***"
|
||||
|
||||
#define TIME_24_HOUR true
|
||||
#define TIME_24_HOUR
|
||||
#define DISPLAY_ADDRESS 0x70
|
||||
#define BRIGHTNESS 7
|
||||
|
||||
//##########################################################################
|
||||
// Globals
|
||||
//##########################################################################
|
||||
|
||||
// Create display object
|
||||
Adafruit_7segment clockDisplay = Adafruit_7segment();
|
||||
|
||||
@ -48,49 +30,131 @@ int minutes = 0; // Track minutes
|
||||
int seconds = 0; // Track seconds
|
||||
int tzOffset = +2; // Time zone offset (-4 = US Eastern time)
|
||||
|
||||
#ifdef TIME_24_HOUR
|
||||
byte displayHours[24] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
|
||||
#else
|
||||
byte displayHours[24] = {12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
||||
#endif
|
||||
|
||||
bool blinkColon = false; // Track colon status to blink once/sec
|
||||
int status = WL_IDLE_STATUS;
|
||||
bool shouldUpdate = true;
|
||||
|
||||
unsigned int localPort = 2390; // Local port to listen for UDP packets
|
||||
IPAddress timeServer(129,6,15,28); // time.nist.gov NTP server
|
||||
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes
|
||||
byte packetBuffer[NTP_PACKET_SIZE]; // Buffer for incoming and outgoing UDP packets
|
||||
ESP8266WiFiMulti wifiMulti;
|
||||
WiFiUDP ntpUDP;
|
||||
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", tzOffset*3600);
|
||||
|
||||
WiFiUDP Udp; // Set up a WINC1500 client session
|
||||
void setup() {
|
||||
Serial.begin(9600); // Start the serial console
|
||||
Serial.println("Clock starting!"); // Start the clock message.
|
||||
|
||||
//##########################################################################
|
||||
// Functions
|
||||
//##########################################################################
|
||||
wifiMulti.addAP("vulturul", "***REMOVED***");
|
||||
wifiMulti.addAP("Miracle", "***REMOVED***");
|
||||
|
||||
Serial.println("Connecting to WiFi netowrk.");
|
||||
while (wifiMulti.run() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
}
|
||||
Serial.println("Connected to network.");
|
||||
printWiFiStatus(); // Display WiFi status data
|
||||
|
||||
// send an NTP request to the time server at the given address
|
||||
unsigned long sendNTPpacket(IPAddress& address)
|
||||
{
|
||||
//Serial.println("1");
|
||||
// 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)
|
||||
//Serial.println("2");
|
||||
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;
|
||||
setupOTA();
|
||||
|
||||
//Serial.println("3");
|
||||
clockDisplay.begin(DISPLAY_ADDRESS);
|
||||
clockDisplay.setBrightness(BRIGHTNESS);
|
||||
|
||||
// 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
|
||||
//Serial.println("4");
|
||||
Udp.write(packetBuffer, NTP_PACKET_SIZE);
|
||||
//Serial.println("5");
|
||||
Udp.endPacket();
|
||||
//Serial.println("6");
|
||||
timeClient.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
ArduinoOTA.handle();
|
||||
|
||||
if (shouldUpdate && timeClient.forceUpdate()) {
|
||||
shouldUpdate = false;
|
||||
hours = timeClient.getHours();
|
||||
minutes = timeClient.getMinutes();
|
||||
seconds = timeClient.getSeconds();
|
||||
Serial.println(timeClient.getFormattedTime());
|
||||
} else {
|
||||
incrementTime();
|
||||
}
|
||||
displayTime();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
void incrementTime() {
|
||||
seconds++;
|
||||
if (seconds == 60) {
|
||||
seconds = 0;
|
||||
minutes++;
|
||||
if (((minutes % 5) == 0)) shouldUpdate = true;
|
||||
if (minutes == 60) {
|
||||
minutes = 0;
|
||||
Serial.println("Minutes set to zero - should query NTP on next loop()");
|
||||
hours = ++hours % 24;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void displayTime() {
|
||||
int displayHour = displayHours[hours];
|
||||
int displayValue = displayHour*100 + minutes;
|
||||
|
||||
// Print the time on the display
|
||||
clockDisplay.print(displayValue, DEC);
|
||||
|
||||
// Add zero padding when in 24 hour mode and it's midnight.
|
||||
// In this case the print function above won't have leading 0's
|
||||
// which can look confusing. Go in and explicitly add these zeros.
|
||||
if (displayHour == 0) {
|
||||
clockDisplay.writeDigitNum(1, 0);
|
||||
}
|
||||
|
||||
// Blink the colon by flipping its value every loop iteration
|
||||
// (which happens every second).
|
||||
blinkColon = !blinkColon;
|
||||
clockDisplay.drawColon(blinkColon);
|
||||
|
||||
// Now push out to the display the new values that were set above.
|
||||
clockDisplay.writeDisplay();
|
||||
}
|
||||
|
||||
void setupOTA() {
|
||||
ArduinoOTA.onStart([]() {
|
||||
String type;
|
||||
if (ArduinoOTA.getCommand() == U_FLASH) {
|
||||
type = "sketch";
|
||||
} else { // U_FS
|
||||
type = "filesystem";
|
||||
}
|
||||
|
||||
// NOTE: if updating FS this would be the place to unmount FS using FS.end()
|
||||
Serial.println("Start updating " + type);
|
||||
});
|
||||
ArduinoOTA.onEnd([]() {
|
||||
Serial.println("\nEnd");
|
||||
});
|
||||
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
|
||||
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
|
||||
});
|
||||
ArduinoOTA.onError([](ota_error_t error) {
|
||||
Serial.printf("Error[%u]: ", error);
|
||||
if (error == OTA_AUTH_ERROR) {
|
||||
Serial.println("Auth Failed");
|
||||
} else if (error == OTA_BEGIN_ERROR) {
|
||||
Serial.println("Begin Failed");
|
||||
} else if (error == OTA_CONNECT_ERROR) {
|
||||
Serial.println("Connect Failed");
|
||||
} else if (error == OTA_RECEIVE_ERROR) {
|
||||
Serial.println("Receive Failed");
|
||||
} else if (error == OTA_END_ERROR) {
|
||||
Serial.println("End Failed");
|
||||
}
|
||||
});
|
||||
ArduinoOTA.begin();
|
||||
Serial.println("Ready");
|
||||
Serial.print("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
void printWiFiStatus() {
|
||||
@ -109,178 +173,3 @@ void printWiFiStatus() {
|
||||
Serial.print(rssi);
|
||||
Serial.println(" dBm");
|
||||
}
|
||||
|
||||
//##########################################################################
|
||||
// Setup - main
|
||||
//##########################################################################
|
||||
|
||||
// This is one of the two standard functions for every Arduino program,
|
||||
// with the other being loop(). This one runs once at the beginning of the
|
||||
// program execution and is ordinarily used to initialize hardware and
|
||||
// variables.
|
||||
|
||||
void setup() {
|
||||
#ifdef WINC_EN
|
||||
pinMode(WINC_EN, OUTPUT);
|
||||
digitalWrite(WINC_EN, HIGH);
|
||||
#endif
|
||||
|
||||
Serial.begin(115200); // Start the serial console
|
||||
Serial.println("Clock starting!"); // Start the clock message.
|
||||
|
||||
WiFi.persistent(false);
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(STASSID, STAPSK);
|
||||
|
||||
// Now back to the setup
|
||||
|
||||
// Set up the display.
|
||||
clockDisplay.begin(DISPLAY_ADDRESS);
|
||||
clockDisplay.setBrightness(BRIGHTNESS);
|
||||
|
||||
// Attempt to conect to the WiFi network.
|
||||
Serial.println("Connecting to WiFi netowrk.");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
status = WiFi.begin(STASSID, STAPSK); // Connect to WPA2 network
|
||||
uint8_t timeout = 10; // Set a timeout variable
|
||||
while (timeout && (WiFi.status() != WL_CONNECTED)) {
|
||||
timeout--; // Decrement timeout
|
||||
delay(1000); // Delay for one second
|
||||
}
|
||||
}
|
||||
|
||||
Serial.println("Connected to network.");
|
||||
printWiFiStatus(); // Display WiFi status data
|
||||
|
||||
Udp.begin(localPort); // Open the UDP port for comms
|
||||
}
|
||||
|
||||
//##########################################################################
|
||||
// Loop - main
|
||||
//##########################################################################
|
||||
|
||||
// This is one of the two standard functions for every Arduino program,
|
||||
// with the other being setup(). This one runs continuously, forever, and
|
||||
// executes the Arduino program code.
|
||||
|
||||
void loop() {
|
||||
// Refresh the time at the top of every hour, or every five minutes
|
||||
// because the clock drift on the bare Feather M0 is pretty wicked.
|
||||
if ((minutes == 0) || ((minutes % 5) == 0)) {
|
||||
sendNTPpacket(timeServer); // send an NTP packet to a time server
|
||||
// wait to see if a reply is available
|
||||
delay(1000);
|
||||
if ( Udp.parsePacket() ) {
|
||||
Serial.println("packet received");
|
||||
// We've received a packet, read the data from it
|
||||
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into buffer
|
||||
|
||||
//the timestamp starts at byte 40 of the received packet and is four
|
||||
// bytes, or two words, long. First, esxtract the two words:
|
||||
|
||||
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
|
||||
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
|
||||
// combine the four bytes (two words) into a long integer
|
||||
// this is NTP time (seconds since Jan 1 1900):
|
||||
unsigned long secsSince1900 = highWord << 16 | lowWord;
|
||||
Serial.print("Seconds since Jan 1 1900 = " );
|
||||
Serial.println(secsSince1900);
|
||||
|
||||
// now convert NTP time into everyday time:
|
||||
Serial.print("Unix time = ");
|
||||
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
|
||||
const unsigned long seventyYears = 2208988800UL;
|
||||
// subtract seventy years:
|
||||
unsigned long epoch = secsSince1900 - seventyYears;
|
||||
// print Unix time:
|
||||
Serial.println(epoch);
|
||||
|
||||
// print the hour, minute and second:
|
||||
Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT)
|
||||
hours = ((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day)
|
||||
hours += tzOffset; // Calculate the time zone offset
|
||||
if (hours < 0) {
|
||||
hours = 24 + hours;
|
||||
}
|
||||
if (hours > 23) {
|
||||
hours = hours - 24;
|
||||
}
|
||||
Serial.print(hours); // print the hour
|
||||
Serial.print(':');
|
||||
minutes = ((epoch % 3600) / 60);
|
||||
if (minutes < 10 ) {
|
||||
// In the first 10 minutes of each hour, we'll want a leading '0'
|
||||
Serial.print('0');
|
||||
}
|
||||
Serial.print(minutes); // print the minute (3600 equals secs per minute)
|
||||
Serial.print(':');
|
||||
seconds = (epoch % 60); // print the second
|
||||
if ( seconds < 10 ) {
|
||||
// In the first 10 seconds of each minute, we'll want a leading '0'
|
||||
Serial.print('0');
|
||||
}
|
||||
Serial.println(seconds);
|
||||
}
|
||||
}
|
||||
// Display the time
|
||||
int displayValue = hours*100 + minutes;
|
||||
|
||||
if (!TIME_24_HOUR) {
|
||||
if (hours > 12) {
|
||||
displayValue -= 1200;
|
||||
}
|
||||
else if (hours == 0) {
|
||||
displayValue += 1200;
|
||||
}
|
||||
}
|
||||
|
||||
// Print the time on the display
|
||||
clockDisplay.print(displayValue, DEC);
|
||||
|
||||
// Add zero padding when in 24 hour mode and it's midnight.
|
||||
// In this case the print function above won't have leading 0's
|
||||
// which can look confusing. Go in and explicitly add these zeros.
|
||||
if (TIME_24_HOUR && hours == 0) {
|
||||
// Pad hour 0.
|
||||
clockDisplay.writeDigitNum(1, 0);
|
||||
// Also pad when the 10's minute is 0 and should be padded.
|
||||
if (minutes < 10) {
|
||||
clockDisplay.writeDigitNum(2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Blink the colon by flipping its value every loop iteration
|
||||
// (which happens every second).
|
||||
blinkColon = !blinkColon;
|
||||
clockDisplay.drawColon(blinkColon);
|
||||
|
||||
// Now push out to the display the new values that were set above.
|
||||
clockDisplay.writeDisplay();
|
||||
|
||||
// Pause for a second for time to elapse. This value is in milliseconds
|
||||
// so 1000 milliseconds = 1 second.
|
||||
delay(1000);
|
||||
|
||||
// Now increase the seconds by one.
|
||||
seconds += 1;
|
||||
// If the seconds go above 59 then the minutes should increase and
|
||||
// the seconds should wrap back to 0.
|
||||
if (seconds > 59) {
|
||||
seconds = 0;
|
||||
minutes += 1;
|
||||
// Again if the minutes go above 59 then the hour should increase and
|
||||
// the minutes should wrap back to 0.
|
||||
if (minutes > 59) {
|
||||
minutes = 0;
|
||||
Serial.println("Minutes set to zero - should query NTP on next loop()");
|
||||
hours += 1;
|
||||
// Note that when the minutes are 0 (i.e. it's the top of a new hour)
|
||||
// then the start of the loop will read the actual time from NTP
|
||||
// again. Just to be safe though we'll also increment the hour and wrap
|
||||
// back to 0 if it goes above 23 (i.e. past midnight).
|
||||
if (hours > 23) {
|
||||
hours = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user