/*
* Simple Meteobridge network display
* With a 2x 20 LCD on a PCF8574 I2C I/O expander and a ESP8266.
* Aart 06-2023
*/
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x38,20,2);
// The "standard" address for a PCF8574 LCD module seems to be 0x27.
// On the ESP8266: D1 = SCL, D2 = SDA. 4k7 pullups to 3,3 V.
const int ON_Board_LED = 2;
const int BUTTON_PIN = 0; // Pin D3 on a Wemos D1 clone.
const char* ssid = "Wifi_SSID";
const char* password = "Wifi_PASSWORD";
const char* host = "http://meteobridge_user:meteobridge_password@meteobridge_ip/";
// i.e. http://meteobridge:password@192.168.178.30/
const uint32_t UPDATE_INTERVAL = 10000;
String GetAddress, LinkGet, getData;
HTTPClient http;
WiFiClient client;
// Separates a string into substrings using a separator character.
String getValue(String data, char separator, int index)
{
int found = 0;
int strIndex[] = {
0, -1 };
int maxIndex = data.length()-1;
for(int i=0; i<=maxIndex && found<=index; i++){
if(data.charAt(i)==separator || i==maxIndex){
found++;
strIndex[0] = strIndex[1]+1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}
void connectWiFi() {
Serial.print("Connecting");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
digitalWrite(ON_Board_LED, LOW);
delay(250);
digitalWrite(ON_Board_LED, HIGH);
delay(250);
}
digitalWrite(ON_Board_LED, HIGH);
Serial.println("");
Serial.print("Successfully connected to : ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
}
String getMeteoData(void) {
if (WiFi.status() != WL_CONNECTED) {
connectWiFi();
}
Serial.println("----------------Connect to Server-----------------");
Serial.print("Request Link : ");
Serial.println(LinkGet);
HTTPClient http;
http.begin(client, LinkGet);
http.addHeader("Content-Type", "text/plain");
int httpCodeGet = http.GET();
String payloadGet = http.getString();
Serial.print("Response Code : ");
Serial.println(httpCodeGet);
Serial.println("Returned data from Server : ");
Serial.println(payloadGet);
Serial.println("----------------Closing Connection----------------");
http.end();
return (payloadGet);
}
void setup() {
lcd.init();
lcd.backlight();
lcd.setCursor(1,0);
lcd.print("MeteobridgeDisplay");
lcd.setCursor(6,1);
lcd.print("Aart 2023");
Serial.begin(115200);
delay(500);
GetAddress = "cgi-bin/livedata.cgi";
LinkGet = host + GetAddress;
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
pinMode(ON_Board_LED, OUTPUT);
digitalWrite(ON_Board_LED, HIGH);
pinMode(BUTTON_PIN, INPUT);
}
void displayLegend() {
lcd.clear();
lcd.setCursor(0,0);
lcd.print("TEMP");
lcd.setCursor(0,1);
lcd.print("HUMI");
lcd.setCursor(5,0);
lcd.print("WIND");
lcd.setCursor(5,1);
lcd.print("DIR.");
lcd.setCursor(10,0);
lcd.print("RAIN");
lcd.setCursor(10,1);
lcd.print("RATE");
lcd.setCursor(15,0);
lcd.print("SUN");
lcd.setCursor(15,1);
lcd.print("BARO");
}
void DisplayMeteo(String data) {
lcd.clear();
lcd.setCursor(0,0);
lcd.print(getValue(data,' ', 2)); // TEMP
lcd.setCursor(0,1);
lcd.print(getValue(data,' ', 3)); // HUMI
lcd.setCursor(5,0);
lcd.print(getValue(data,' ', 12)); // WIND
lcd.setCursor(4,1);
lcd.print(getValue(data,' ', 10)); // DIR.
lcd.setCursor(10,0);
lcd.print(getValue(data,' ', 17)); // RAIN
lcd.setCursor(9,1);
lcd.print(getValue(data,' ', 16)); // RATE.
lcd.setCursor(16,0);
lcd.print(getValue(data,' ', 7)); // SUN
lcd.setCursor(14,1);
lcd.print(getValue(data,' ', 25)); // BARO
}
void loop() {
static String meteoData;
static int state = 0, lastState = 0, lamp = 1;
static uint32_t lastbutton, lastUpdate;
enum state {START, WAIT, DB_DOWN, DOWN, DB_UP, UP};
// States of button state machine. DB = DeBounce.
uint8_t button = digitalRead(BUTTON_PIN);
// debug
if (lastState != state) {
lastState = state;
Serial.print("New button state: "); Serial.println(state);
}
switch (state) {
case START:
meteoData = getMeteoData();
DisplayMeteo(meteoData);
state = WAIT;
break;
case WAIT:
if (button == LOW) {
lastbutton = millis();
state = DB_DOWN;
}
if (millis() - lastUpdate > UPDATE_INTERVAL ) {
meteoData = getMeteoData();
lastUpdate = millis();
DisplayMeteo(meteoData);
}
break;
case DB_DOWN:
if (millis() - lastbutton > 100) {
state = DOWN;
displayLegend();
lamp = !lamp;
if (lamp) lcd.backlight(); else lcd.noBacklight();
}
else if (button == HIGH) state = WAIT;
break;
case DOWN:
if (button == HIGH) {
lastbutton = millis();
state = DB_UP;
}
break;
case DB_UP:
if (millis() - lastbutton > 100) state = UP;
else if (button == LOW) state = DOWN;
break;
case UP:
DisplayMeteo(meteoData);
state = WAIT;
break;
}
}