openWeather – DIY ESP8266 Wetterstation

openWeather – DIY ESP8266 Wetterstation

In letzter Zeit habe ich mich viel mit ESP32 und ESP8266 beschäftigt. Nun hatte ich die Idee für mein Smarthome Set-Up ein paar Temperatur und Feuchtigkeitssensoren in der Wohnung zu verteilen. Damit da nicht einfach nackte Platinen herumliegen, wollte ich ein schickes Gehäuse gestalten, schließlich bin ich ja Industriedesigner. Für die Küche wäre aber direkt eine kleine Wetterstation cool, die auch beim Frühstück anzeigt, wie das Wetter in den nächsten Stunden wird.

So ist das Projekt open.Weather entstanden. Das ganze Projekt habe ich unter der GNU V3 auf GitHub veröffentlicht. Und so sieht das Ergebnis aus:

So sah übrigens meine Konzeptzeichnung aus:

Also ran ans Werk. Wir brauchen folgende Komponenten:

  • 1x ESP8266 oder ESP32
  • 1x DHT11 oder DHT22 (der 22 ist genauer)
  • 4x WS2812 LED

Die Scheibe ist mit dem Lasercutter hergestellt, das Gehäuse ist 3D-gedruckt. Also wäre Zugriff auf beides nicht schlecht, zum Beispiel im regionalen FabLab. Ich habe einen K40 und nutze einen Anycubic i3 Mega.

Konzept

Beim Magic Mirror habe ich ja eine API-Anfrage an Open Weather Map. Wie sich herausstellte, kann man auch direkt vom ESP8266 aus einen http Request stellen. Also kann ich den Wetterbericht aus dem Netz abfragen. Außerdem werde ich die Temperatur und Luftfeuchtigkeit mit dem DHT22 messen. Je nach Werten, sollen die WS2812 eine entsprechende Farbe anzeigen. Z.B. wenn die Luftfeuchtigkeit zu hoch ist, einen Hinweis geben, dass man Lüften sollte. Oder wenn es draußen sehr Warm oder Kalt ist entsprechend mit Orange / Rot / Blau den Hinweis geben. So auch für die Innentemperatur. Und je nach Wetterlage soll eins der Symbole beleuchtet werden.

Design

Bei Pinterest habe ich mir ein paar schöne Wetterstationen angeschaut und nach Inspiration gesucht. Dort habe ich viele hässliche Wetterstationen gefunden, doch auch ein paar schöne. Das ganze sollte irgendwie Holzoptik bekommen und minimalistisch werden. Damit es nicht wie noch ein Wecker aussieht, habe ich auf ein richtiges Display verzichtet.

Scheibe

Herzstück der Wetterstation ist die Scheibe mit den Icons. Wir wollen diese von unten mit RGB LEds beleuchten und das PMMA quasi wie einen Lichtleiter nutzen. Je nach Wetterlage soll ein Icon leuchten.

Optik

Vor ein paar Jahren habe ich ja in der Lichttechnik gearbeitet, daher wollte ich mal gucken, ob ich es noch hinbekomme, eine kleine Kollimator-Optik für die WS2812 zu entwickeln. Leider konnte ich den genauen Brennpunkt für die die LED nicht herausfinden, daher habe ich einfach eine Parabel für den Mittelpunkt des Chips ausgelegt.

Die Optik bündelt das licht der LED und sorgt dafür, dass nur der jeweilige Bereich der Scheibe beleuchtet wird, für den sie vorgesehen ist und nicht so viel Streulicht auf die anderen Icons gelangt.

Für die Auslegung braucht man lediglich das Brechungsgesetz und den Brechungsindex des Scheibenmaterials. Dann konstruiert man mit ein paar Tangenten für ein paar vordefinierte Strahlenpfade. Good enough for me.

Icons

Natürlich sind coole Icons besonders wichtig für ein ansprechendes Aussehen. Ich habe mir im Netz ein paar Referenz-Icons gesucht, die mir vom Style her gefallen (minimalistisch) haben und angelehnt an diese dann in Solidworks die Icons konstruiert. Sie bestehen hauptsächlich aus Langlöchern, Kreisen und Splines. Zusammen mit der Schiebenkontur ergeben sie das erste Bauteil. Daraus kann man eine .dxf Datei ableiten. Die entsprechenden Farben für den K40-Whisperer habe ich in Inkscape zusammengefügt.

