359 lines
8.3 KiB
C++
359 lines
8.3 KiB
C++
/*
|
|
* Copyright Paul Warren 2019 <pwarren@pwarren.id.au>
|
|
*
|
|
* Released under the terms of the GPLv3 license.
|
|
*
|
|
*D1Mini: Colour : UART Module
|
|
* D5: White : DOUT
|
|
* D6: Green : DIN
|
|
* D7: Yellow : Wake Up
|
|
* D8: Blue : Reset
|
|
*
|
|
*
|
|
*/
|
|
#include <ESP8266HTTPClient.h>
|
|
#include <ESP8266WiFi.h>
|
|
#include <WiFiUdp.h>
|
|
#include <NTPClient.h>
|
|
#include <Timezone.h>
|
|
#include <ArduinoJson.h>
|
|
|
|
#include "epd.h"
|
|
#include "credential.h"
|
|
|
|
|
|
// BOM, see bom_rrd2.py
|
|
const String ds_url = "http://pwarren.id.au/darksky/bom.json";
|
|
|
|
bool ds_done = false;
|
|
|
|
// 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;
|
|
|
|
|
|
// when to wake up the display and get going
|
|
int wakeup_seconds = 50;
|
|
|
|
|
|
// Network clients
|
|
WiFiClient wfclient;
|
|
WiFiUDP ntpUDP;
|
|
HTTPClient http;
|
|
NTPClient timeClient(ntpUDP, "pi.lan", 0, 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
|
|
|
|
//NTPClient timeClient(ntpUDP, "au.pool.ntp.org", 0, 60000); //use external ntp server, update every 10 minutes
|
|
|
|
// 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;
|
|
|
|
// Font width
|
|
int dwidth = 185;
|
|
|
|
// yes this seems backwards but it works...
|
|
void ledOn(void) { digitalWrite(led, LOW);}
|
|
void ledOff(void) { digitalWrite(led, HIGH);}
|
|
void wait(void) { delay(1500);}
|
|
|
|
|
|
// globals for the temperature :(
|
|
const char* current_outside;
|
|
const char* current_bedroom;
|
|
const char* current_lounge;
|
|
|
|
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\nSTARTING\r\n");
|
|
|
|
wifi();
|
|
timeClient.begin();
|
|
ntpUpdate();
|
|
/* weatherUpdate();
|
|
printDateTime(1);
|
|
|
|
epd_update();
|
|
wait(); */
|
|
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() {
|
|
if (timeClient.update()) {
|
|
setTime(timeClient.getEpochTime());
|
|
}
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
// wait();
|
|
}
|
|
|
|
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);
|
|
delay(500);
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
|
void printDateTime(int update_epd)
|
|
{
|
|
char buf[64];
|
|
|
|
time_t t;
|
|
t = ausET.toLocal(now()+60, &tcr);
|
|
|
|
char m[4]; // temporary storage for month string (DateStrings.cpp uses shared buffer)
|
|
strncpy(m, monthShortStr(month(t)), 4);
|
|
sprintf(buf, "%.2d:%.2d:%.2d", hour(t), minute(t), second(t));
|
|
Serial.print(buf); Serial.print(" ");
|
|
|
|
if (update_epd > 0) {
|
|
Serial.println("Adding Time");
|
|
disp_time(hour(t), minute(t));
|
|
}
|
|
|
|
sprintf(buf, "%s %.2d %s %d",
|
|
dayShortStr(weekday(t)),
|
|
day(t),
|
|
m,
|
|
year(t));
|
|
|
|
Serial.println(buf);
|
|
|
|
if (update_epd > 0) {
|
|
Serial.println("Adding Date");
|
|
epd_set_en_font(ASCII64);
|
|
epd_disp_string(buf, 50, 225);
|
|
}
|
|
}
|
|
|
|
void weatherUpdate(void) {
|
|
char buf[64];
|
|
const size_t capacity = 4*JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(4) + 150;
|
|
DynamicJsonDocument jsonBuffer(capacity);
|
|
|
|
http.begin(wfclient, ds_url);
|
|
int httpCode = http.GET();
|
|
|
|
if (httpCode > 0) {
|
|
auto error = deserializeJson(jsonBuffer, http.getString());
|
|
if (error) {
|
|
Serial.print("Failed to parse json");
|
|
return;
|
|
}
|
|
http.end();
|
|
|
|
const char* today_day = jsonBuffer["today"]["day"]; // "Wednesday"
|
|
const char* today_icon = jsonBuffer["today"]["icon"]; // "sunny.jpg"
|
|
int today_max = jsonBuffer["today"]["max"]; // "27"
|
|
|
|
const char* tomorrow_day = jsonBuffer["tomorrow"]["day"]; // "Thursday"
|
|
const char* tomorrow_icon = jsonBuffer["tomorrow"]["icon"]; // "sunny.jpg"
|
|
int tomorrow_max = jsonBuffer["tomorrow"]["max"]; // "31"
|
|
|
|
const char* day_after_day = jsonBuffer["day_after"]["day"]; // "Friday"
|
|
const char* day_after_icon = jsonBuffer["day_after"]["icon"]; // "pcloud.jpg"
|
|
int day_after_max = jsonBuffer["day_after"]["max"]; // "33"
|
|
|
|
int current_outside = jsonBuffer["current"]["outside"];
|
|
int current_bedroom = jsonBuffer["current"]["bedroom"];
|
|
int current_lounge = jsonBuffer["current"]["lounge"];
|
|
|
|
Serial.println("Updating EPD with weather");
|
|
|
|
epd_set_en_font(ASCII64);
|
|
|
|
//Today
|
|
epd_disp_bitmap(today_icon, 0, 290);
|
|
epd_disp_string(today_day, 0, 536);
|
|
sprintf(buf, "%d", today_max);
|
|
epd_disp_string(buf, 75, 460);
|
|
|
|
//Tomorrow
|
|
epd_disp_bitmap(tomorrow_icon, 267, 290);
|
|
epd_disp_string(tomorrow_day, 260, 536);
|
|
sprintf(buf, "%d", tomorrow_max);
|
|
epd_disp_string(buf, 352, 460);
|
|
|
|
//Day After
|
|
epd_disp_bitmap(day_after_icon, 533, 290);
|
|
epd_disp_string(day_after_day, 533, 536);
|
|
sprintf(buf, "%d", day_after_max);
|
|
epd_disp_string(buf, 615, 460);
|
|
|
|
//Serial.println("Adding Temps");
|
|
sprintf(buf, "E: %d I: %d",
|
|
current_outside,
|
|
current_lounge);
|
|
//Serial.println(buf);
|
|
epd_disp_string(buf, 500, 225);
|
|
|
|
} else {
|
|
Serial.print("Error on HTTP Request: ");
|
|
Serial.println(httpCode);
|
|
}
|
|
|
|
}
|
|
|
|
void loop() {
|
|
int sleep_seconds = 0;
|
|
|
|
Serial.println("Back from sleep!");
|
|
|
|
if (WiFi.status() != WL_CONNECTED) {
|
|
wifi();
|
|
}
|
|
|
|
ntpUpdate();
|
|
|
|
if (second(now()) >= wakeup_seconds) {
|
|
epd_wakeup();
|
|
epd_clear();
|
|
weatherUpdate();
|
|
Serial.print("Weather details sent: ");
|
|
Serial.println(second(now()));
|
|
printDateTime(1);
|
|
Serial.println("Waiting on minute to change");
|
|
while (second(now()) != 0) {
|
|
delay(500);
|
|
}
|
|
|
|
}
|
|
Serial.println("EPD Update");
|
|
epd_update();
|
|
delay(4000);
|
|
Serial.println("EPD Stop");
|
|
epd_enter_stopmode();
|
|
|
|
sleep_seconds = wakeup_seconds - second(now());
|
|
|
|
if (sleep_seconds < 0) {
|
|
sleep_seconds = 10;
|
|
}
|
|
|
|
Serial.print("Sleeping for: ");
|
|
Serial.println(sleep_seconds);
|
|
|
|
delay(sleep_seconds * 1000);
|
|
|
|
}
|