2019-11-22 19:34:26 +11:00
/*
* Copyright Paul Warren 2019 < pwarren @ pwarren . id . au >
*
* Released under the terms of the GPLv3 license .
*/
# include <ESP8266HTTPClient.h>
# include <ESP8266WiFi.h>
# include <WiFiUdp.h>
# include <NTPClient.h>
# include <Timezone.h>
2019-11-23 20:21:10 +11:00
# include <ArduinoJson.h>
2019-11-22 19:34:26 +11:00
# include "epd.h"
# include "credential.h"
2019-11-23 20:21:10 +11:00
2019-11-22 19:34:26 +11:00
// Weather bits
// Australian BOM bits, Belconnen is mine.
// see http://www.bom.gov.au/catalogue/data-feeds.shtml
//const char* aac = "NSW_PT254";
//const char* bom_url = "ftp://ftp.bom.gov.au/anon/gen/fwo/IDN11060.xml";
// openweathermap, api_key from credential.h
2019-11-23 20:21:10 +11:00
// const String owm_url = "http://api.openweathermap.org/data/2.5/weather?q=Belconnen,AU&units=metric&APPID=";
2019-11-26 23:42:01 +11:00
// DarkSky see darksky.py
//const String ds_url = "http://pwarren.id.au/darksky/darksy.json";
// BOM, see bom_xml.py
const String ds_url = " http://pwarren.id.au/darksky/bom.json " ;
2019-11-22 19:34:26 +11:00
2019-11-23 20:21:10 +11:00
bool ds_done = false ;
2019-11-22 19:34:26 +11:00
// Timezone bits
// Australia Eastern Time Zone (Sydney, Melbourne)
TimeChangeRule aEDT = { " AEDT " , First , Sun , Oct , 2 , 660 } ; // UTC + 11 hours
TimeChangeRule aEST = { " AEST " , First , Sun , Apr , 3 , 600 } ; // UTC + 10 hours
Timezone ausET ( aEDT , aEST ) ;
TimeChangeRule * tcr ;
// Network clients
WiFiUDP ntpUDP ;
HTTPClient http ;
2019-11-26 23:42:15 +11:00
NTPClient timeClient ( ntpUDP , " raspberrypi.lan " , 9 , 60000 ) ; //use internal ntp server, update every 10 minutes, taking in to account the 9 seconds it takes to update the screen for the current time
2019-11-22 19:34:26 +11:00
2019-11-23 20:21:10 +11:00
//NTPClient timeClient(ntpUDP, "au.pool.ntp.org", 0, 60000); //use internal ntp server, update every 10 minutes
2019-11-22 19:34:26 +11:00
// defined in "credentials.h"
const char * ssid = ssid_name ; // The SSID (name) of your Wi-Fi network
const char * password = ssid_pass ; // The password of the Wi-Fi network
const int led = LED_BUILTIN ;
2019-11-23 20:21:10 +11:00
// Font width
int dwidth = 185 ;
2019-11-22 19:34:26 +11:00
// yes this seems backwards but it works...
void ledOn ( void ) { digitalWrite ( led , LOW ) ; }
void ledOff ( void ) { digitalWrite ( led , HIGH ) ; }
void wait ( void ) { delay ( 1500 ) ; }
void setup ( ) {
pinMode ( led , OUTPUT ) ;
ledOff ( ) ;
wifi_set_sleep_type ( LIGHT_SLEEP_T ) ;
epd_init ( ) ;
epd_wakeup ( ) ;
epd_set_memory ( MEM_NAND ) ;
epd_set_color ( BLACK , WHITE ) ;
epd_set_en_font ( ASCII64 ) ;
epd_clear ( ) ;
Serial . begin ( 115200 ) ; // Start serial communication
Serial . setTimeout ( 2000 ) ;
while ( ! Serial ) { }
Serial . println ( " \r \n \r \n STARTING \r \n " ) ;
wifi ( ) ;
timeClient . begin ( ) ;
ntpUpdate ( ) ;
epd_clear ( ) ;
2019-11-23 20:21:10 +11:00
weatherUpdate ( ) ;
2019-11-22 19:34:26 +11:00
printDateTime ( 1 ) ;
2019-11-23 20:21:10 +11:00
epd_update ( ) ;
2019-11-22 19:34:26 +11:00
ledOff ( ) ;
}
void wifi ( ) {
WiFi . persistent ( false ) ;
WiFi . mode ( WIFI_OFF ) ;
WiFi . mode ( WIFI_STA ) ;
WiFi . begin ( ssid , password ) ; // Access WiFi
Serial . print ( " Connecting to " ) ;
Serial . print ( ssid ) ;
Serial . print ( " ... " ) ;
while ( WiFi . status ( ) ! = WL_CONNECTED ) { // Wait for WiFi to connect
delay ( 250 ) ;
Serial . print ( " . " ) ;
}
Serial . println ( ' \n ' ) ;
Serial . println ( " WiFi connection established " ) ;
Serial . print ( " Device's IP address is " ) ;
Serial . println ( WiFi . localIP ( ) ) ; // Show device's IP address
}
void ntpUpdate ( ) {
2019-11-23 20:21:10 +11:00
if ( timeClient . update ( ) ) {
setTime ( timeClient . getEpochTime ( ) ) ;
}
2019-11-22 19:34:26 +11:00
}
void disp_digit ( int digit , int xpos ) {
// digit: digit to display
// xpos: X digit position, indexed at 1
int dpos = 0 ;
int ypos = 0 ;
dpos = ( ( xpos - 1 ) * dwidth ) ;
if ( xpos > 2 ) {
dpos + = 60 ; // account for colon
}
switch ( digit ) {
case 0 :
epd_disp_bitmap ( " 0.JPG " , dpos , ypos ) ;
break ;
case 1 :
epd_disp_bitmap ( " 1.JPG " , dpos , ypos ) ;
break ;
case 2 :
epd_disp_bitmap ( " 2.JPG " , dpos , ypos ) ;
break ;
case 3 :
epd_disp_bitmap ( " 3.JPG " , dpos , ypos ) ;
break ;
case 4 :
epd_disp_bitmap ( " 4.JPG " , dpos , ypos ) ;
break ;
case 5 :
epd_disp_bitmap ( " 5.JPG " , dpos , ypos ) ;
break ;
case 6 :
epd_disp_bitmap ( " 6.JPG " , dpos , ypos ) ;
break ;
case 7 :
epd_disp_bitmap ( " 7.JPG " , dpos , ypos ) ;
break ;
case 8 :
epd_disp_bitmap ( " 8.JPG " , dpos , ypos ) ;
break ;
case 9 :
epd_disp_bitmap ( " 9.JPG " , dpos , ypos ) ;
break ;
}
2019-11-26 23:42:01 +11:00
wait ( ) ;
2019-11-22 19:34:26 +11:00
}
void disp_time ( int hours , int minutes ) {
// first digit of hours
if ( hours > 19 ) {
disp_digit ( 2 , 1 ) ;
hours - = 20 ;
} else if ( hours > 9 ) {
disp_digit ( 1 , 1 ) ;
hours - = 10 ;
} else {
disp_digit ( 0 , 1 ) ;
}
// second hours digit
disp_digit ( hours , 2 ) ;
epd_disp_bitmap ( " COLO.JPG " , 2 * dwidth , 0 ) ;
2019-11-23 20:21:10 +11:00
delay ( 500 ) ;
2019-11-22 19:34:26 +11:00
// first minutes digit
if ( minutes > 49 ) {
disp_digit ( 5 , 3 ) ;
minutes - = 50 ;
} else if ( minutes > 39 ) {
disp_digit ( 4 , 3 ) ;
minutes - = 40 ;
} else if ( minutes > 29 ) {
disp_digit ( 3 , 3 ) ;
minutes - = 30 ;
} else if ( minutes > 19 ) {
disp_digit ( 2 , 3 ) ;
minutes - = 20 ;
} else if ( minutes > 9 ) {
disp_digit ( 1 , 3 ) ;
minutes - = 10 ;
} else {
disp_digit ( 0 , 3 ) ;
}
// second minutes digit
disp_digit ( minutes , 4 ) ;
2019-11-23 20:21:10 +11:00
2019-11-22 19:34:26 +11:00
}
void printDateTime ( int update_epd )
{
char buf [ 64 ] ;
2019-11-23 20:21:10 +11:00
time_t t ;
2019-11-22 19:34:26 +11:00
t = ausET . toLocal ( now ( ) , & tcr ) ;
2019-11-23 20:21:10 +11:00
2019-11-22 19:34:26 +11:00
char m [ 4 ] ; // temporary storage for month string (DateStrings.cpp uses shared buffer)
strcpy ( m , monthShortStr ( month ( t ) ) ) ;
sprintf ( buf , " %.2d:%.2d:%.2d " , hour ( t ) , minute ( t ) , second ( t ) ) ;
Serial . print ( buf ) ; Serial . print ( " " ) ;
if ( update_epd > 0 ) {
disp_time ( hour ( t ) , minute ( t ) ) ;
2019-11-23 20:21:10 +11:00
wait ( ) ;
2019-11-22 19:34:26 +11:00
}
sprintf ( buf , " %s %.2d %s %d %s " , dayShortStr ( weekday ( t ) ) , day ( t ) , m , year ( t ) , & tcr - > abbrev ) ;
Serial . println ( buf ) ;
if ( update_epd > 0 ) {
epd_set_en_font ( ASCII64 ) ;
2019-11-23 20:21:10 +11:00
epd_disp_string ( buf , 150 , 225 ) ;
2019-11-26 23:42:01 +11:00
wait ( ) ;
2019-11-22 19:34:26 +11:00
}
}
void weatherUpdate ( void ) {
2019-11-26 23:42:01 +11:00
const size_t capacity = 4 * JSON_OBJECT_SIZE ( 3 ) + 150 ;
2019-11-23 20:21:10 +11:00
DynamicJsonBuffer jsonBuffer ( capacity ) ;
http . begin ( ds_url ) ;
2019-11-22 19:34:26 +11:00
int httpCode = http . GET ( ) ;
2019-11-23 20:21:10 +11:00
2019-11-22 19:34:26 +11:00
if ( httpCode > 0 ) {
2019-11-23 20:21:10 +11:00
JsonObject & root = jsonBuffer . parseObject ( http . getString ( ) ) ;
if ( ! root . success ( ) ) {
Serial . print ( F ( " parseObject() failed: " ) ) ;
return ;
}
2019-11-26 23:42:01 +11:00
http . end ( ) ;
JsonObject & today = root [ " today " ] ;
const char * today_day = today [ " day " ] ; // "Wednesday"
const char * today_icon = today [ " icon " ] ; // "sunny.jpg"
const char * today_max = today [ " max " ] ; // "27"
2019-11-23 20:21:10 +11:00
2019-11-26 23:42:01 +11:00
JsonObject & tomorrow = root [ " tomorrow " ] ;
const char * tomorrow_day = tomorrow [ " day " ] ; // "Thursday"
const char * tomorrow_icon = tomorrow [ " icon " ] ; // "sunny.jpg"
const char * tomorrow_max = tomorrow [ " max " ] ; // "31"
2019-11-23 20:21:10 +11:00
2019-11-26 23:42:01 +11:00
JsonObject & day_after = root [ " day_after " ] ;
const char * day_after_day = day_after [ " day " ] ; // "Friday"
const char * day_after_icon = day_after [ " icon " ] ; // "pcloud.jpg"
const char * day_after_max = day_after [ " max " ] ; // "33"
2019-11-23 20:21:10 +11:00
2019-11-26 23:42:01 +11:00
Serial . println ( " Updating EPD " ) ;
2019-11-23 20:21:10 +11:00
epd_set_en_font ( ASCII64 ) ;
//Today
2019-12-01 19:18:20 +11:00
epd_disp_bitmap ( today_icon , 0 , 290 ) ;
2019-11-26 23:42:01 +11:00
wait ( ) ;
2019-12-01 19:18:20 +11:00
epd_disp_string ( today_day , 0 , 536 ) ;
2019-11-26 23:42:01 +11:00
wait ( ) ;
2019-12-01 19:18:20 +11:00
epd_disp_string ( today_max , 75 , 460 ) ;
2019-11-26 23:42:01 +11:00
wait ( ) ;
2019-11-23 20:21:10 +11:00
2019-12-01 19:18:20 +11:00
2019-11-23 20:21:10 +11:00
//Tomorrow
2019-12-01 19:18:20 +11:00
epd_disp_bitmap ( tomorrow_icon , 267 , 290 ) ;
2019-11-26 23:42:01 +11:00
wait ( ) ;
2019-12-01 19:18:20 +11:00
epd_disp_string ( tomorrow_day , 260 , 536 ) ;
2019-11-26 23:42:01 +11:00
wait ( ) ;
2019-12-01 19:18:20 +11:00
epd_disp_string ( tomorrow_max , 352 , 460 ) ;
2019-11-26 23:42:01 +11:00
wait ( ) ;
2019-12-01 19:18:20 +11:00
2019-11-26 23:42:01 +11:00
//Day After
2019-12-01 19:18:20 +11:00
epd_disp_bitmap ( day_after_icon , 533 , 290 ) ;
2019-11-26 23:42:01 +11:00
wait ( ) ;
2019-12-01 19:18:20 +11:00
epd_disp_string ( day_after_day , 533 , 536 ) ;
2019-11-26 23:42:01 +11:00
wait ( ) ;
2019-12-01 19:18:20 +11:00
epd_disp_string ( day_after_max , 615 , 460 ) ;
2019-11-26 23:42:01 +11:00
wait ( ) ;
2019-12-01 19:18:20 +11:00
2019-11-26 23:42:01 +11:00
2019-11-22 19:34:26 +11:00
} else {
Serial . print ( " Error on HTTP Request: " ) ;
Serial . println ( httpCode ) ;
}
2019-11-26 23:42:01 +11:00
2019-11-22 19:34:26 +11:00
}
void loop ( ) {
2019-11-26 23:42:01 +11:00
int wakeup_seconds = 43 ;
2019-11-22 19:34:26 +11:00
int sleep_seconds = 0 ;
Serial . println ( " Back from sleep! " ) ;
if ( WiFi . status ( ) ! = WL_CONNECTED ) {
wifi ( ) ;
}
ntpUpdate ( ) ;
2019-11-26 23:42:01 +11:00
if ( second ( now ( ) ) > = wakeup_seconds ) {
2019-11-22 19:34:26 +11:00
epd_wakeup ( ) ;
2019-11-23 20:21:10 +11:00
epd_clear ( ) ;
weatherUpdate ( ) ;
2019-11-26 23:42:01 +11:00
Serial . print ( " Weather details sent: " ) ;
Serial . println ( second ( now ( ) ) ) ;
while ( second ( now ( ) ) ! = 0 ) {
delay ( 500 ) ;
}
2019-11-22 19:34:26 +11:00
printDateTime ( 1 ) ;
2019-11-23 20:21:10 +11:00
epd_update ( ) ;
2019-11-26 23:42:01 +11:00
delay ( 3000 ) ;
2019-11-22 19:34:26 +11:00
epd_enter_stopmode ( ) ;
}
2019-11-26 23:42:01 +11:00
sleep_seconds = wakeup_seconds - second ( now ( ) ) ;
2019-11-22 19:34:26 +11:00
Serial . print ( " Sleeping for: " ) ;
Serial . println ( sleep_seconds ) ;
delay ( sleep_seconds * 1000 ) ;
}