Für das Ausschneiden der Scheibe hat mein K40 bei einem Vorschub von 5mm/s und ca. 20mA Stromstärke 5 Durchgänge gebraucht. Die Icons habe ich dann im Raster-Modus mit 300m/s und ebenfalls bei 20mA Stromstärke graviert.

Zuhause etwas mit dem Laser produzieren ist einfach geil 🙂

Der Sockel

Der Sockel besteht aus vier Teilen. Einem Boden, dem eigentlichen Sockel und einem Deckel. Dazu kommt noch eine Art Brücke auf der die LEDs Platz finden.

Eigentlich würde ich nun den Deckel einfach über Kopf drucken, doch ich wollte hier nicht, dass die Struktur des Druckbettes sichtbar ist. Daher habe ich den Deckel in etwas ungünster ausrichtung gesliced – dazu habe ich dann einen kleinen Rand für eine Schichtdicke hinzu konstruiert, damit ich nicht so viel Support benötige. Das hat sogar ganz gut geklappt. Die restlichen Teile waren soweit kein Problem, nur hat der Anycubic mal wieder einen kleine defekt erlitten. Das Fitting für den PTFE Schlauch hat sich verabschiedet – das Gewinde ist gebrochen.

Innenleben

Im Inneren der Wetterstation befindet sich der ESP sowie der DHT-Sensor. Für den ESP8266 gibt es passende Schraubsockel, für die Version ESP32 muss ich diese noch einbauen.

Der ESP8266 wird mit M3 Schrauben befestigt, die Pins müssen nach oben zeigen. So passt der USB-Port direkt in das andere Gehäuseteil und die LEDs und der Sensor können einfach per Jumper angeschlossen werden.

DHT22

In meiner Version der Wetterstation nutze ich den DHT22, ich habe aber auch ein Case für den DHT11 konstruiert. Die Teile sind modular, so dass sie unterschiedlich kombiniert werden können (ESP32 / DHT 11, etc).

Der Sensor wird einfach in die Öffnung gesteckt und per Jumper mit dem ESP verbunden. Er sollte durch Reibung halten.

LED Stripe

Ich habe vier WS2812 LEDs benutzt. Das schöne bei diesen LEDs ist, dass man nur einen digitalen Pin braucht, um diese RGB LEDs anzusteuern. Wir gucken also dass wir uns passend zum PMMA Display einen LED Strip basteln. Dazu legen wir die LEDs unter die Kollimatoren und suchen uns passende Kabel heraus, bzw. kürzen diese entsprechend.

Bei meiner LED Version gibt es jeweils eine Seite auf der Platine an der der Dateneingang ist, die anderen drei sind Ausgänge. Hier habe ich Pins angelötet. Achtet darauf + und – korrekt zu verlöten.

Als mein Lightstrip fertig war, habe ich zunächst getestet, ob er funktioniert und die LEDs an die Positionen passen. Dann hab ich ihn mit Isolierband an der LED Brücke befestigt und diese in den vorbereiteten Sockel gesteckt. Das ganze sollte auf Reibung halten.

Zum Schluss kann einfach der Deckel mit Scheibe eingesteckt werden, welcher auch durch Reibung halten sollte. Damit ist die Hardware der Wetterstation zusammengebaut.

Code

Der Code ist doch recht umfangreich geworden, da ich mir vom DHT die Werte noch per MQTT an mein openHAB senden lasse und so direkt die Küche mit Loggen kann. Außerdem habe ich ein kleines Easter-Egg eingebaut 🙂 Ich poste hier mal den gesamten Sketch und gehe dann auf die einzelnen Abschnitte ein. Da der Code so lang ist, gibt es hier einen Seitenumbruch.

