spudnut1
Published

Internet Connected Clock with News, Time, Weather and Chimes

Arduino Mega based clock that drives multiple displays for time, date, DOW, Temp, Humid, Bar, etc. Internet connected thru ESP8266 chip

IntermediateShowcase (no instructions)1,266
Internet Connected Clock with News, Time, Weather and Chimes

Things used in this project

Hardware components

MAX7219/MAX7221 LED Display Drivers
Maxim Integrated MAX7219/MAX7221 LED Display Drivers
2 x 4 unit matrix at a minimum and perhaps 3 if that's the choice for persistent time display
×3
Arduino Mega 2560
Arduino Mega 2560
Needed for memory and number of GPIOs
×1
Adafruit FX 2mb Soundboard with built in amp and speaker terminals
×1
Adafruit MPL115A2 Barometer sensor
×1
Adafruit RTC DS3231 Real time clock
×1
Generic SPST NO pushbuttons
Set, Up, Down, Demo/Easter Egg
×4
Generic SPST Toggle switch
ANSO and Internet-use on/off
×2
Generic SPDT center off toggle switch
Used to select single chime, Westminster chime or silent
×1
Generic LDR photocell
×1
Resistor 10k ohm
Resistor 10k ohm
×1
DHT22 temperature-humidity sensor
Adafruit DHT22 temperature-humidity sensor
×1
ESP8266 ESP-12E
Espressif ESP8266 ESP-12E
Actually, I use ESP8266 from HILETGO on Amazon...
×1
Adafruit 8x8 LED matrix with I2C backpack
Only if using for 2ndary persistent time display
×4
Adafruit 1.2" 7 segment LED with I2c backpack
Again, only if you want to use it as a 2ndary persistent time display
×1
Generic 8 ohm speaker
×1
4 to 5 amp power supply
5 volt --
×1
Some sort of Enclosure -- I used wooden wine boxes
I had single bottle wooden wine boxes 'fronted' with either red acrylic or the Chemist Black LED diffusion panels to cover the displays
×1

Software apps and online services

NPT time server
NYT API
NPR API

Story

Read more

Custom parts and enclosures

Sound files

Sound files for FX sound board

Loaded onto Arduino FX sounboard (OGG files)

Schematics

Clock connections and assembly

Each connection is described.

Back of clock

Front

Code

ESP8266 "Co Processor" code

Arduino
Used by main clock to get time, news and weather
/*
    News, Time and Weather: ESP 8266 co-processor for the Matrix Clock series
    Responds to wired interrupt and takes a series of commands to return
    time, NYT RSS Feed headline and Accuweather current weather and forecast
    Requires SSID, password, offset from GMT and zip code

    8-25-20   Update 'remove HTML apostrophe' code and edit degree sign
    8-31-20   Remove yet another HTML apostrophe sneaking in
    9-16-20   Add NPR news feed read and internal test code
    9-17-20   Debugged version
    9-28-20   Added 'disconnect from prior network' before wifi begins
    9-29-20   Added tomorrow forecast to ACW updates
    10-22-20  No change
    11-30-20  Reduce time between segment sends from 400 ms to 40 ms
    1-5-21    Remove redundant time validity test
    01-29-21  Replace '&' with just '&' in strings
*/

#define USING_AXTLS
#include <ESP8266WiFi.h>
#include <EasyNTPClient.h>
#include <WiFiUdp.h>
#include <TimeLib.h>
#include <Wire.h>


// force use of AxTLS (BearSSL is now default)
#include <WiFiClientSecureAxTLS.h>
using namespace axTLS;

 // #define H7912                                            // house 1
   #define H274                                             //house 2

#ifdef H7912
#define STASSID "xxxx"                                        // Your SSID and
#define STAPSK  "zzzzzzzz"                               // Password
#define MyOffset -8                                           // Your offset to GMT
#define MyZipCode "98040"                                     // Your zipcode used for localization of weather
#endif

#ifdef H274
#define STASSID "xxxxxx"
#define STAPSK  "yyyyyyyyyyy"
#define MyOffset -8
#define MyZipCode "98358"
#endif

//#define test_mode                       // if defined code runs standalone to test readers

#define DDT                                 // define to turn on debugging tools
void DDTv(String st, int vt) {              // Print descriptor and value
  #ifdef DDT
    Serial.print("  ");
    Serial.print(st);
    Serial.print("  ");
    Serial.print(vt);
  #endif 
    } 
