Weather Station
Weather Station
* Board : NodeMCU V3
* Sensor DHT11
* Thingspeak
* Status LED on D4
* Connections:
* DHT11 -- Pin D5
* SDA -- Pin D2
* SDA -- Pin D2
* LED -- Pin D4
****************************************/
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <DNSServer.h>
#include <WiFiManager.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <ArduinoJson.h>
#include <EEPROM.h>
#define LED_PIN D4
struct Config {
char ssid[32];
char password[32];
char apiKey[32];
int updateInterval;
bool ledEnabled;
};
Config config;
Adafruit_BMP280 bmp;
WiFiClient client;
ESP8266WebServer server(80);
WiFiManager wifiManager;
int lcdPage = 0;
<!DOCTYPE html>
<html>
<head>
<style>
body {font-family: Arial, Helvetica, sans-serif; margin: 0; padding: 20px; background-color: #f0f8ff;}
.container {max-width: 500px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);}
.btn {background-color: #0077cc; color: white; padding: 10px 15px; border: none; border-radius: 4px;
cursor: pointer; width: 100%;}
.slider:before {position: absolute; content: ""; height: 26px; width: 26px; left: 4px; bottom: 4px;
background-color: white; transition: .4s; border-radius: 50%;}
</style>
</head>
<body>
<div class="container">
<h1>Weather Station</h1>
<div class="status">
<div class="status-item">
</div>
<div class="status-item">
</div>
<div class="status-item">
</div>
<div class="status-item">
<span class="status-label">ThingSpeak:</span>
</div>
</div>
<div class="form-group">
</div>
<div class="form-group">
</div>
<div class="form-group">
</div>
<div class="form-group">
</div>
<div class="form-group">
<label>LED Indicator:</label>
<label class="switch">
<span class="slider"></span>
</label>
</div>
</form>
</div>
</body>
</html>
)rawliteral";
void loadConfig() {
EEPROM.begin(CONFIG_SIZE);
EEPROM.get(0, config);
EEPROM.end();
void saveConfig() {
EEPROM.begin(CONFIG_SIZE);
EEPROM.put(0, config);
EEPROM.commit();
EEPROM.end();
}
// LED functions
digitalWrite(LED_PIN, HIGH);
delay(delayMs);
digitalWrite(LED_PIN, LOW);
void flashLED() {
if (config.ledEnabled) {
digitalWrite(LED_PIN, HIGH);
ledState = true;
void updateLCD() {
lcdPage = (lcdPage + 1) % 2;
lcdPageChangeTime = currentTime;
lcd.clear();
if (lcdPage == 0) {
lcd.setCursor(0, 0);
lcd.print("T:");
lcd.print(temperature, 1);
lcd.print("C ");
lcd.setCursor(8, 0);
lcd.print("P:");
lcd.print(pressure, 0);
lcd.print("hPa");
lcd.setCursor(0, 1);
lcd.print("H:");
lcd.print(dht.readHumidity(), 0);
lcd.print("%");
lcd.setCursor(8, 1);
lcd.print("WiFi:");
lcd.print(WiFi.RSSI());
} else {
lcd.setCursor(0, 0);
lcd.print("Alt:");
lcd.print(altitude, 1);
lcd.print("m");
lcd.setCursor(0, 1);
lcd.print("");
lcd.print(WiFi.localIP().toString());
void updateThingSpeak() {
if (client.connect(thingspeak_server, 80)) {
postStr += "&field1=";
postStr += String(temperature);
postStr += "&field2=";
postStr += String(pressure);
postStr += "&field3=";
postStr += String(altitude);
postStr += "&field4=";
postStr += String(humidity);
postStr += "\r\n\r\n";
client.print("Host: api.thingspeak.com\n");
client.print("Connection: close\n");
client.print("Content-Type: application/x-www-form-urlencoded\n");
client.print("Content-Length: ");
client.print(postStr.length());
client.print("\r\n\r\n");
client.print(postStr);
client.stop();
lastUpdateTime = millis();
return String();
}
result.replace("%SSID%", String(config.ssid));
result.replace("%PASSWORD%", String(config.password));
result.replace("%API_KEY%", String(config.apiKey));
result.replace("%INTERVAL%", String(config.updateInterval));
return result;
void handleRoot() {
if (server.hasArg("ssid")) {
server.arg("ssid").toCharArray(config.ssid, sizeof(config.ssid));
if (server.hasArg("password")) {
server.arg("password").toCharArray(config.password, sizeof(config.password));
if (server.hasArg("apiKey")) {
server.arg("apiKey").toCharArray(config.apiKey, sizeof(config.apiKey));
if (server.hasArg("interval")) {
config.updateInterval = server.arg("interval").toInt();
config.ledEnabled = server.hasArg("ledEnabled");
saveConfig();
server.sendHeader("Location", "/");
server.send(303);
if (WiFi.getMode() == WIFI_STA) {
WiFi.disconnect();
delay(1000);
WiFi.begin(config.ssid, config.password);
// Setup function
void setup() {
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
// Initialize LCD
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.setCursor(0, 1);
lcd.print("Initializing...");
EEPROM.begin(CONFIG_SIZE);
loadConfig();
// Initialize sensors
delay(100);
sensorBMP280_OK = bmp.begin(0x76);
if (!sensorBMP280_OK) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("BMP280 Error!");
blinkLED(3, 300);
dht.begin();
float h = dht.readHumidity();
sensorDHT11_OK = !isnan(h);
if (!sensorDHT11_OK) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("DHT11 Error!");
blinkLED(3, 300);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Connecting WiFi");
WiFi.mode(WIFI_STA);
WiFi.begin(config.ssid, config.password);
int timeout = 0;
delay(500);
lcd.print(".");
timeout++;
}
// If WiFi connection fails, start AP mode with captive portal
if (WiFi.status() != WL_CONNECTED) {
WiFi.mode(WIFI_AP);
WiFi.softAP(AP_NAME);
lcd.clear();
lcd.setCursor(0, 0);
lcd.setCursor(0, 1);
lcd.print("SSID: ");
lcd.print(AP_NAME);
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("WiFi Connected!");
lcd.setCursor(0, 1);
lcd.print(WiFi.localIP().toString());
delay(2000);
server.on("/", handleRoot);
server.begin();
}
// Main loop
void loop() {
server.handleClient();
digitalWrite(LED_PIN, LOW);
ledState = false;
updateLCD();
lastLcdUpdate = millis();
updateThingSpeak();