/* Open Weather - the open source weatherbeacon that also looks good.
    We connect to your home wifi and send a http request to open weathermap every hour to update the free 3 hour forecast.
    depending on the weather-id (https://openweathermap.org/weather-conditions#Weather-Condition-Codes-2) another led will light up
    in a predefined colour to resemble weather and temperature and hightlight the respective icon.

    See Full documentation on https://daniel-strohbach.de/diy-esp8266-wetterstation

    Parts needed:
    - ESP8266 or ESP32 Board, alternatively arduino nano with wifi shield will do as well but not coded here
    - Optional: DHT22 or DHT11 Sensor to measure Indoor Temp and Humidity
    - 4x WS2812 (aka NeoPixel) LED

    Solder the 4 LEDs into a tiny LED Strip and connect to Dev Board:
    Board LED   LED   LED   LED
    3V3 - VCC - VCC - VCC - VCC
    GND - GND - GND - GND - GND
    D8 -  I/0 - I/O - I/O - I

    Connect DHT22 / DHT11 to
    Board DHT
    3V3 - +
    GND - -
    D4  - OUT

    Pixel-ID Icon reference (take care when assembling or switch in the code

    0 - clear sky
    1 - cloudy
    2 - rainy
    3 - snow

    Outdoortemperature & Colours:
    > 30°C - Red
    > 21°C - Warm yellow
    < 18°C - Light blue
    < 00°C - Blue
    Thunderstorm: Yellow
    Fog: White

    Red: Wifi related error
    green: connecting

    Optional: Send the measured DHT Data to an MQTT Broker

    Made By Daniel Strohbach www.daniel-strohbach.de/
*/

//--- USER CONFIG ---

//Do you want to use MQTT?
#define USEMQTT

//Do you want to use DHT?
#define USEDHT

//Do you use ESP8266 or ESP32?
#define ESP8266

//Do you want to use Serial Monitor for Debugging?
#define DEBUGING

#ifdef ESP8266
#include <ESP8266WiFi.h> // for WiFi functionality
#include <ESP8266HTTPClient.h> //for the API-Request
#endif

#ifdef ESP32
#include <WiFi.h> //in case you are on esp32 we switch to this line
#include <HTTPClient.h>
#endif

// Please Change to your WIFI-Credentials
const char* ssid = "YOUR WIFI";
const char* password = "YOUR PW";

//What citiy you want to receive the weather from?
const char* city = "Oldenburg,de"; //City and Country like this Oldenburg,de

//Here please add your Open Weathermap API Key from https://home.openweathermap.org/api_keys
const char* openWeatherAPI = "YOUR API";

//What units do you use?
const char* unitSystem = "metric";

#include <ArduinoJson.h> //JSON String conversion for Open Weathermap API Request

// We use Neopixel to Control the WS2812. In my build i use a node mcu esp8266 and pin d8 to drive the pixels
#include <Adafruit_NeoPixel.h>

#define LEDPIN D8 //neopixels to pin d8
#define NUMPIXELS 4 // My Vesion has 4 Pixels

Adafruit_NeoPixel pixels(NUMPIXELS, LEDPIN, NEO_GRB + NEO_KHZ800); //build the neopixel constructor

//--- MQTT ---
#ifdef USEMQTT
#include <PubSubClient.h>

const char* mqttServer = "YOUR MQTT IP";
const char* mqttUsername = "MQTT USERNAME";
const char* mqttPassword = "YOUR PSK";
const char* mqttDeviceId = "openWeather"; //you can pick any name here

//i use something quite similar to tasmota, but feel free to change
const char* subTopic = "cmnd/openWeather/command";
const char* temperatureTopic = "stat/openWeather/Temperatur";
const char* humidityTopic = "stat/openWeather/Feuchtigkeit" ;
const char* heatIndexTopic = "stat/openWeather/HeatIndex";
unsigned long lastMsg = 0;

WiFiClient openWeather;
PubSubClient client(openWeather);
#endif

//--- DHT ---
#ifdef USEDHT
#include "DHTesp.h"
#define DHTPIN D4
DHTesp dht;

//--- Global Variables for Sensor storage---
float temperature, humidity, heatIndex;
#endif

//--- Timer Stuff ---
unsigned long previousMillisMes; //previous timer time
unsigned long previousMillisPub; //
unsigned long previousMillisReq;

const unsigned long measureIntervall = 500; //update sensor every 500ms
const unsigned long publishIntervall = 5000; //publish mqtt every 5 sekonds
const unsigned long requestIntervall = 3600000; //drive http request every hour

int modus = 0;
bool firstloop = true;

//--- ARDUINO SETUP ---