void DDTl(String st, int vt) {               // Print descriptor and value and new line
  #ifdef DDT
    DDTv(st, vt);
    Serial.println(" ");
  #endif
    }
void DDTs(String st) {                     // Print string 
  #ifdef DDT
    Serial.print(st);
  #endif 
    } 
void DDTt(String st) {                     // Print string and new line
  #ifdef DDT
    Serial.println(st); 
  #endif
    } 
void DDTf(String st, float fi) {          // Print descriptor and floating point value and new line
  #ifdef DDT
    Serial.print("  ");
    Serial.print(st);
    Serial.print("  ");
    Serial.println(fi,4);
  #endif 
    } 
void DDTsl(String st, String vt) {                                                      // Print descriptor and string value and new line
  #ifdef DDT
    Serial.print(st);
    Serial.println(vt);
  #endif
    }   


const char* ssid = STASSID;
const char* password = STAPSK;
WiFiUDP udp;
EasyNTPClient ntpClient(udp, "pool.ntp.org", ((MyOffset * 60 * 60)));         // initialize and set up offset

unsigned long t_unix_date;
int MyYear;                                                     // to receive the parsed date, time
int MyMonth;
int MyDay;
int MyHour;
int MyMinute;
int MySecond;
int MyWeekDay;
char MyDaysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
#define  SDA 4 // D2.
#define SCL 5 // D1

const int MasterPin = 2;       // D4                          // Pin to take interrupt on when asked for time and date
bool ESPvalue;                                                // Value to read interrupt status into
bool Setflag = false;                                         // Single flag set to 'true' when interrupt occurs
const int ConnectTries = 20;                                   // number of tries to wait for Wifi connection
const int ConnectWait = 500;                                  // milliseconds between tries
const int WaitingTime = 2000;                                    // milliseconds to fully delay between network status tries
const int WaitingCounter = 50;                                  // times to wait
const int MasterChannel = 8;                                    // although it seems like the master, to us its the slave (its I2C address)
byte Master_Command = 0;
const int MC_GetTime = 1;                                       // potential values for clock to ask for
const int MC_GetNYT = 2;                                        // NYT RSS
const int MC_GetACW = 3;                                        // Current Accuweather
const int MC_GetNPR = 4;                                         // NPR
const int MC_Bad = 0;
const int MC_Null = 5;

String line =  "                                                                                                                                                      ";   //150
String NYTLine = line;
String ACWLine = line;
String NPRLine = line;
int NYTLength;                                                          // length of returned headline
int ACWLength;                                                          // length of returned accuweather line
int NPRLength;                                                          // length of returned NPR line
bool GotNYT = false;                                                     // set true by successful "GET"
bool GotACW = false;                                                     // same - only need one for both currrent and forecast
bool GotNPR = false;                                                     // same
int Status_Flag;                                                        // result of wire transmission
int Inptr;                                                              // 'from' string pointer
int Outptr;                                                             // 'to'
const int MaxBytes = 10;                                                // I2C has a 32 byte limitation, but I can't get past 10 or so
int NYTCCounter;                                                           // decrementing character counter
int ACWCCounter;                                                           // decrementing character counter
int NPRCCounter;                                                           // decrementing character counter
char Segment [MaxBytes];                                                // segment header only in first segment:
int Segment_Delay = 40;                                               // milliseconds to wait between segment sends
const int SSH_Type = 0;                                                 // segment header 'type' (will be MC_Command parroted back)
const int SSH_Length = 1;                                               // length of data (not including header)
const int SSH_Contents = 2;                                             // where the data lives
const int Repeat_Sends = 5;                                             // number of times to try to send segment 


WiFiClientSecure client;

void setup() {
  Serial.begin(9600);
  WiFi.disconnect();                                           // Disconnect from any prior network
  Wire.begin(SDA, SCL);                                       // join i2c bus with address defined (int sda, int scl);
  pinMode(MasterPin, INPUT_PULLUP);                           // initialize pin to listen to master on 
 
 // Serial.print("connecting to ");
  //Serial.println(ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print("."); }

 // Serial.println("Initially connected");
 // Serial.println("");
 // Serial.println("WiFi connected");
 // Serial.println("IP address: ");
 // Serial.println(WiFi.localIP());

 #ifndef test_mode
  GetCommandByte();                                                   // ask for first byte
 #endif
 
//  DDTt("asking for initial byte");
  attachInterrupt(digitalPinToInterrupt(MasterPin), ISR, FALLING );   // set to interrupt when becomes LOW

  }  // end of setup
  
