Oled and Time
- >> Raspberry graphic, Temperature/Voltage, Time
- >> Mods will show peanut graphic, Temperature/Voltage,
Murphy, Web input, Time
https://www.geekstips.com/arduino-time-sync-ntp-server-esp8266-udp/
/*
OLED code modified from esp8266-oled-ssd1306 demo
The MIT License (MIT)
Copyright (c) 2018 by ThingPulse, Daniel Eichhorn
Copyright (c) 2018 by Fabrice Weinberg
See complete copyright notice at the bottom of the
file
Modified from the demo program by the above authors by Deid
Reimer (Jan 2019) to:
- Simplify to the specific application
- Add wifi and web server
- Add temperature and voltage
- Add Murphy saying
- Add Time
===========================
NTP time code modified from
- www.geekstips.com for Arduino Time Sync
from NTP Server using ESP8266 WiFi module
*/
// Include wifi and web server.
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266WebServer.h>
// Get time requirements
#include <WiFiUdp.h>
#include <time.h>
#include <Ticker.h>
// local port to listen for UDP packets
unsigned int localPort = 2390;
IPAddress timeServerIP;
const char* ntpServerName = "0.ca.pool.ntp.org";
// NTP time stamp is in the first 48 bytes of the message
const int NTP_PACKET_SIZE = 48;
//buffer to hold incoming and outgoing NTP packets
byte packetBuffer[ NTP_PACKET_SIZE];
// Holds returned and calculated Unix time.
time_t unixTime;
time_t unixTimeNTP;
// Tick and ntp times in seconds and create the Ticker attach
objects.
int tickTime = 1;
int ntpTime = 300;
Ticker tick;
Ticker ntp;
// Set true by the ntp Ticker (it was not happy getting the time
in a timer interrupt routine - duh?)
bool timeToGetNTPtime = false;
// Used in loop() {} to count up the display period
unsigned long lastmillis = 0;
// Create a UDP instance to let us send and receive packets over
UDP
WiFiUDP udp;
// Include libraries for the DS18B20 temperature sensor
#include <OneWire.h>
#include <DallasTemperature.h>
// Include the OLED display library
#include "SSD1306Wire.h" // legacy include: `#include "SSD1306.h"`
// Include custom images
#include "images.h"
// Set up to read battery voltage on ADC.
ADC_MODE(ADC_VCC);
// Temperature ata wire is connected to D6/GPIO 12
#define ONE_WIRE_BUS D6
// Setup a oneWire instance to communicate with any OneWire
devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// and pass our oneWire instance reference to the Dallas
Temperature routine
DallasTemperature DS18B20(&oneWire);
// Create variables to hold the temperature and voltage
measurements
char temperatureCString[8];
char voltageCString[8];
// Create a variable type to hold the display function addresses
typedef void (*Demo)(void);
// Delay time. This will be changed by each display
function.
int delayNow = 5;
// Which of the n display functions is current
int demoMode = 0;
// Text from the web form
String inputText;
// Which of the several display lists choose by >>...
is current
int displayType = 2;
// Instantiate and tell the web server to listen on port 80
ESP8266WebServer server(80);
// Initialize the OLED display using Wire library
// 0x3C is the display address
// D3 is SDA - data line
// D5 is SCL - clock line
SSD1306Wire display(0x3c, D3, D5);
// -----------------------------------------
// Functions
// Wifi web and time functions
// Convert IPV4 IP to String for display on the OLED
String ipToString(IPAddress ip) {
String ips = String(ip[0]) + "." + String(ip[1]) + "." +
String(ip[2]) + "." + String(ip[3]);
return ips;
}
// Function to request WiFi IP address and show the process.
bool getIP(IPAddress ip, IPAddress gateway, IPAddress subnet,
char* ssid, char* password){
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.setFont(ArialMT_Plain_16);
WiFi.disconnect();
WiFi.config(ip, gateway, subnet);
WiFi.begin(ssid, password);
// Loop until a connection or 20 tries
int j = 0;
while (WiFi.status() != WL_CONNECTED and j < 20) {
delay(500);
Serial.print(j);
Serial.println(ssid);
display.clear();
display.drawString(0, 0, String(j));
display.drawString(0, 20, ssid);
display.display();
j++;
}
// Display the connection information if connected and
return status
if (WiFi.status() == WL_CONNECTED) {
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
display.clear();
display.drawString(0, 0, "IP address: ");
display.drawString(0, 15,
ipToString(WiFi.localIP()));
Serial.print("Connected to ");
Serial.println(ssid);
display.drawString(0, 30, "Connected to");
display.drawString(0, 45, ssid);
display.display();
delay(10000);
return true;
} else {
return false;
}
}
// Function to build amd display the web page.
void showPage() {
String webPage00 = "<html><head><meta
charset=\"UTF-8\"><meta name=viewport
content=\"width=device-width,
initial-scale=1.5\"><title>OLDisplay</title>";
String webPage000 = "<meta name = \"viewport\" content =
\"width = device-width, initial-scale = 1.0, maximum-scale = 1.0,
user-scalable=0\">";
String webPage01 = "</head><body>";
String webPage0 = "<h3>Message for OLED
...</h3>";
String webPage02 = "<FORM METHOD=\"get\"
action=\"/getForm\"> <input type=\"text\"
name=\"getText\">";
String webPage03 = "<input type=\"submit\"
value=\"Submit\"></form>" ;
String webPage99 = "</body></html>";
String webPage = webPage00 + webPage000 + webPage01 +
webPage0 + webPage02 + webPage03 + webPage99;
server.send(200, "text/html", webPage);
Serial.println("sent new page");
delay(2000);
}
// Function to get the data from the web form
void handleForm() {
showPage();
String formText = server.arg("getText");
if (formText.length() >= 150) {
formText = formText.substring(0, 149);
}
// Check for short/long etc. command, or just new text.
if (formText == ">>Short") {
displayType = 1;
demoMode = 0;
} else if (formText == ">>Long") {
displayType = 2;
demoMode = 0;
} else if (formText == ">>Rand") {
displayType = 3;
demoMode = 0;
} else if (formText == ">>Time") {
displayType = 4;
} else if (formText == ">>Mods") {
displayType = 5;
demoMode = 0;
} else {
inputText = formText;
demoMode = 0;
}
Serial.println("Text received. Contents: ");
Serial.println(formText);
Serial.println(inputText);
//delay(2);
}
// Function to get the current Unix time from an NTP server
void getNTPTime() {
//get a random server from the pool
WiFi.hostByName(ntpServerName, timeServerIP);
// send an NTP packet to a time server
sendNTPpacket(timeServerIP);
// wait to see if a reply is available
delay(1000);
int cb = udp.parsePacket();
if (!cb) {
Serial.println("no packet yet");
} else {
Serial.println("Time packet received.");
// We've received a packet, read the data from
it into the buffer
udp.read(packetBuffer, NTP_PACKET_SIZE);
// The timestamp starts at byte 40 of the
received packet and is four bytes,
// or two words, long. Extract 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;
// Convert NTP time into a Unix timestamp:
Serial.print("NTP time = ");
// Unix time starts on Jan 1 1970. In seconds,
that's 2208988800:
const unsigned long seventyYears =
2208988800UL;
// subtract seventy years and save as Unix
time. Then convert to PST
unixTime = time_t(secsSince1900 -
seventyYears);
unixTime = unixTime - 3600 * 8;
unixTimeNTP = unixTime;
Serial.println(displayUnixTime(unixTime));
}
}
// Function to send an NTP request to the time server at the given
address
void sendNTPpacket(IPAddress & address) {
Serial.println("sending NTP packet to: ");
Serial.println(address);
// 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)
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
// [4] - [11] are 8 bytes of zero for Root Delay & Root
Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now
// you can send a packet to port 123 requesting a
timestamp:
udp.beginPacket(address, 123);
udp.write(packetBuffer, NTP_PACKET_SIZE);
udp.endPacket();
}
// Function to return a formatted date and time String.
String displayUnixTime(time_t t) {
struct tm *mytime;
mytime = localtime(&t);
int year = mytime->tm_year + 1900;
int month = mytime->tm_mon + 1;
char stringBuf[20];
sprintf(stringBuf, "%4d/%02d/%02d\n%02d:%02d:%02d", year,
month, mytime->tm_mday, mytime->tm_hour, mytime->tm_min,
mytime->tm_sec);
return stringBuf;
}
// Ticker interrupt routine to count seconds
void countSeconds() {
unixTime++;
Serial.println (displayUnixTime(unixTime));
}
// Ticker interrupt routine to set request to get NTP time.
void setGetNTPTime() {
timeToGetNTPtime = true;
}
// ------------------------------------------------------------
// Oled display functions
// Set up the display function lists
Demo longDemos[] = {drawImageDemo, drawImageDemo1, drawTempVolt,
drawTimeDemo, drawFontFaceDemo, drawTextFlowDemo, drawMurphy,
drawTextAlignmentDemo, drawRectDemo, drawCircleDemo,
drawProgressBarDemo};
Demo shortDemos[] = {drawTempVolt, drawTextFlowDemo};
Demo randDemos[] = {drawTempVolt, drawMurphy};
Demo timeDemos[] = {drawImageDemo, drawTempVolt, drawTimeDemo};
Demo modsDemos[] = {drawImageDemo1, drawTempVolt, drawMurphy,
drawTextFlowDemo, drawTimeDemo};
int longDemoLength = (sizeof(longDemos) / sizeof(Demo));
int shortDemoLength = (sizeof(shortDemos) / sizeof(Demo));
int randDemoLength = (sizeof(randDemos) / sizeof(Demo));
int timeDemoLength = (sizeof(timeDemos) / sizeof(Demo));
int modsDemoLength = (sizeof(modsDemos) / sizeof(Demo));
//Get and display a murphy saying
void drawMurphy() {
HTTPClient http;
http.begin("http://drsol.com/~deid/murphy/murphy.php");
int stat = http.GET();
if (stat > 0) {
String text = http.getString();
delayNow = 10;
display.setFont(ArialMT_Plain_10);
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.drawStringMaxWidth(0, 0, 128, text);
} else {
display.setFont(ArialMT_Plain_16);
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.drawStringMaxWidth(0, 0, 128, "Oops -
No Web!");
}
http.end();
}
// Display temperature and voltage.
void drawTempVolt() {
delayNow = 3;
float tempC;
int battVolt;
//float tempF;
// Loop until the temperature is not out of range
do {
DS18B20.requestTemperatures();
tempC = DS18B20.getTempCByIndex(0);
delay(1000);
} while (tempC == (-127.0));
tempC = tempC + 1;
dtostrf(tempC, 6, 2, temperatureCString);
// tempF = DS18B20.getTempFByIndex(0);
// dtostrf(tempF, 6, 2, temperatureFString)
String t = temperatureCString;
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.setFont(ArialMT_Plain_16);
display.drawString(0, 0, t + " C");
int voltage = analogRead(A0);
float v = voltage / 65536.0 * 3.3;
display.drawString(16, 18, String(v) + " V");
}
// Display different font sizes
void drawFontFaceDemo() {
delayNow = 5;
// create more fonts at http://oleddisplay.squix.ch/
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.setFont(ArialMT_Plain_10);
display.drawString(0, 0, "Hello PiMakers");
display.setFont(ArialMT_Plain_16);
display.drawString(0, 10, "Hello World");
display.setFont(ArialMT_Plain_24);
display.drawString(0, 26, "Nice Day!");
}
// Display the text retrieved from the "web"
void drawTextFlowDemo() {
delayNow = 9;
display.setFont(ArialMT_Plain_10);
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.drawStringMaxWidth(0, 0, 128, inputText);
}
// Display text in different horizontal alignments
void drawTextAlignmentDemo() {
delayNow = 5;
// Text alignment demo
display.setFont(ArialMT_Plain_10);
// The coordinates define the left starting point of the
text
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.drawString(0, 10, "Left aligned (0,10)");
// The coordinates define the center of the text
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(64, 22, "Center aligned (64,22)");
// The coordinates define the right end of the text
display.setTextAlignment(TEXT_ALIGN_RIGHT);
display.drawString(128, 33, "Right aligned (128,33)");
}
// Display drawing on the screen - a rectangle.
void drawRectDemo() {
delayNow = 5;
// Draw a pixel at given position
for (int i = 0; i < 10; i++) {
display.setPixel(i, i);
display.setPixel(10 - i, i);
}
display.drawRect(12, 12, 20, 20);
// Fill the rectangle
display.fillRect(14, 14, 17, 17);
// Draw a line horizontally
display.drawHorizontalLine(0, 40, 20);
// Draw a line vertically
display.drawVerticalLine(40, 0, 20);
}
// Display a couple of circles.
void drawCircleDemo() {
delayNow = 5;
for (int i = 1; i < 8; i++) {
display.setColor(WHITE);
display.drawCircle(32, 32, i * 3);
if (i % 2 == 0) {
display.setColor(BLACK);
}
display.fillCircle(96, 32, 32 - i * 3);
}
}
// Display a progress bar
void drawProgressBarDemo() {
int counter = 1;
int progress;
delayNow = 0;
while (counter < 100) {
display.clear();
progress = (counter) % 100;
// draw the progress bar
display.drawProgressBar(0, 32, 120, 10,
progress);
// draw the percentage as String
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(64, 15, String(progress) +
"%");
display.display();
// Count for the progress bar
counter++;
delay(60);
}
}
// Display images.
// Raspberry
void drawImageDemo() {
delayNow = 3;
// see
http://blog.squix.org/2015/05/esp8266-nodemcu-how-to-create-xbm.html
// on how to create xbm files
// display.drawXbm(34, 14, WiFi_Logo_width,
WiFi_Logo_height, WiFi_Logo_bits);
display.drawXbm(17, 0, noobs_width, noobs_height,
noobs_bits);
}
// Peanut
void drawImageDemo1() {
delayNow = 3;
display.drawXbm(20, 0, peanut_width, peanut_height,
peanut_bits);
}
// Display the date and time
void drawTimeDemo() {
//display.clear();
delayNow = 3;
display.setFont(ArialMT_Plain_16);
display.setTextAlignment(TEXT_ALIGN_LEFT);
// Display the current time
display.drawStringMaxWidth(0, 0, 128,
displayUnixTime(unixTime));
display.setFont(ArialMT_Plain_10);
// Display the time of the last NTP request in smaller text
at bottom.
display.drawStringMaxWidth(0, 52, 128,
displayUnixTime(unixTimeNTP));
Serial.println(displayUnixTime(unixTime));
}
// -----------------------------------------------------------
// Setup
void setup() {
// Reserve space for the web form input variable
inputText.reserve(150);
inputText = "Computer science is no more about computers
than astronomy is about telescopes.";
// Set up serial interface
Serial.begin(9600);
// Initialise the UI, this will init the display too.
display.init();
display.flipScreenVertically();
display.setFont(ArialMT_Plain_10);
delay(500);
// Connect to WiFi. Try each Access Point
below and give up if none.
WiFi.mode(WIFI_STA);
bool stat = false;
//bool stat = getIP ({0,0,0,0},{0,0,0,0},{0,0,0,0},
"Steele", "Piwehavelotsof.");
stat = getIP ({10, 10, 45, 10}, {10, 10, 45, 254}, {255,
255, 255, 0}, "Steele", "Bazbarfoo");
if (!stat) {
Serial.println("try makiki");
stat = getIP ({0, 0, 0, 0}, {0, 0, 0, 0}, {0,
0, 0, 0}, "Makiki", "foobarbaz");
} if (!stat) {
Serial.println("try lalala6");
stat = getIP ({192, 168, 78, 39}, {192, 168,
78, 1}, {255, 255, 255, 0}, "lalala6", "fibblefabblefoo");
} if (!stat) {
Serial.println("try lalala");
stat = getIP ({192, 168, 0, 39}, {192, 168, 0,
1}, {255, 255, 255, 0}, "lalala", "foofabblefibble");
}
if (!stat) {
// Continue without an an internet connection.
Serial.println("Continuing without IP");
display.clear();
display.drawString(0, 10, "No IP");
display.display();
delay(5000);
}
// Turn of the AP
WiFi.softAPdisconnect (true);
// Start the web server.
server.begin();
// Set up the responder for web requests.
server.on("/getForm", handleForm);
server.on("/", showPage);
server.onNotFound(showPage);
udp.begin(localPort);
Serial.print("Local port: ");
Serial.println(udp.localPort());
// Get the initial time.
getNTPTime();
Serial.println(unixTime);
Serial.println(displayUnixTime(unixTime));
// Start the timer interrupt routines
tick.attach(tickTime, countSeconds);
ntp.attach(ntpTime, setGetNTPTime);
}
//-----------------------------------
// Loop
void loop() {
// Get time from an NTP server if it is time to do that.
if (timeToGetNTPtime) {
getNTPTime();
timeToGetNTPtime = false;
}
// Create a display and show it it it is time to do
that.
if (millis() > (delayNow * 1000) + lastmillis) {
lastmillis = millis();
display.clear();
// Choose which set of displays to run one of.
if ( displayType == 1) {
shortDemos[demoMode]();
demoMode = (demoMode + 1) %
shortDemoLength;
} else if (displayType == 2) {
longDemos[demoMode]();
demoMode = (demoMode + 1) %
longDemoLength;
} else if (displayType == 3) {
randDemos[demoMode]();
demoMode = (demoMode + 1) %
randDemoLength;
} else if (displayType == 4) {
timeDemos[demoMode]();
demoMode = (demoMode + 1) %
timeDemoLength;
} else if (displayType == 5) {
modsDemos[demoMode]();
demoMode = (demoMode + 1) %
modsDemoLength;
}
display.setTextAlignment(TEXT_ALIGN_RIGHT);
display.display();
// Look for and handle a web request.
server.handleClient();
}
// Just in case there is someting else to do - like
watchdog timer.
yield();
}
/**
The MIT License (MIT)
Copyright (c) 2018 by ThingPulse, Daniel Eichhorn
Copyright (c) 2018 by Fabrice Weinberg
Permission is hereby granted, free of charge, to any
person obtaining a copy
of this software and associated documentation files
(the "Software"), to deal
in the Software without restriction, including
without limitation the rights
to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell
copies of the Software, and to permit persons to whom
the Software is
furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE
SOFTWARE.
ThingPulse invests considerable time and money to
develop these open source libraries.
Please support us by buying our products (and not the
clones) from
https://thingpulse.com
*/