void setup() {
  //Begin serial connection
#ifdef DEBUGING
  Serial.begin(9600);

  //Welcome to Serial Monitor
  Serial.println("openWeather: Erfasse Wetter, Temperatur, Feuchtigkeit on: ");
  String thisBoard = ARDUINO_BOARD;
  Serial.println(thisBoard);
#endif

  //--Neopixel
  pixels.begin(); // INITIALIZE NeoPixel strip object
  pixels.clear(); // Set all pixel colors to 'off'

  //--Wifi
  setup_wifi();

  //--MQTT
#ifdef USEMQTT
  client.setServer(mqttServer, 1883);
  client.setCallback(callback);
#endif

  //--DHT
#ifdef USEDHT
  dht.setup(DHTPIN, DHTesp::DHT22); // Connect DHT sensor to GPIO 17
#endif

}

//--- ARDUINO LOOP ---

void loop() {
#ifdef DEBUGING
  Serial.println("void loop: Started... ");
#endif

  if (!client.connected()) {
    reconnect();
#ifdef DEBUGING
    Serial.println("void loop: Lost MQTT... ");
#endif
  }
  client.loop();

#ifdef DEBUGING
  Serial.print("void loop: Modus: ");
  Serial.println(modus);
#endif

//if we are in the first loop, we already want to fetch the weather data, afterwards only every hour
  if (firstloop) {
    getWeather();
    firstloop=false;
  }

  //get Weatherdata
  if (millis() - previousMillisReq >= requestIntervall) {
    previousMillisReq = millis();
    if (modus == 0) {
      getWeather();
    }
  }

  //read sensor
  if (millis() - previousMillisMes >= measureIntervall) {
    previousMillisMes = millis();
    getDHT();
  }

  //publish to MQTT Broker
  if (millis() - previousMillisPub >= publishIntervall) {
    previousMillisPub = millis();
    publishMQTT();
  }

  if (modus == 1) {
    pixelParty();
  }
  if (modus == 2) {
    rainbowFade(3, 3, 1);
  }

}

//--- CUSTOM CLASSES ---
//--Wifi
void setup_wifi() {
#ifdef DEBUGING
  Serial.println("setup_wifi: Started... ");
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to: ");
  Serial.println(ssid);
#endif

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);

#ifdef DEBUGING
    Serial.print(".");
#endif

    //Signal wifi connecting with green animation
    for (int i = 0; i < NUMPIXELS; i++) { // For each pixel...

      // pixels.Color() takes RGB values, from 0,0,0 up to 255,255,255
      // Here we're using a moderately bright green color:
      pixels.setPixelColor(i, pixels.Color(0, 255, 0));

      pixels.show();   // Send the updated pixel colors to the hardware.

      delay(500); // Pause before next pass through loop
    }
  }

#ifdef DEBUGING
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
#endif
}

//----------------------------------- RECONNECT MQTT ---------------------
#ifdef USEMQTT
void reconnect() {
  // Loop until we're reconnected
#ifdef DEBUGING
  Serial.println("reconnect: ");
#endif

  while (!client.connected()) {
#ifdef DEBUGING
    Serial.println("Attempting MQTT connection...");
#endif
    pixels.clear();
    for (int i = 0; i < NUMPIXELS; i++) { // For each pixel...

      // pixels.Color() takes RGB values, from 0,0,0 up to 255,255,255
      // Here we're using a moderately bright green color:
      pixels.setPixelColor(i, pixels.Color(0, 0, 255));

      pixels.show();   // Send the updated pixel colors to the hardware.

      delay(500); // Pause before next pass through loop
    }


    // Attempt to connect
    if (client.connect(mqttDeviceId, mqttUsername, mqttPassword)) {
#ifdef DEBUGING
      Serial.println("connected");
#endif

      client.subscribe(subTopic);
    } else {
#ifdef DEBUGING
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
#endif

      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}
#endif

//----------------------------------- CALLBACK MQTT ---------------------
// you can use this to send commands to the weather beacon.
#ifdef USEMQTT
void callback(char* topic, byte* message, unsigned int length) {
#ifdef DEBUGING
  Serial.println("callback: ");
  Serial.print("Message arrived on topic: ");
  Serial.print(topic);
  Serial.print(". Message: ");
#endif
  String messageTemp;

  for (int i = 0; i < length; i++) {
#ifdef DEBUGING
    Serial.print((char)message[i]);
#endif
    messageTemp += (char)message[i];
  }
#ifdef DEBUGING
  Serial.println();
#endif

  // Feel free to add more if statements to control more GPIOs with MQTT

  // If a message is received on the topic, you check if the message is either "on" or "off".
  // Changes the output state according to the message
  if (String(topic) == subTopic) {
#ifdef DEBUGING
    Serial.print("Changing output to ");
#endif
    if (messageTemp == "PixelParty1") {
#ifdef DEBUGING
      Serial.println("PixelParty1");
#endif
      modus = 1;
    }
    else if (messageTemp == "PixelParty2") {
#ifdef DEBUGING
      Serial.println("PixelParty2");
#endif
      modus = 2;
    }
    else if (messageTemp == "endParty") {
#ifdef DEBUGING
      Serial.println("The Party is over");
#endif
      modus = 0;
        firstloop = true;
    }
  }
}
#endif

//----------------------------------- Publish MQTT ---------------------
#ifdef USEMQTT
void publishMQTT() {
#ifdef DEBUGING
  Serial.println("publishMQTT: Sende Nachrichten...");
#endif

  unsigned long now = millis();
  if (now - lastMsg > 5000) { //Sending every 5 seconds
    lastMsg = now;

    client.publish(temperatureTopic, String(temperature).c_str());
    client.publish(humidityTopic, String(humidity).c_str());
    client.publish(heatIndexTopic, String(heatIndex).c_str());

  }
}
#endif

//-- Get the Weather from Open Weather Map --
void getWeather() {
  pixels.clear();
  
#ifdef DEBUGING
  Serial.println("getWeather: Stelle OpenWeathermap HTTP Request...");
#endif

  if ((WiFi.status() == WL_CONNECTED)) { //Checks if we are connected to a wifi
#ifdef DEBUGING
    Serial.println("getWeather: Wifi stabil...");
#endif

    HTTPClient http; //starting an instance of httpclient named http
#ifdef DEBUGING
    Serial.println("getWeather: Starte HTTPClient...");
#endif

    http.begin("http://api.openweathermap.org/data/2.5/weather?q=" + String(city) + "&units=" + String(unitSystem) +"&appid=" + String(openWeatherAPI)); //URL für die Abfrage
#ifdef DEBUGING
    Serial.println("getWeather: Verbinde zu URL: ");
    Serial.println("http://api.openweathermap.org/data/2.5/weather?q=" + String(city) + "&units=" + String(unitSystem) + "&appid=" + String(openWeatherAPI));
#endif

    int httpCode = http.GET(); //get answer from server
#ifdef DEBUGING
    Serial.print("getWeather: Antwort des Servers: ");
    Serial.println(httpCode); //print the answer to serial monitor
#endif

    if (httpCode == 200) { //if the answer is 200

      String payload = http.getString(); //Store the string from server to string payload on esp

      const size_t capacity = JSON_ARRAY_SIZE(1) + 2 * JSON_OBJECT_SIZE(1) + 2 * JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(14) + 290;

      DynamicJsonDocument doc(capacity); //dynamic switch size for json string buffer

      DeserializationError error = deserializeJson(doc, payload); //JSON parsing

      http.end(); //End Serverconnection.

      if (error) { //Fehlermeldung bei fehlerhafter Verarbeitung
#ifdef DEBUGING
        Serial.print(F("deserializeJson() failed: "));
        Serial.println(error.c_str());
#endif
        return;
      }

      //---Temperature LOGIC ---
      JsonObject main = doc["main"];
      int outdoor_temp = (int)main["temp"]; // Convert data to type INT and store to outdoor_temp
#ifdef DEBUGING
      Serial.print("Received Outdoor Temperature: ");

      if (unitSystem == "metric") {
        Serial.println(String(outdoor_temp) + " °C"); //add a nice little c for celsius
      } else if (unitSystem == "imperial") {
        Serial.println(String(outdoor_temp) + " °F"); //or F for Fahrenheit
      }
#endif

      int colourR, colourG, colourB;

      //if temperature is below zero °C
      if (outdoor_temp < 0) {
        colourR = 30;
        colourG = 50;
        colourB = 255;
      }

      //if it is below 10 °C
      else if (outdoor_temp < 10) {
        colourR = 50;
        colourG = 150;
        colourB = 220;
      }

      //if it is below 20 °C
      else if (outdoor_temp < 20) {
        colourR = 100;
        colourG = 150;
        colourB = 150;
      }

      //if it is above 25 °C
      else if (outdoor_temp > 25) {
        colourR = 240;
        colourG = 150;
        colourB = 20;
      }

      //if it is above 30 °C
      else if (outdoor_temp > 30) {
        colourR = 230;
        colourG = 130;
        colourB = 35;
      }

      //if it is above 40 °C
      else if (outdoor_temp > 30) {
        colourR = 230;
        colourG = 80;
        colourB = 60;
      }

      //--- Weather LOGIC ---
      JsonObject weather_0 = doc["weather"][0]; //here we figure out which kind of weather we will get
      int weather_0_id = weather_0["id"];       // Weather-ID

#ifdef DEBUGING
      Serial.print("Received Weather ID: ");
      Serial.println(weather_0_id);
#endif

      //Cloudy
      if (weather_0_id > 800 && weather_0_id <= 804) {
        pixels.setPixelColor(1, pixels.Color(colourR, colourG, colourB)); //Set color of Pixel 1 to temperature dependend colour
      }

      //Different types of Rain
      else if (weather_0_id >= 300 && weather_0_id < 600) {
        pixels.setPixelColor(2, pixels.Color(colourR, colourG, colourB)); //Set color of Pixel 2 to temperature dependend colour
      }

      //Thunderstorm
      else if (weather_0_id >= 200 && weather_0_id < 300) {
        colourR = 241;
        colourG = 196;
        colourB = 15;
        pixels.setPixelColor(2, pixels.Color(colourR, colourG, colourB)); //Set color of Pixel 2 to overwritten thunderstorm colour
      }

      //Snow
      else if (weather_0_id >= 600 && weather_0_id < 700) {
        pixels.setPixelColor(3, pixels.Color(colourR, colourG, colourB)); //Set color of Pixel 2 to temperature dependend colour
      }

      //Atmosphere Stuff (Mist, Dust, and so on) -> setting LED Colour to White
      else if (weather_0_id >= 700 && weather_0_id < 800) {
        colourR = 255;
        colourG = 255;
        colourB = 255;
      }

      //Weathergroup 800 = Clear Sky
      else if (weather_0_id == 800) {
        pixels.setPixelColor(0, pixels.Color(colourR, colourG, colourB)); //Clear sky is Pixel 0
      }

    } // End if HTTP Succesfull

    pixels.show();   // Send the updated pixel colors to the hardware.

  } //End of if (is wifi connected)

  else { //if we get an error we can signal via an led animation (Red ...)
#ifdef DEBUGING
    Serial.println("Error on HTTP request");
#endif
    for (int i = 0; i < NUMPIXELS; i++) { // For each pixel...

      // pixels.Color() takes RGB values, from 0,0,0 up to 255,255,255
      // Here we're using a moderately bright green color:
      pixels.setPixelColor(i, pixels.Color(255, 0, 0));

      pixels.show();   // Send the updated pixel colors to the hardware.

      delay(500); // Pause before next pass through loop
    }
  }
}

//--- DHT ---
#ifdef USEDHT
void getDHT() {
  delay(dht.getMinimumSamplingPeriod());
  humidity = dht.getHumidity();
  temperature = dht.getTemperature();
  heatIndex = dht.computeHeatIndex(temperature, humidity, false);
}
#endif

//--- Fun Stuff (from neopixel example) ---
void pixelParty() {
  colorWipe(pixels.Color(255,   0,   0)     , 50); // Red
  colorWipe(pixels.Color(  0, 255,   0)     , 50); // Green
  colorWipe(pixels.Color(  0,   0, 255)     , 50); // Blue
  colorWipe(pixels.Color(  0,   0,   0, 255), 50); // True white (not RGB white)
}

void colorWipe(uint32_t color, int wait) {
  for (int i = 0; i < pixels.numPixels(); i++) { // For each pixel in strip...
    pixels.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    pixels.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}

void rainbowFade(int wait, int rainbowLoops, int whiteLoops) {
  int fadeVal = 0, fadeMax = 100;

  // Hue of first pixel runs 'rainbowLoops' complete loops through the color
  // wheel. Color wheel has a range of 65536 but it's OK if we roll over, so
  // just count from 0 to rainbowLoops*65536, using steps of 256 so we
  // advance around the wheel at a decent clip.
  for (uint32_t firstPixelHue = 0; firstPixelHue < rainbowLoops * 65536;
       firstPixelHue += 256) {

    for (int i = 0; i < pixels.numPixels(); i++) { // For each pixel in strip...

      // Offset pixel hue by an amount to make one full revolution of the
      // color wheel (range of 65536) along the length of the strip
      // (pixels.numPixels() steps):
      uint32_t pixelHue = firstPixelHue + (i * 65536L / pixels.numPixels());

      // pixels.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or
      // optionally add saturation and value (brightness) (each 0 to 255).
      // Here we're using just the three-argument variant, though the
      // second value (saturation) is a constant 255.
      pixels.setPixelColor(i, pixels.gamma32(pixels.ColorHSV(pixelHue, 255,
                                             255 * fadeVal / fadeMax)));
    }

    pixels.show();
    delay(wait);

    if (firstPixelHue < 65536) {                             // First loop,
      if (fadeVal < fadeMax) fadeVal++;                      // fade in
    } else if (firstPixelHue >= ((rainbowLoops - 1) * 65536)) { // Last loop,
      if (fadeVal > 0) fadeVal--;                            // fade out
    } else {
      fadeVal = fadeMax; // Interim loop, make sure fade is at max
    }
  }

  for (int k = 0; k < whiteLoops; k++) {
    for (int j = 0; j < 256; j++) { // Ramp up 0 to 255
      // Fill entire strip with white at gamma-corrected brightness level 'j':
      pixels.fill(pixels.Color(0, 0, 0, pixels.gamma8(j)));
      pixels.show();
    }
    delay(1000); // Pause 1 second
    for (int j = 255; j >= 0; j--) { // Ramp down 255 to 0
      pixels.fill(pixels.Color(0, 0, 0, pixels.gamma8(j)));
      pixels.show();
    }
  }
}

Außerdem habe ich eine GitHub Repo erstellt. Dort gibt es auch die anderen Files.

MQTT

Ich nutze wieder MQTT um die Sensorwerte in meine openHAB Instanz auf dem RaspberryPi zu senden. Dort werden diese in einer InfluxDB gespeichert und mit Grafana visualisiert. Hier nur kurz ein paar Screenshots, da ich das vorgehen ja schon zur genüge in anderen Beiträgen beschrieben hab.

//openWeather
Number openWeatherTemperature   "MQTT: openWeather Temperatur"     { channel="mqtt:topic:openWeather:openWeatherTemperature"}
Number openWeatherHumidity      "MQTT: openWeather Feuchtigkeit"   { channel="mqtt:topic:openWeather:openWeatherHumidity"}
Number openWeatherHeatIndex     "MQTT: openWeather HeatIndex"      { channel="mqtt:topic:openWeather:openWeatherHeatIndex"}
Switch openWeatherPixelParty1   "MQTT: openWeather PixelParty1"    { channel="mqtt:topic:openWeather:party1switch"}
Switch openWeatherPixelParty2   "MQTT: openWeather PixelParty2"    { channel="mqtt:topic:openWeather:party2switch"}
Switch openWeatherLEDswitch     "MQTT: openWeather LEDSwitch"      { channel="mqtt:topic:openWeather:LEDswitch"}

Wer kein openHAB will oder hat, aber noch einen RaspberryPi herumfliegen hat, kann <hier/> den Guide für einen IOT Server auf Basis des RaspberryPi nachlesen.

3D-Files

Hier sind die 3D-Daten zum Angucken:

Case DHT22

WP 3D Thingviewer need Javascript to work.
Please activate and reload the page.

Sockel ESP8266

WP 3D Thingviewer need Javascript to work.
Please activate and reload the page.

LED-Halterung

WP 3D Thingviewer need Javascript to work.
Please activate and reload the page.

Deckel

WP 3D Thingviewer need Javascript to work.
Please activate and reload the page.

Galerie

Hier wieder die restlichen Projektbilder.

Schreibe einen Kommentar