void loop() {

if (WiFi.status() != WL_CONNECTED){                          // if disconnected from network, restart
//  DDTt("Not connected at top of loop");
  ESP.restart();}
#ifdef test_mode
Setflag = true;                                                       // if testing, we are always set                       
#endif

if (Setflag) {                                                // we got a wired interrupt

#ifdef test_mode                                                  // if testing a reader
    Master_Command = MC_GetNPR;                                   // THIS is the reader to test - change to suit test
#else  
    GetCommandByte();                                             // ask Master for a command byte
    DDTl("Command Byte = ",Master_Command);
#endif

  switch (Master_Command) {
    case MC_Bad:
//     DDTs("Got a zero command");
     break;
    case MC_GetTime:
      if (!GetTheTime()) DDTt("GetThetime failed");
      break;
    case MC_GetNYT:
      GotNYT = GetNYT();                                        // do the fetch from RSS site and store success/fail
      if (!GotNYT) {DDTt("GETNYT failed");} 
      if (!SendNYT()) DDTt("SendNYT failed");
      break;
    case MC_GetACW:
      GotACW = GetACW();                                        // do the fetch from RSS site and store success/fail
      if (!GotACW) {DDTt("GETACW failed");}  
      if(!SendACW()) DDTt("SendAccuweather failed");
      break;
    case MC_GetNPR:
      GotNPR = GetNPR();                                        // do the fetch from RSS site and store success/fail
      if (!GotNPR) {DDTt("GETNPR failed");} 
      if(!SendNPR()) DDTt("SendNPR failed");
      break;
     case MC_Null:
       DDTt("Got idle startup command");
      break;
    default:
    DDTl("Never on CASE",Master_Command);
    break;
  }  // end of case switch
    
    Setflag = false;                                          // and clear "got interrupt" flag
}
 #ifdef test_mode
 delay(30000);                                       //delay between repeated reads
 #endif
}         // end of Void Loop

ICACHE_RAM_ATTR void ISR(){                               // Simple routine to set 'true' on interrupt
  Setflag = true;
//  DDTt("Got interrupt from Master");
}  // end of ISR

