Skip to content

Instantly share code, notes, and snippets.

@inthuriel
Created May 29, 2022 15:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save inthuriel/f9104d18e6bd9f5bd003dfb9513e91d3 to your computer and use it in GitHub Desktop.
Save inthuriel/f9104d18e6bd9f5bd003dfb9513e91d3 to your computer and use it in GitHub Desktop.
// required liblaries
#include <LiquidCrystal_I2C.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <Adafruit_BME280.h>
#include <RTClib.h>
#include <uptime_formatter.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <Timezone.h>
// predefined constants
const char* SSID = "";
const char* WIFI_PASSWORD = "";
const float SEALEVELPRESSURE_HPA = 1013.25;
const unsigned int CLOCK_INTERVAL = 1000;
const unsigned int SENSOR_INTERVAL = 60000;
const unsigned int NTP_INTERVAL = 3600000;
const unsigned int REST_PORT = 80;
// predefined vars
unsigned int display_opt = 0;
unsigned long clock_time = 0;
unsigned long sensor_time = 0;
unsigned long ntp_time = 0;
String hostname = "weather-station-" + String(ESP.getChipId(), HEX);
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120};
TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60};
float pressure;
float humidity;
float temperature;
// create timezone object based on predefined rules for Central Europe
Timezone central_europe_tz(CEST, CET);
// initialize LCD via I2C bus
LiquidCrystal_I2C lcd(0x27, 16, 2);
// initialize thermometer via I2C bus
Adafruit_BME280 bme;
// initialize RTC via I2C bus
RTC_DS3231 rtc;
// initialize web server
ESP8266WebServer http_server(REST_PORT);
// initialize UDP WiFi instance
WiFiUDP ntpUDP;
// initialize NTP client via UDP
NTPClient ntp_client(ntpUDP, "europe.pool.ntp.org");
// functions headers
void api_sensor_readings();
void api_device_status();
void api_base_info();
void api_not_found();
void basic_clock();
void extend_tmp();
void rest_server_routing();
int set_display_opt(int opt);
void short_tmp();
void update_time();
void setup() {
// initialize pin for button input
pinMode(13, INPUT);
// initialize LCD, set backlight and clear contents
lcd.init();
lcd.backlight();
lcd.clear();
// initialize WiFi connection and set device hostname
WiFi.begin(SSID, WIFI_PASSWORD);
WiFi.hostname(hostname);
// initialize sensor readings
bme.begin(0x76);
// initialize RTC device
rtc.begin();
// display user message about connecting to WiFi network
lcd.print("Connecting to ");
lcd.setCursor(0, 1);
lcd.print(SSID);
int i = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
}
// as we are connected to WiFi establish HTTP server
// and run NTP client with time update
rest_server_routing();
http_server.onNotFound(api_not_found);
http_server.begin();
ntp_client.begin();
update_time();
// display user message about initialization completion
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Initialized!");
lcd.setCursor(0, 1);
lcd.print("IP: ");
lcd.print(WiFi.localIP());
delay(1000);
// display default message for user
lcd.clear();
basic_clock();
short_tmp();
}
void loop () {
// display clock if proper option was choosen
// refres every interval defined in CLOCK_INTERVAL miliseconds
if(millis() >= clock_time + CLOCK_INTERVAL){
if (display_opt == 0) {
clock_time +=CLOCK_INTERVAL;
basic_clock();
}
}
// display sensor data if proper option was choosen
// refres every interval defined in SENSOR_INTERVAL miliseconds
if(millis() >= sensor_time + SENSOR_INTERVAL){
if (display_opt == 0) {
sensor_time +=SENSOR_INTERVAL;
short_tmp();
}
}
// display extended sensor data if proper option was choosen
// refres every interval defined in SENSOR_INTERVAL miliseconds
if(millis() >= sensor_time + SENSOR_INTERVAL){
if (display_opt == 1) {
sensor_time +=SENSOR_INTERVAL;
extend_tmp();
}
}
// update RTC time settings
// refres every interval defined in NTP_INTERVAL miliseconds
if(millis() >= ntp_time + NTP_INTERVAL){
ntp_time +=NTP_INTERVAL;
update_time();
}
// check if touch sensor was touched to change display informations
if (digitalRead(13) == HIGH) {
int old_display_opt = display_opt;
display_opt = set_display_opt(display_opt);
if (old_display_opt - display_opt < 0) {
lcd.clear();
basic_clock();
short_tmp();
} else {
lcd.clear();
extend_tmp();
}
}
// run HTTP server
http_server.handleClient();
}
int set_display_opt(int opt) {
opt +=1;
if (opt > 1) {
opt = 0;
}
return opt;
}
void update_time() {
ntp_client.update();
rtc.adjust(DateTime(central_europe_tz.toLocal(ntp_client.getEpochTime())));
}
void basic_clock() {
char formatted_date[16];
char sep;
DateTime now = rtc.now();
if (now.second() % 2 != 0) {
sep = ':';
} else {
sep = ' ';
}
sprintf(formatted_date, "%2d.%02d.%4d %2d%c%02d", now.day(),now.month(), now.year(), now.hour(), sep, now.minute());
lcd.setCursor(0, 0);
lcd.print(formatted_date);
}
void extend_tmp() {
char formatted_temp[16];
char formatted_hum[16];
temperature = bme.readTemperature();
pressure = bme.readPressure();
humidity = bme.readHumidity();
sprintf(formatted_temp, "%2.1f *C %4.0f hPa",temperature, round(pressure / 100.0F));
sprintf(formatted_hum, "%4.2f proc.",temperature, humidity);
lcd.setCursor(0, 0);
lcd.print(formatted_temp);
lcd.setCursor(0, 1);
lcd.print(formatted_hum);
}
void short_tmp() {
char formatted_temp[16];
temperature = bme.readTemperature();
pressure = bme.readPressure();
humidity = bme.readHumidity();
sprintf(formatted_temp, "%2.1f *C %4.0f hPa",temperature, round(pressure / 100.0F));
lcd.setCursor(0, 1);
lcd.print(formatted_temp);
}
void api_sensor_readings() {
char rest_response[128];
DateTime now = rtc.now();
int currenttimestamp = now.unixtime();
sprintf(rest_response, "{\"environment\":{\"temperature\": %f, \"humidity\": %f, \"pressure\": %f}, \"timestamp\": %d}", temperature, humidity, pressure, currenttimestamp);
http_server.send(200, "text/json", rest_response);
}
void api_device_status() {
char rest_response[1024];
DateTime now = rtc.now();
int currenttimestamp = now.unixtime();
String uptime = uptime_formatter::getUptime() + "";
String wifi_status;
if (WiFi.status() == WL_CONNECTED) {
wifi_status = "connected";
} else {
wifi_status = "disconnected";
}
sprintf(rest_response, "{\"status\":{\"wlan-status\": \"%s\", \"ssid\": \"%s\", \"hostname\":\"%s\", \"ip\": \"%s\", \"uptime\": \"%s\"}, \"timestamp\": %d}", wifi_status.c_str(), SSID, hostname.c_str(), WiFi.localIP().toString().c_str(), uptime.c_str(), currenttimestamp);
http_server.send(200, "text/json", rest_response);
}
void api_base_info() {
char rest_response[1024];
DateTime now = rtc.now();
int currenttimestamp = now.unixtime();
sprintf(rest_response, "{\"api\":{\"v1\": {\"endpoints\": [{\"name\": \"sensor readings\", \"path\": \"/api/v1/sensor\"}, {\"name\": \"device status\", \"path\": \"/api/v1/status\"}]}}, \"timestamp\": %d}", currenttimestamp);
http_server.send(200, "text/json", rest_response);
}
void api_not_found() {
char rest_response[1024];
DateTime now = rtc.now();
int currenttimestamp = now.unixtime();
sprintf(rest_response, "{\"message\": \"Endpoint %s not found\", \"type\": \"error\", \"code\": 404, \"timestamp\": %d}", http_server.uri(), currenttimestamp);
http_server.send(404, "text/json", rest_response);
}
void rest_server_routing() {
http_server.on(("/"), HTTP_GET, api_base_info);
http_server.on(("/api/v1/sensor"), HTTP_GET, api_sensor_readings);
http_server.on(("/api/v1/status"), HTTP_GET, api_device_status);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment