Arduino Weather Station
Ik heb een LED weerstation gemaakt met een ESP8266 arduino. Met de API van OpenWeatherMap wordt de weerdata opgehaald. Vervolgens wordt het huidige weer en temperatuur weergegeven door WS2812B LED'jes, die achter een vel doorzichtig papier zitten.
Met dit simpele weerstation kun je het de huidige weersituatie en temperatuur zien. Door een segmented display kunnen weerscenario's op 6 verschillende manieren worden weergegeven. De temperatuur wordt weergegeven door een aantal LED's op te lichten, in de vorm van een traditionele thermostaat.
Supplies
Onderdelen:
- ESP2866 Arduino met WiFi verbinding
- WS2812B LED's (50)
- Bedrading
- Micro-USB kabel
- Wifi of mobiele hotspot
Behuizing:
- Dun, buigbaar, bouwkarton
- Vel A4 papier
Gereedschap:
- Schaar
- Soldeerbout met tin
- Lijm
Design
Voor stap 1 was ik vooral gewoon aan het experimenteren met verschillende ideeen die ik had. Zoals bijvoorbeeld geluiden toevoegen, of alleen maar een kleur lamp hebben, zonder display. Verder had ik ook nog ideeen om bijvoorbeeld een klok er in te verwerken. Maar toen ik langs een oud weerstation kwam die ik ergens zag liggen, was ik geinteresseerd door het segmenten-display. Het leek mij leuk om dat na te maken. De foto hierboven toont een van mijn vroege designs; een lamp aan de binnenkant van een cilinder. Mijn idee was toen om de lamp voor elke weersituatie een andere kleur te geven, en daarnaast toepassende geluiden af te spelen. Het bleek snel dat het lastig was om zo duidelijk te maken wat voor weer wat was. Het uiteindelijke design was veel duidelijker.
Constructie
De behuizing van het weerstation is gemaakt van dun knutselkarton. De segmenten aan de binnenkant en de zijkanten zijn gemaakt van dikker karton. De segmenten zijn zo neergezet, dat er zeer weinig verschillende LED strips gebruikt hoeven te worden. Er zijn in totaal 50 lichtjes. Er zijn 12 segmenten. 3 verschillende voor de zon/wolken, en 9 voor de verschillende soorten neerslag/mist. Verder is er een groot verticaal stuk voor de thermostaat. Aan de achterkant is genoeg plek om de ESP2866 kwijt te krijgen.
Code
De code is redelijk ingewikkeld, en by far waar de meeste moeite voor dit project in gegaan is. De code werkt in verschillende stappen. Bovenaan worden verschillende variabelen gedefinieerd.
Daarna wordt data ingevuld voor de verbinding met WIFI. In dit geval is dit mijn persoonlijke hotspot op mijn telefoon. Daarna wordt de juiste data bij elkaar gehaald zodat de weerinformatie van OpenWeatherMap gehaald kan worden. (Dit deel van de code is grotendeels van https://randomnerdtutorials.com/esp32-http-get-open-weather-map-thingspeak-arduino/)
In de setup worden veel verschillende dingen gedaan. De LED's worden verbonden, de serial monitor wordt aangezet, en er wordt verbonden met de WiFi.
Daarna wordt de Json request om de minuut opgevraagd. Wanneer de Json binnen eerst, wordt eerst de temperatuur omgezet van Kelvin naar Celsius, en dan wordt de temperatuur getoond op de thermostaat-LED's.
Daaronder staan allemaal verschillende switch-cases, die elk voor verschilllende weersituaties gebruikt worden. Dankzij de manier waarop het geformuleerd is, (4 rijen van 3 maakt 12 segmenten) is het makkelijk om nieuwe scenario's toe te voegen. Daarna worden de LED's aangestuurd.
Hieronder zien we hoe dat zo mooi geformuleerd is, hier staat een enorme waslijst LED adressen die duidelijkere namen gegeven worden, en sommige worden permanent uitgezet omdat ze in de behuizing op een plek zitten waar ze niet te zien zijn.
Daaronder staat meer van de code van de website die hierboven ook gelinked staat. Ik heb geprobeerd om zelf deze code vanaf niks te schrijven, maar het werd mij aangeraden om toch code te gebruiken van iemand met meer ervaring.
#include <ESP8266WiFi.h> #include <ESP8266HTTPClient.h> #include <WiFiClient.h> #include <Arduino_JSON.h> #include <FastLED.h> #define LED_PIN 5 #define button_pin 13 #define ledSunStart 1 #define ledSunEnd 5 #define ledSun2Start 6 #define ledSun2End 9 #define ledCloudStart 10 #define ledCloudEnd 22 #define ledInd1 23 #define ledInd2 28 #define ledInd3 33 #define ledTempStart 34 #define ledTempEnd 50 #define NUM_LEDS 50 #define tempGrad 30 #define colorSun 0xf2bb13 #define colorCloud 0xffffff #define colorRain 0x0592f7 #define colorZap 0xf7ef05 #define colorOff 0x000000 CRGB leds[NUM_LEDS]; int mode = 1; int id; const char* ssid = "thegamer"; const char* password = "bananana"; // Your Domain name with URL path or IP address with path String openWeatherMapApiKey = "f3d03e8938ac1114d664bbb8a663ce2f"; // Example: //String openWeatherMapApiKey = "bd939aa3d23ff33d3c8f5dd1dd4"; // Replace with your country code and city String city = "Amersfoort"; String countryCode = "NL"; unsigned long lastTime = 0; unsigned long timerDelay = 60000; int tempTime = timerDelay; String jsonBuffer; void setup() { Serial.begin(115200); FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS); pinMode(13, INPUT_PULLUP); WiFi.begin(ssid, password); Serial.println("Connecting"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("Connected to WiFi network with IP Address: "); Serial.println(WiFi.localIP()); Serial.println("Timer set to 60 seconds (timerDelay variable), it will take 60 seconds before publishing the first reading."); } void loop() { // Send an HTTP GET request if ((millis() - lastTime + tempTime) > timerDelay) { tempTime = 0; // Check WiFi connection status if (WiFi.status() == WL_CONNECTED) { String serverPath = "http://api.openweathermap.org/data/2.5/weather?q=" + city + "," + countryCode + "&APPID=" + openWeatherMapApiKey; jsonBuffer = httpGETRequest(serverPath.c_str()); Serial.println(jsonBuffer); JSONVar myObject = JSON.parse(jsonBuffer); id = int(myObject["weather"][0]["id"]); float temp = double(myObject["main"]["temp"]); temp = temp - 273.15; int tempint = round(temp); fill_solid(&(leds[ledTempStart]), (temp+ledTempStart)/2, 0xc91b0e); mode = mode + 1; fill_solid(&(leds[0]), 50, 0xc91b0e); } else { Serial.println("WiFi Disconnected"); } switch (id) { case 701 ... 800: ledColor(colorSun, colorSun, colorOff, colorOff, colorOff, colorOff, colorOff, colorOff, colorOff, colorOff, colorOff, colorOff); break; case 801: ledColor(colorSun, colorCloud, colorCloud, colorOff, colorOff, colorOff, colorOff, colorOff, colorOff, colorOff, colorOff, colorOff); break; case 500 ... 622: ledColor(colorOff, colorCloud, colorCloud, colorRain, colorOff, colorRain, colorOff, colorOff, colorOff, colorRain, colorOff, colorRain); break; case 200 ... 232: ledColor(colorOff, colorCloud, colorCloud, colorRain, colorZap, colorRain, colorOff, colorZap, colorOff, colorRain, colorZap, colorRain); break; case 300 ... 321: ledColor(colorOff, colorCloud, colorCloud, colorOff, colorRain, colorOff, colorOff, colorOff, colorOff, colorOff, colorOff, colorOff); break; case 802 ... 805: ledColor(colorOff, colorCloud, colorCloud, colorOff, colorOff, colorOff, colorOff, colorOff, colorOff, colorOff, colorOff, colorOff); } lastTime = millis(); } FastLED.show(); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ledColor(uint32_t sun, uint32_t sun2, uint32_t cloud, uint32_t ind1a, uint32_t ind2a, uint32_t ind3a, uint32_t ind1b, uint32_t ind2b, uint32_t ind3b, uint32_t ind1c, uint32_t ind2c, uint32_t ind3c) { fill_solid(&(leds[ledSunStart]), ledSunEnd, sun); fill_solid(&(leds[ledSun2Start]), ledSun2End, sun2); fill_solid(&(leds[ledCloudStart]), ledCloudEnd, cloud); leds[ledInd1] = ind1a; leds[ledInd1+1] = ind2a; leds[ledInd1+2] = ind3a; leds[ledInd1+3] = colorOff; leds[ledInd1+4] = colorOff; leds[ledInd2] = ind1b; leds[ledInd2+1] = ind2b; leds[ledInd2+2] = ind3b; leds[ledInd2+3] = colorOff; leds[ledInd2+4] = colorOff; leds[ledInd3] = ind1c; leds[ledInd3+1] = ind2c; leds[ledInd3+2] = ind3c; } String httpGETRequest(const char* serverName) { WiFiClient client; HTTPClient http; // Your IP address with path or Domain name with URL path http.begin(client, serverName); // Send HTTP POST request int httpResponseCode = http.GET(); String payload = "{}"; if (httpResponseCode > 0) { Serial.print("HTTP Response code: "); Serial.println(httpResponseCode); payload = http.getString(); } else { Serial.print("Error code: "); Serial.println(httpResponseCode); } // Free resources http.end(); return payload; }
Conclusie
Ik heb veel geleerd met dit project. Ik heb geleerd hoe ik met API's en Json bestanden werk, maar ook hoe ik moet solderen. Dat vond ik het leukst en meest interessant aan dit project, hoeveel verschillende vaardigheden je nodig hebt, en dus de kans krijgt om deze allemaal aan te scherpen. Ik zou liegen als ik zou zeggen dat het van een leien dakje ging, maar als ik erop terug kijk ben ik toch erg blij met de ervaring en het resultaat.