void GetCommandByte(){                                          // routine to ask for one byte from master clock
  Wire.requestFrom (MasterChannel, 1);
  if (Wire.available() == 1) {Master_Command = Wire.read();
//  DDTv("Master Command received = ",Master_Command);
  } else 
    {Master_Command = MC_Bad;
     DDTv("Bad or no Command received = ",Master_Command);
     DDTv("and length was",Wire.available()); 
     }
    
}  // end of get Command byte

 bool GetNYT(){
   // Use WiFiClientSecure class to create TLS connection
  
  const char* host = "rss.nytimes.com";
  const int httpsPort = 443;

// Use web browser to view and copy
// SHA1 fingerprint of the certificate
    
//https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml
//CB:29:78:50:52:F1:B9:1E:53:0C:BE:54:6C:11:DF:E6:29:94:D7:6E
//const char* fingerprint = "CB 29 78 50 52 F1 B9 1E 53 0C BE 54 6C 11 DF E6 29 94 D7 6E";

  if (!client.connect(host, httpsPort)) {
    DDTt("connection failed");
    return false;}

//  if (!client.verify(fingerprint, host)) {                              // it appears fingerprint not needed
//     DDTt("certificate doesn't match");
 //     return false;}

  String url = "/services/xml/rss/nyt/HomePage.xml";
//  Serial.print("requesting URL: ");
//  Serial.println(url);

 client.print(String("GET ") + url +
                " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
             "Connection: close\r\n\r\n");
//  Serial.println("request sent");
  while (client.connected()) {
     line = client.readStringUntil('\n');
    if (line == "\r") {
//      Serial.println("headers received");
      break;
    }
  }
   line = client.readStringUntil('\n');
  if (line.startsWith("<?xml version")) {
   // Serial.println("Successfull!");
 } else {
   // Serial.println("Failed");
   return false;
  }
//  Serial.println("reply was:");
//  Serial.println("==========");
//  Serial.println(line);
//  Serial.println("==========");
    SearchTag("<item>");                                        // search for item tag
    line = client.readStringUntil('\n');                        // read next line
    RemoveTags();
    line.replace("&#39;", "'");                                   // another instance of HTML apostrophe sneaking in - replace it
    line.replace("&amp;", "&");                                   // Replace '&amp;' with just '&' 
    Serial.println(line);
    NYTLength = line.length();
    DDTl("Length of Line is ",NYTLength);
    NYTCCounter = NYTLength;                                         // initialize the counter (send the terminator too)
    line.setCharAt(NYTCCounter,'\n');                                  // and ensure it IS a terminator
    NYTLine = line;                                                 // and copy the line for send  
//  Serial.println("closing connection");
    return true;
 }  // end of GetNYT

 bool SendNYT(){
    if (!GotNYT){NYTLine = "NY Times Not Available";                      // if didn't get it, can't send it
                 NYTCCounter = NYTLine.length();}
 //   DDTl("SendNYT Called with data length of ",NYTCCounter); 
    Segment[SSH_Type] = MC_GetNYT;                                      // first byte is a flag (command mirrored)
    Segment[SSH_Length] = NYTCCounter;                                     // second is number of data bytes past header
    Inptr = 0;                                                                // initialize 'get' pointer
    Outptr = SSH_Contents;                                                     // and the output pointer past header bytes
    while (NYTCCounter > 0){
      Segment[Outptr] = NYTLine.charAt(Inptr);                           // copy the character
      if (Segment[Outptr] == 226){                                        // if we hit the dreaded HTML apostrophe [sequence is 226,128,153]
        Segment[Outptr] = 39;                                           // set it to correct one
        Inptr = Inptr+2;                                                  // skip next two character
        NYTCCounter = NYTCCounter-2;                                      // increment pointer, decrement count
      }
 //   DDTv("Character",char(Segment[Outptr]));
 //   DDTl(" and value is ",int(Segment[Outptr]));
      Inptr++;                                                        // increment in pointer and output
      Outptr++;                                                       
      NYTCCounter--;                                                     // and decrement remaining character 
      if (Outptr == MaxBytes) {
        if (!Send_Segment(MaxBytes)) return false;
        Outptr = 0;                                                            // and reset pointer
//      DDTl("Status of NYT transmission",Status_Flag);                           // 0 = success, 1 = data too long, 2 NACK on address, 3= NACK on data, 4= other error*/
    }  // end of transmit segment
    }  // end of while
        if (Outptr != 0){                                                   // if we have a partial segment
        if  (!Send_Segment(Outptr)) return false;
//      DDTl("Status of NYT stub transmission",Status_Flag);                           // 0 = success, 1 = data too long, 2 NACK on address, 3= NACK on data, 4= other error*/
        }
        return true;
 }  // end of SendNYT

 bool GetNPR(){                                                                     // NPR News Feed 
   // Use WiFiClientSecure class to create TLS connection
  
const char* host = "feeds.npr.org";
// https://feeds.npr.org/1001/rss.xml
const int httpsPort = 443;

//const char* fingerprint = "b13ec36903f8bf4701d498261a0802ef63642bc3";

  if (!client.connect(host, httpsPort)) {
    DDTt("connection failed");
    return false;}

//  if (!client.verify(fingerprint, host)) {                                          // does not appear to need fingerprint
 //    DDTt("certificate doesn't match");
 //     return false;}
 String url = "/1001/rss.xml";
  Serial.print("requesting URL: ");
  Serial.println(url);

 client.print(String("GET ") + url +
                " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
             "Connection: close\r\n\r\n");
//  Serial.println("request sent");
  while (client.connected()) {
     line = client.readStringUntil('\n');
    if (line == "\r") {
      Serial.println("headers received");
      break;  }
  }
   line = client.readStringUntil('\n');
  if (line.startsWith("<?xml version")) {
   // Serial.println("Successfull!");
 } else {
   Serial.println("Failed");
   return false;
  }
 // Serial.println("reply was:");
 // Serial.println("==========");
//  Serial.println(line);
//  Serial.println("==========");
    SearchTag("<item>");                                        // search for item tag
    line = client.readStringUntil('\n');                        // read next line
    RemoveTags();
    line.replace("&#39;", "'");                                   // another instance of HTML apostrophe sneaking in - replace it
    line.replace("&amp;", "&");                                   // Replace '&amp;' with just '&' 
    Serial.println(line);
    NPRLength = line.length();
    DDTl("Length of Line is ",NPRLength);
    NPRCCounter = NPRLength;                                         // initialize the counter (send the terminator too)
    line.setCharAt(NPRCCounter,'\n');                                  // and ensure it IS a terminator
    NPRLine = line;                                                 // and copy the line for send  
 // Serial.println("closing connection");
    return true;
 }  // end of GetNPR

 bool SendNPR(){
    if (!GotNPR){NPRLine = "NPR Not Available";                      // if didn't get it, can't send it
                 NPRCCounter = NPRLine.length();}
 //   DDTl("SendNPR Called with data length of ",NPRCCounter); 
    Segment[SSH_Type] = MC_GetNPR;                                      // first byte is a flag (command mirrored)
    Segment[SSH_Length] = NPRCCounter;                                     // second is number of data bytes past header
    Inptr = 0;                                                                // initialize 'get' pointer
    Outptr = SSH_Contents;                                                     // and the output pointer past header bytes
    while (NPRCCounter > 0){
      Segment[Outptr] = NPRLine.charAt(Inptr);                           // copy the character
      if (Segment[Outptr] == 226){                                        // if we hit the dreaded HTML apostrophe [sequence is 226,128,153]
        Segment[Outptr] = 39;                                           // set it to correct one
        Inptr = Inptr+2;                                                  // skip next two character
        NPRCCounter = NYTCCounter-2;                                      // increment pointer, decrement count
      }
 //   DDTv("Character",char(Segment[Outptr]));
 //   DDTl(" and value is ",int(Segment[Outptr]));
      Inptr++;                                                        // increment in pointer and output
      Outptr++;                                                       
     NPRCCounter--;                                                     // and decrement remaining character 
      if (Outptr == MaxBytes) {
        if (!Send_Segment(MaxBytes)) return false;
        Outptr = 0;                                                            // and reset pointer
//      DDTl("Status of NPR transmission",Status_Flag);                           // 0 = success, 1 = data too long, 2 NACK on address, 3= NACK on data, 4= other error*/
    }  // end of transmit segment
    }  // end of while
        if (Outptr != 0){                                                   // if we have a partial segment
        if  (!Send_Segment(Outptr)) return false;
//      DDTl("Status of NPR stub transmission",Status_Flag);                           // 0 = success, 1 = data too long, 2 NACK on address, 3= NACK on data, 4= other error*/
        }
        return true;
 }  // end of SendNPR

