2018-05-07 23:01:41 +03:00
# include <ESP8266WiFi.h>
# include <WiFiClient.h>
2018-05-08 12:50:12 +03:00
# include <ESP8266WebServer.h>
2018-05-07 23:01:41 +03:00
# include <ESP8266mDNS.h>
# include <NTPClient.h>
# include <WiFiUdp.h>
# include "SSD1306Brzo.h"
2018-05-08 12:50:12 +03:00
# include <ArduinoJson.h>
# include <FS.h>
# include "wifi.h" //not working :/
2018-05-07 23:01:41 +03:00
# include "Adafruit_MQTT.h"
# include "Adafruit_MQTT_Client.h"
double inTemp , outTemp , pressure , humid ;
2018-05-08 12:50:12 +03:00
unsigned short int onTime = 5 , offTime = 23 , beepDelay = 60 , lastNtp , lastBeep ;
2018-05-07 23:01:41 +03:00
bool mqttAvail ;
WiFiUDP ntpUDP ;
NTPClient timeClient ( ntpUDP ) ;
SSD1306Brzo display ( 0x3C , 4 , 5 ) ; //oled display w/ address 0x3C with SDA on GPIO4 and SCL on GPIO5 //address == offset
2018-05-08 12:48:25 +03:00
2018-05-07 23:01:41 +03:00
WiFiClient client ;
2018-05-08 12:50:12 +03:00
ESP8266WebServer server ( 80 ) ;
2018-05-07 23:01:41 +03:00
Adafruit_MQTT_Client mqtt ( & client , " 192.168.100.102 " , 1883 ) ;
Adafruit_MQTT_Subscribe pressureFeed = Adafruit_MQTT_Subscribe ( & mqtt , " pressure " ) ;
Adafruit_MQTT_Subscribe inFeed = Adafruit_MQTT_Subscribe ( & mqtt , " bmpTemp " ) ;
Adafruit_MQTT_Subscribe outFeed = Adafruit_MQTT_Subscribe ( & mqtt , " externalTemp " ) ;
Adafruit_MQTT_Subscribe humidFeed = Adafruit_MQTT_Subscribe ( & mqtt , " humid " ) ;
void wifiConnect ( ) {
int beginMillis = millis ( ) ;
WiFi . begin ( ssid , password ) ;
while ( WiFi . status ( ) ! = WL_CONNECTED & & millis ( ) - beginMillis < 30000 ) {
delay ( 250 ) ;
displayStatus ( 1 ) ;
Serial . print ( " . " ) ;
}
if ( WiFi . status ( ) ! = WL_CONNECTED ) {
displayStatus ( 2 ) ;
delay ( 10000 ) ;
ESP . reset ( ) ;
}
MDNS . begin ( " esp8266-frontend " ) ;
2018-05-08 12:50:12 +03:00
Serial . print ( " Connected to " + String ( ssid ) + " ; IP address: " ) ;
Serial . println ( WiFi . localIP ( ) ) ;
2018-05-07 23:01:41 +03:00
displayStatus ( 0 ) ;
}
void setup ( ) {
Serial . begin ( 115200 ) ;
//==DISPLAY INIT==
display . init ( ) ;
display . flipScreenVertically ( ) ;
display . setContrast ( 255 ) ;
//==WIFI CONNECT==
WiFi . mode ( WIFI_STA ) ;
wifiConnect ( ) ;
//==READ CONFIG==
2018-05-08 12:50:12 +03:00
if ( ! SPIFFS . begin ( ) )
SPIFFS . format ( ) ;
if ( ! readConfig ( ) )
defConfig ( ) ;
2018-05-07 23:01:41 +03:00
//==NTP INIT==
timeClient . begin ( ) ;
timeClient . setTimeOffset ( 10800 ) ;
//MQTT
pressureFeed . setCallback ( pressureCall ) ;
inFeed . setCallback ( inCall ) ;
outFeed . setCallback ( outCall ) ;
humidFeed . setCallback ( humidCall ) ;
mqtt . subscribe ( & pressureFeed ) ;
mqtt . subscribe ( & outFeed ) ;
mqtt . subscribe ( & inFeed ) ;
mqtt . subscribe ( & humidFeed ) ;
2018-05-08 12:50:12 +03:00
server . on ( " /edit " , editConfig ) ;
2018-05-07 23:01:41 +03:00
}
void loop ( ) {
2018-05-08 12:50:12 +03:00
if ( WiFi . status ( ) ! = WL_CONNECTED ) { //check wifi status
2018-05-07 23:01:41 +03:00
wifiConnect ( ) ;
}
2018-05-08 12:50:12 +03:00
server . handleClient ( ) ;
MQTT_connect ( ) ; //check connection and get packets for 0.5s
2018-05-07 23:01:41 +03:00
mqtt . processPackets ( 500 ) ;
2018-05-08 12:50:12 +03:00
2018-05-07 23:13:41 +03:00
mainScreen ( ) ; //it could be cool and smooth if we could update screen independently, in some kind of separate thread or smthn similar
2018-05-08 12:50:12 +03:00
// if (timeClient.getMinutes() == 0 && timeClient.getSeconds() < 5 && !nightMode() && lastBeep != timeClient.getHours()) {
if ( ( timeClient . getHours ( ) * 60 + timeClient . getMinutes ( ) - lastBeep > beepDelay ) & & ( ! nightMode ( ) ) ) { //beep every $lastBeep
2018-05-07 23:01:41 +03:00
tone ( 15 , 1000 ) ;
delay ( 100 ) ;
noTone ( 15 ) ;
2018-05-08 12:50:12 +03:00
lastBeep = timeClient . getHours ( ) * 60 + timeClient . getMinutes ( ) ;
2018-05-07 23:01:41 +03:00
}
2018-05-08 12:50:12 +03:00
updateNtp ( ) ; //update time
2018-05-07 23:01:41 +03:00
}
//TODO
//AT LEAST MAKE IT WORK (show ui and get data + ntp) - compiling - ... - WORKS!!11
//debug -> release
//remove useless serial debug - DONE
//show wifi info on oled - DONE
//reset on not connected - DONE
//check connectivity during work and do actions - DONE
//beep hourly - DONE
2018-05-08 12:48:25 +03:00
//github - oh yeahhh
2018-05-08 12:50:12 +03:00
2018-05-07 23:01:41 +03:00
//load config
2018-05-08 12:50:12 +03:00
//webconfig (?) - in progress
2018-05-07 23:01:41 +03:00
//mqtt update interval
2018-05-08 12:50:12 +03:00
//second screen
//reconfig wifi if not found (start webserver and AP)
2018-05-07 23:01:41 +03:00
//GRAPH
/*
get json from server
~ 12 values
hourly values + hourly display
if pressure lowers then weather gonna be bad
if pressure uppers then weather gonna be good
*/
//CONFIG
/*
beep time
on time
off time
mqtt update interval
*/
//====================IN PROGRESS===================
2018-05-08 12:50:12 +03:00
void editConfig ( ) {
if ( server . args ( ) > 0 ) {
for ( uint8_t i = 0 ; i < server . args ( ) ; i + + ) {
String Argument_Name = server . argName ( i ) ;
String client_response = server . arg ( i ) ;
if ( Argument_Name = = " beepDelay " ) {
beepDelay = client_response . toInt ( ) ;
}
if ( Argument_Name = = " onTime " ) {
onTime = client_response . toInt ( ) ;
}
if ( Argument_Name = = " offTime " ) {
offTime = client_response . toInt ( ) ;
}
updateConfig ( ) ;
}
2018-05-07 23:01:41 +03:00
}
2018-05-08 12:50:12 +03:00
}
bool updateConfig ( ) {
StaticJsonBuffer < 200 > jsonBuffer ;
JsonObject & json = jsonBuffer . createObject ( ) ;
json [ " onTime " ] = onTime ;
json [ " offTime " ] = offTime ;
json [ " beepDelay " ] = beepDelay ;
File configFile = SPIFFS . open ( " /config.json " , " w " ) ;
if ( ! configFile ) {
Serial . println ( " Failed to open config file for writing " ) ;
return false ;
2018-05-07 23:01:41 +03:00
}
2018-05-08 12:50:12 +03:00
json . printTo ( configFile ) ;
return true ;
2018-05-07 23:01:41 +03:00
}
2018-05-08 12:50:12 +03:00
bool readConfig ( ) {
File configFile = SPIFFS . open ( " /config.json " , " r " ) ;
if ( ! configFile ) {
Serial . println ( " Failed to open config file " ) ;
return false ;
}
size_t size = configFile . size ( ) ;
if ( size > 1024 ) {
Serial . println ( " Config file size is too large " ) ;
return false ;
}
// Allocate a buffer to store contents of the file.
std : : unique_ptr < char [ ] > buf ( new char [ size ] ) ;
// We don't use String here because ArduinoJson library requires the input buffer to be mutable. If you don't use ArduinoJson, you may as well use configFile.readString instead.
configFile . readBytes ( buf . get ( ) , size ) ;
StaticJsonBuffer < 200 > jsonBuffer ;
JsonObject & json = jsonBuffer . parseObject ( buf . get ( ) ) ;
if ( ! json . success ( ) ) {
Serial . println ( " Failed to parse config file " ) ;
return false ;
}
offTime = int ( json [ " offTime " ] ) ;
onTime = int ( json [ " onTime " ] ) ;
beepDelay = int ( json [ " beepDelay " ] ) ;
return true ;
2018-05-07 23:01:41 +03:00
2018-05-08 12:50:12 +03:00
}
bool defConfig ( ) {
StaticJsonBuffer < 200 > jsonBuffer ;
JsonObject & json = jsonBuffer . createObject ( ) ;
json [ " onTime " ] = " 6 " ;
json [ " offTime " ] = " 23 " ;
json [ " beepDelay " ] = " 60 " ;
File configFile = SPIFFS . open ( " /config.json " , " w " ) ;
if ( ! configFile ) {
Serial . println ( " Failed to open config file for writing " ) ;
return false ;
2018-05-07 23:01:41 +03:00
}
2018-05-08 12:50:12 +03:00
json . printTo ( configFile ) ;
return true ;
2018-05-07 23:01:41 +03:00
}
2018-05-08 12:50:12 +03:00
//====================paused===================
2018-05-07 23:01:41 +03:00
// void secondDisplay() {
// display.clear();
// display.setFont(ArialMT_Plain_16);
// display.setTextAlignment(TEXT_ALIGN_CENTER);
// display.drawString(0, 30, timeClient.getFormattedTime());
// display.drawRect(0,18,128,53); //frame
// /*
// 128/12=10px
// 128x32 resolution
// 32-19=13px for graph
// */
// int x = 0;
// for (int i=0;i<12;++i){
// display.drawLine(x+i*10, y[x], x+i*10+10, y[x]);
// }
// }
2018-05-08 12:50:12 +03:00
//===================WELL DONE=======================
void mainScreen ( ) {
display . clear ( ) ;
2018-05-07 23:01:41 +03:00
2018-05-08 12:50:12 +03:00
if ( ! nightMode ( ) ) { //turn off screen at night
int x = ( timeClient . getHours ( ) * 60 + timeClient . getMinutes ( ) ) / 11 ;
//Time
display . setFont ( ArialMT_Plain_24 ) ;
display . setTextAlignment ( TEXT_ALIGN_CENTER ) ;
display . drawString ( 64 , 22 , timeClient . getFormattedTime ( ) ) ;
//progress bar
display . drawLine ( 0 , 22 , x , 22 ) ;
if ( mqttAvail ) { //do not show info if mqtt not available
//external temp //top left
display . setFont ( ArialMT_Plain_10 ) ;
display . setTextAlignment ( TEXT_ALIGN_LEFT ) ;
display . drawString ( 0 , 0 , " o: " + String ( outTemp ) ) ;
//pressure //top right
display . setFont ( ArialMT_Plain_10 ) ;
display . setTextAlignment ( TEXT_ALIGN_RIGHT ) ;
display . drawString ( 128 , 0 , " p: " + String ( pressure ) ) ;
//inside temp //bottom left
display . setFont ( ArialMT_Plain_10 ) ;
display . setTextAlignment ( TEXT_ALIGN_LEFT ) ;
display . drawString ( 0 , 53 , " i: " + String ( inTemp ) ) ;
//humid //bottom right
display . setFont ( ArialMT_Plain_10 ) ;
display . setTextAlignment ( TEXT_ALIGN_RIGHT ) ;
display . drawString ( 128 , 53 , " h: " + String ( humid ) + " % " ) ;
}
else {
display . setFont ( ArialMT_Plain_10 ) ;
display . setTextAlignment ( TEXT_ALIGN_LEFT ) ;
display . drawString ( 0 , 53 , " mqtt unavailable " ) ;
}
}
display . display ( ) ;
}
2018-05-07 23:01:41 +03:00
2018-05-08 12:50:12 +03:00
void displayStatus ( int state ) {
display . clear ( ) ;
if ( state = = 0 ) {
display . setFont ( ArialMT_Plain_16 ) ;
display . setTextAlignment ( TEXT_ALIGN_CENTER ) ;
display . drawString ( 64 , 22 , " Connected! " ) ;
}
if ( state = = 1 ) {
display . setFont ( ArialMT_Plain_16 ) ;
display . setTextAlignment ( TEXT_ALIGN_CENTER ) ;
display . drawString ( 64 , 22 , " Connecting... " ) ;
}
if ( state = = 2 ) {
display . setFont ( ArialMT_Plain_16 ) ;
display . setTextAlignment ( TEXT_ALIGN_CENTER ) ;
display . drawString ( 64 , 22 , " Not connected! " ) ;
display . setFont ( ArialMT_Plain_10 ) ;
display . setTextAlignment ( TEXT_ALIGN_LEFT ) ;
display . drawString ( 0 , 53 , " we will die in 10s! :0 " ) ;
}
display . display ( ) ;
}
2018-05-07 23:01:41 +03:00
void MQTT_connect ( ) {
if ( mqtt . connected ( ) ) {
return ;
}
2018-05-08 12:50:12 +03:00
int8_t ret ;
2018-05-07 23:01:41 +03:00
uint8_t retries = 3 ;
2018-05-08 12:50:12 +03:00
while ( ( ret = mqtt . connect ( ) ) ! = 0 ) {
displayStatus ( 3 ) ;
mqtt . disconnect ( ) ;
delay ( 5000 ) ;
retries - - ;
if ( retries = = 0 ) {
mqttAvail = false ;
}
2018-05-07 23:01:41 +03:00
}
2018-05-08 12:50:12 +03:00
if ( mqtt . connected ( ) )
mqttAvail = true ;
2018-05-07 23:01:41 +03:00
}
void pressureCall ( double x ) {
pressure = x ;
}
void inCall ( double x ) {
inTemp = x ;
}
void outCall ( double x ) {
outTemp = x ;
}
void humidCall ( double x ) {
humid = x ;
}
void updateNtp ( ) {
if ( lastNtp ! = timeClient . getHours ( ) ) {
2018-05-08 12:50:12 +03:00
if ( timeClient . update ( ) )
lastNtp = timeClient . getHours ( ) ;
2018-05-07 23:01:41 +03:00
}
}
bool nightMode ( ) {
if ( ( timeClient . getHours ( ) > offTime ) | | ( timeClient . getHours ( ) < onTime ) ) { //turn off screen between loaded time
return true ;
}
else
return false ;
}