/*
  void GetTheWeather() {                                                              // vestigial code for OpenWeatherMap get the weather...
    
 //open weather map api key 
String apiKey= "a0517cca5c02ebb3b2075b89d4121d96"; 
//the city you want the weather for 
String location= "98040,us"; 
WiFiClient client;
char server[] = "api.openweathermap.org"; 
//api.openweathermap.org/data/2.5/weather?q=London,uk&APPID=a0517cca5c02ebb3b2075b89d4121d96 
//api.openweathermap.org/data/2.5/weather?zip=98040,us   
//api.openweathermap.org/data/2.5/weather?q=98040,us&APPID=a0517cca5c02ebb3b2075b89d4121d96&units=imperial&mode=xml   gets you xml and farenheit 
 Serial.println("\nStarting connection to server..."); 
 // if you get a connection, report back via serial: 
 if (client.connect(server, 80)) { 
   Serial.println("connected to server"); 
   // Make a HTTP request: 
   client.print("GET /data/2.5/weather?"); 
   client.print("q="+location); 
   client.print("&appid="+apiKey); 
   client.print("&cnt=3"); 
   client.println("&units=imperial"); 
   client.println("Host: api.openweathermap.org"); 
   client.println("Connection: close"); 
   client.println(); 
 } else { 
   Serial.println("unable to connect"); 
 } 
 delay(1000); 

    line = ""; 
   line = client.readStringUntil('\n'); 
   Serial.println(line); 

} // end of Get Weather
*/

bool GetACW() {                                                             // get accuweather

   // Use WiFiClientSecure class to create TLS connection
  
  const char* host = "rss.accuweather.com";
  const int httpsPort = 443;

// Use web browser to view and copy
// SHA1 fingerprint of the certificate
    
//https://rss.accuweather.com/rss/liveweather_rss.asp?locCode=98040
//7B:E1:6E:70:F8:2F:64:52:3B:1A:71:F4:42:43:4A:1A:11:06:AC:8E
const char* fingerprint = "7B E1 6E 70 F8 2F 64 52 3B 1A 71 F4 42 43 4A 1A 11 06 AC 8E";

  if (!client.connect(host, httpsPort)) {
    DDTt("connection failed");
    return false;}

  if (!client.verify(fingerprint, host)) {
    DDTt("certificate doesn't match");
      return false;
  }

//  String url = "/rss/liveweather_rss.asp?locCode=98040";
   String url = "/rss/liveweather_rss.asp?locCode=";
   url = url + MyZipCode;
//  Serial.print("requesting URL: ");
//  Serial.println(url);

 client.print(String("GET ") + url +
                " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
             "Connection: close\r\n\r\n");
 // Serial.println("request sent");
  while (client.connected()) {
    String line = client.readStringUntil('\n');
    if (line == "\r") {
 //     Serial.println("headers received");
      break;
    }
  }
   line = client.readStringUntil('\n');
  if (line.startsWith("<?xml version")) {
 //   Serial.println("Successful!");
 } else {
   DDTsl("XML Version test failed",line);
   return false;
  }
// Serial.println("reply was:");
// Serial.println("==========");
//  Serial.println(line);
//  Serial.println("==========");


   SearchTag("<item>");                                     // read until <item> found
   line = client.readStringUntil('\n');                     // read next line
   RemoveTags();                                            // remove tags on line
   Serial.println(line);                                   // should be today's conditions terse format                                                    
   SearchTag("<description>");                              // find today's longer version of day forecast             
   RemoveTags();                                             // and remove tags
   line.replace(" &#176;","~");                              // Edit out HTML degree in weather feed and insert tilde
   Serial.println(line);                                      // should be today's conditions verbose
   ACWLength = line.length();
// DDTl("Length of Weather Line is ",ACWLength);
   ACWCCounter = ACWLength;                                         // initialize the counter (send the terminator too)
   line.setCharAt(ACWCCounter,'\n');                                  // and ensure it IS a terminator
   ACWLine = line;                                                  // and copy the line for send                                                                 
//[UNCOMMENT TO GET TOMORROW FORECAST]   
    SearchTag("</item>");                                    // read string from RSS site til out of current weather     
    SearchTag("<item>");                                        
    SearchTag("<title>");
    RemoveTags();                                               // get rid of the tags
    Serial.println(line);                                   // should be forecast description (e.g., "2/27/2020 FORECAST")
    SearchTag("<description>");
    RemoveTags();                                             // clean it up
    RemoveIMGThroughGIF();
    RemoveTags();                                
   Serial.println(line);                                   // should be forecast detail (e.g., ")
   SearchTag("</item>");
   SearchTag("<item>");
   SearchTag("<title>");
   RemoveTags();                                               // get rid of the tags
   Serial.println(line);                                   // should be forecast description (e.g., "2/27/2020 FORECAST")
   SearchTag("<description>");
   RemoveTags();                                             // clean it up
   RemoveIMGThroughGIF();
   RemoveTags();                                            
   Serial.println(line);                                   // should be forecast detail (e.g., ")
   ACWLine = ACWLine + "$" + line;                                   // combine lines (Current and forecast)
   ACWLength = ACWLine.length();                                       // reset length to reflect combined line
// DDTl("Length of Weather Forecast Line is ",ACWFLength);
   ACWCCounter = ACWLength;                                         // reset line length (send the terminator too)
//   line.setCharAt(ACWCCounter,'\n');                                  // and ensure it IS a terminator
 
  //Serial.println("closing connection");
    return true;
 }  // end of GetAccuweather

bool SendACW(){                                                               //  send "Current + "$" + "Forecast"
    if (!GotACW){ACWLine = "Accuweather Not Available";                      // if didn't get it, can't send it
                ACWCCounter = ACWLine.length();}
//  DDTl("SendACW Called with data length of ",ACWCCounter+ACWFCCounter);  
    Segment[SSH_Type] = MC_GetACW;
    Segment[SSH_Length] = ACWCCounter;
    Inptr = 0;
    Outptr = SSH_Contents;                                                     // and the output pointer
    while (ACWCCounter > 0){
      Segment[Outptr] = ACWLine.charAt(Inptr);                           // copy the character
      Inptr++;                                                        // increment in pointer and output
      Outptr++;                                                       
      ACWCCounter--;                                                     // and decrement remaining character 
      if (Outptr == MaxBytes) {
        if (!Send_Segment(MaxBytes)) return false;
        Outptr = 0;                                                            // and reset pointer
//      DDTl("Status of ACW transmission",Status_Flag);                           // 0 = success, 1 = data too long, 2 NACK on address, 3= NACK on data, 4= other error*/
    }  // end of transmit segment
    }  // end of while
        if (Outptr != 0){                                                   // if we have a partial segment
        if  (!Send_Segment(Outptr)) return false;
//         DDTl("Status of ACW stub transmission",Status_Flag);                           // 0 = success, 1 = data too long, 2 NACK on address, 3= NACK on data, 4= other error*/
        }
        return true;
 }  // end of SendACW

bool GetTheTime(){
                                 // we got a request AND we are connected
  t_unix_date = ntpClient.getUnixTime();

  if(t_unix_date == 0) return false;

  MyYear = year(t_unix_date);
  MyMonth = month(t_unix_date);
  MyDay = day(t_unix_date);
  MyHour = hour(t_unix_date);
  MyMinute = minute(t_unix_date);
  MySecond = second(t_unix_date);
  MyWeekDay = weekday(t_unix_date);                             // note: returns 1-7, not 0-6
/*
  Serial.print("Today's Date and Time: ");
  Serial.print(MyDaysOfTheWeek[MyWeekDay-1]);
  Serial.print("  ");
  Serial.print(MyWeekDay);
  Serial.print("  ");
  Serial.print(MyMonth);
  Serial.print("/");
  Serial.print(MyDay);
  Serial.print("/");
  Serial.print(MyYear);
  Serial.print("  ");
  Serial.print(MyHour);
  Serial.print(":");
  if (MyMinute < 10) {
    Serial.print("0");
  }
  Serial.print(MyMinute);
  Serial.print(":");
  if (MySecond < 10) {
    Serial.print("0");
  }
  Serial.print(MySecond);
  Serial.println(" ");
*/
  Segment[SSH_Type] = MC_GetTime;                                              // load segment array up
  Segment[SSH_Length] = 7;                                                    // number of data bytes
  Segment[SSH_Contents] = MyYear-2019;                                        // base year is 2019, so it fits in a byte
  Segment[SSH_Contents+1] = MyMonth;
  Segment[SSH_Contents+2] = MyDay;
  Segment[SSH_Contents+3] = MyHour;
  Segment[SSH_Contents+4] = MyMinute;
  Segment[SSH_Contents+5] = MySecond;
  Segment[SSH_Contents+6] = MyWeekDay;
  Send_Segment(9);
  return true;
} 

  void SearchTag(String MyTag){
    do { line = client.readStringUntil('\n');               // read string from RSS site until this string is found
    } while (line.indexOf(MyTag) <0);
//    Serial.print("Searchtag found ");
//    Serial.print(MyTag);
//   Serial.print(" in line ");
//   Serial.println(line);
  }

  void RemoveTags(){
    line.remove(0,(line.indexOf(">"))+1);
    line.remove(line.indexOf("<"),line.indexOf(">"));
  }       // end of RemoveTags
  void RemoveIMGThroughGIF(){
    line.remove(line.indexOf("img")-4,line.indexOf("gif"));
  }       // end of RIG

bool Send_Segment(int bytestosend){
    int trycounter = Repeat_Sends;
    do {Wire.beginTransmission(MasterChannel);                              // Send bytes result to Master
    Wire.write(Segment,bytestosend);                                         //
//  DDTl("segment transmission sent",bytestosend);      
    Status_Flag = Wire.endTransmission(true);
    delay(Segment_Delay);} while ((Status_Flag != 0) && (trycounter-- >0));           // keep trying until good status or counter gone
    if (trycounter > 0) {return true;} else {return false;}
}

Arduino code for clock (Arduino Mega)

Arduino
Runs the main clock
No preview (download only).

Credits

spudnut1

spudnut1

10 projects • 15 followers

Comments