SmartHome im Weihnachtshaus - AZ-Delivery

Der Bausatz Christmas House verfügt durch den Nano Mikrocontroller nur über begrenzte Funktionen, wie das Einschalten des Lichts über den Taster neben der Tür.

In diesem Blogbeitrag soll das Set mit einem D1 mini Mikrocontroller zu einem kleinen Smart-Home mit WLAN-Funktion im Weihnachtlichen Look verwandelt werden.

 

Hardware

Für die Realisation benötigen Sie:


Christmas House Kit

D1 mini ESP8266 (auch andere Ausführungen möglich)

Pegelwandler

Silikonkabel

F2F Jumper

Relay

DHT22 Sensormodul

Bausatz LED Christmas Tree  (auch andere Ausführungen möglich)

 

Auch als Bundle erhältlich:

SmartHome im Weihnachtshaus Bundle

 

Schließen Sie den Pegelwandler wie folgt mit den Silikon Kabeln an den D1mini an:


Abbildung 1: Verdrahtung D1mini

 

Für die rechte Seite können Sie eine Buchsenleiste des D1mini verwenden. Falls Sie über das entsprechende Werkzeug verfügen, ist eine gecrimpte Verbindung natürlich die professionelle Variante.

 

Nachdem Sie den Christmas House Bausatz nach der Anleitung zusammengebaut haben, öffnen Sie das Dachpaneel auf der Seite der Batteriebox.

Schließen Sie nun das Relay und den DHT22 an die folgenden Anschlüsse des Nano-Shields an.

 

DHT22

Shield

Relay

Shield

+

V 11

-

G 7

OUT

S 11

+

(V 7)

-

G 11

S

S 7

 

Die bereits installierten Module aus dem Bausatz bleiben an den in der Anleitung beschriebenen Anschlüssen.

Der WS2812 LED Strip wird in diesem Blog nicht verwendet, stattdessen wird der LED Weihnachtsbaum über das Relais gesteuert. Dieser kann aber auch durch die anpassung der LED Anzahl verwendet werden.

 

Schließen Sie den LED Baum wie folgt an:

 

Baum

Relay

Shield

VCC

 

V

GND

NO

 

 

COM

G


Abbildung 2: Anschlüsse für 5V Stromversorgung

 

Hinweis:

Falls Sie das Projekt mit dem Relais und Weihnachtsbaum über eine externe Spannungsquelle (z.B. Akkupaket auf der Rückseite) versorgen, kann dies bei einem hohen Strombedarf durch die zusätzlichen Komponenten zu einer starken Erwärmung des Low-Dropout-Regulators kommen. Dies kann unter Umständen zu einer Beschädigung führen. Verwenden Sie bei einem Strombedarf über 500mA eine separate Spannungsquelle bzw. über einen Buck-Converter.

 

Die Relais und der DHT22 Sensor können nun zum Beispiel mit doppelseitigem Klebeband im Haus fixiert werden.

 

Lassen Sie den hinteren Teil des Daches für die nächsten Schritte weiterhin geöffnet.

 

Software

Da der Nano über keine WLAN Schnittstelle verfügt, wird der D1 mini benötigt. Dieser hat als alleinige Aufgabe den Webserver für die Steuerung bereitzustellen. Die Informationen werden dann über die UART Schnittstelle an den Nano, welcher die gesamte Steuerung der Komponenten übernimmt, übertragen.

Da die beiden Mikrocontroller über die UART Schnittstelle die Daten austauschen, muss die Verbindung zum Flashen eines Mikrocontrollers getrennt sein.

 

Vorbereitung Arduino IDE

Falls Sie sich zum ersten Mal mit Mikrocontrollern befassen, müssen Sie noch den passenden Treiber herunterladen, um das Programm auf das Board übertragen zu können.

Die Installationsdatei für den passenden Treiber können Sie hier herunterladen.

 

Für den D1 mini benötigen Sie noch ein zusätzliches Paket, kopieren Sie zum installieren folgenden Link in der Arduino IDE unter: File->Preferences->Additional boards manager URLs : 

http://arduino.esp8266.com/stable/package_esp8266com_index.json

 

und installieren Sie in der Arduino IDE Boardverwaltung das ESP32 Paket.

 

Des weiteren werden noch Bibliotheken benötigt, um das LCD Display, das LED Modul und DHT22 Sensor ansteuern zu können:

Adafruit_NeoPixel

LiquidCrystal_I2C

DHT_sensor_library

 

Die Libraries können Sie über die in der Arduino IDE integrierten Bibliotheksverwaltung installieren oder über den Link von Github als .zip herunterladen und unter
Sketch > include Library > Add .zip Library …

einbinden.

 

Code Nano

Laden Sie das folgende Programm auf den Nano:

#include <Wire.h>
#
include <Adafruit_NeoPixel.h>
#
include <LiquidCrystal_I2C.h>
#
include "DHT.h"

#
define LED           A0
#
define BUTTON        2
#
define LDR           A3
#
define RELAY         7
#
define DHTPIN        11

#
define NUMPIXELS     4
#
define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321

long lastMillis;

LiquidCrystal_I2C lcd(
0x27, 16, 2);
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, LED, NEO_GRB + NEO_KHZ800);
DHT dht(DHTPIN, DHTTYPE);

void handleSensors() {
 
float h = dht.readHumidity();
 
// Read temperature as Celsius (the default)
 
float t = dht.readTemperature();

 
float b = map(analogRead(LDR), 900, 100, 0, 100);
 
//Sensorwerte Auslesen
 
String json = "{";
  json +=
"\"v1\":" + String(b) + ",";
  json +=
"\"v2\":" + String(t) + ",";
  json +=
"\"v3\":" + String(h) + "";
  json +=
"}";

 
Serial.println(json);
}

String readLine(Stream &port, unsigned long timeout = 1000) {
 
String line = "";
 
unsigned long start = millis();
 
while (millis() - start < timeout) {
   
while (port.available()) {
     
char c = port.read();
     
if (c == '\r') continue;
     
if (c == '\n') return line;
     
line += c;
     
if (line.length() > 256) return line;
    }
  }
 
return line;
}

void setup() {
 
Serial.begin(9600);
  dht.
begin();
  lcd.
begin(16, 2);
  lcd.
clear();
  lcd.backlight();
 
pinMode(RELAY, OUTPUT);
  strip.
begin();
}

void loop() {
 
if(millis()-lastMillis >= 1000) { //every second
    handleSensors();
    lastMillis =
millis();
  }
 
 
String line = readLine(Serial);
 
int idx1 = line.indexOf(';');
 
int idx2 = line.indexOf(';', idx1 + 1);
 
int idx3 = line.indexOf(';', idx2 + 1);
 
int idx4 = line.indexOf(';', idx3 + 1);
 
 
if (idx1 < 0 || idx2 < 0 || idx3 < 0 || idx4 < 0) return;

 
String recvHexColor = line.substring(1, idx1);//.toInt();
 
String recvText1    = line.substring(idx1 + 1, idx2);
 
String recvText2    = line.substring(idx2 + 1, idx3);
 
boolean relay = line.substring(idx3 + 1, idx4).toInt() == 1;
 
 
unsigned long colorInt = strtoul(recvHexColor.c_str(), NULL, 16);
 
    
for(int i=0; i<=4; i++) {
      strip.setPixelColor(i, colorInt);
    }
    strip.show();


  lcd.
setCursor(0, 0);
  lcd.
print(recvText1);
  lcd.
setCursor(0, 1);
  lcd.
print(recvText2);

 
digitalWrite(RELAY, relay);
}

 

Der komplette Code kann hier heruntergeladen werden.

Erklärung:

Zu Beginn werden die Bibliotheken eingebunden und Makros für die Pinbezeichnungen der angeschlossenen Module erstellt.

Danach folgt die Initialisierung der globalen Variablen und Objekte der Libraries.

Die darauf folgende Methode liest die Sensorwerte aus und generiert aus diesen einen json-String, welcher dann über die Serielle Schnittstelle (UART) an den D1mini gesendet wird, damit die Klimawerte auf der Website angezeigt werden können. Da der LDR nur ein Widerstand und somit nicht von Werk aus Kalibriert ist, können die tatsächlichen Grenzwerte abweichen. Diese können Sie in der map() Funktion einstellen. (900 unter Grenzwert 0%; 100 oberer Grenzwert 100%)

Die folgende Funktion readLine() bildet aus den einzelnen Zeichen, welche über die UART-Schnittstelle empfangen werden, einen String. Die Zeichen werden hier solange aneinandergefügt, bis eine neue Zeile (\n) beginnt. Die Funktion wird für die spätere Datenauswertung benötigt.

Im setup() werden die Startmethoden der Libraries aufgerufen und der IO des Relais als Output konfiguriert.

Der loop() startet mit dem Ausführen der handleSensors Funktion jede Sekunde. Die Zeitliche Verzögerung ist hier mit einem Vergleich über die millis() Funktion umgesetzt. Dadurch wird der loop() nicht blockiert.
Im Anschluss wird der String mit den Eingaben aus dem Webserver ausgewertet und daraufhin die LED in die ausgewählte Farbe gesetzt, der Text auf dem Display angezeigt und zum Schluss das Relais in den übermittelten Zustand gesetzt.

 

Webserver:

Nun folgt der html code welcher den Webserver anzeigt:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AZ Christmas House Control</title>

<style>
body { font-family: Arial; margin: 20px; background:#f0f0f0; }
#box { padding:20px; background:white; border-radius:10px; width:300px; }
label { font-weight:bold; }

/* Toggle switch */
.switch { position: relative; display: inline-block; width: 50px; height: 24px; }
.switch input { display:none; }
.slider {
 
position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0;
 
background-color: #ccc; transition: .4s; border-radius: 24px;
}
.slider:before {
 
position: absolute; content: ""; height: 18px; width: 18px;
 
left: 3px; bottom: 3px; background-color: white;
 
transition: .4s; border-radius: 50%;
}
input:checked + .slider { background-color: #4CAF50; }
input:checked + .slider:before { transform: translateX(26px); }
</style>

</head>

<body>
<div id="box">
<h1> Christmas House </h1>
<h2> Smart Home</h2>

<label>Beleuchtung:</label><br>
<input type="color" id="color" onchange="sendColor()"><br><br>

<label>Display:</label><br>
<input type="text" id="t1" maxlength="16"><br><br>

<input type="text" id="t2" maxlength="16"><br><br>

<button onclick="sendText()">Anzeigen</button><br><br>

<label>Baum:</label><br>
<label class="switch">
 
<input type="checkbox" id="toggle" onchange="sendToggle()">
 
<span class="slider"></span>
</label><br><br>

<h3>Klima:</h3>
Helligkeit:
<span id="v1">--</span> % <br>
Temperatur:
<span id="v2">--</span> °C <br>
Luftfeuchte:
<span id="v3">--</span> %H <br>

</div>

<script>
// ----------------- Initialwerte laden -----------------
window.onload = function() {
  fetch(
"/getState")
    .then(r => r.json())
    .then(data => {
     
document.getElementById("color").value = data.color;
     
document.getElementById("t1").value = data.text1;
     
document.getElementById("t2").value = data.text2;
     
document.getElementById("toggle").checked = data.toggle;
    });
};

// ---- RGB senden ----
function sendColor(){
 
let col = document.getElementById("color").value;
  fetch(
"/setColor?hex=" + encodeURIComponent(col));
}

// ---- Texte senden ----
function sendText(){
 
let tx1 = document.getElementById("t1").value;
 
let tx2 = document.getElementById("t2").value;
  fetch(
"/setText?t1=" + tx1 + "&t2=" + tx2);
}

// ---- Schalter senden ----
function sendToggle(){
 
let st = document.getElementById("toggle").checked ? 1 : 0;
  fetch(
"/setToggle?state=" + st);
}

// ---- Werte vom ESP abrufen ----
setInterval(()=>{
  fetch(
"/values")
    .then(response => response.json())
    .then(data =>{
     
document.getElementById("v1").innerHTML = data.v1;
     
document.getElementById("v2").innerHTML = data.v2;
     
document.getElementById("v3").innerHTML = data.v3;
    });
},
1000);
</script>

</body>
</html>

 

Grundsätzlich ist jede html Datei in einen head und body unterteilt. Im Head findet die Konfiguration statt. Dazu gehört auch das Styling der Elemente.

Im Body befinden sich die einzelnen html Elemente wie Eingabefelder und Buttons zudem aber auch ein script Teil, welcher Methoden enthält.
Beim Betätigen eines Buttons wird eine zugewiesene Methode ausgeführt, welche die Eingaben dann an den Mikrocontroller übermittelt.

Auf die genauen html Funktionen und den Aufbau wird hier aber nicht weiter eingegangen.

 

 

D1mini Code

Laden Sie das vollständige Programm (Download am Ende)  auf den D1mini:

#include <ESP8266WiFi.h>
#
include <ESP8266WebServer.h>

ESP8266WebServer server(
80);

// Gespeicherte Werte
String colorHex = "#ff0000";
String text1 = "";
String text2 = "";
bool toggleState = false;

String data;
String jsonVal = "{\"v1\":-99,\"v2\":-99,\"v3\":-99}";

long lastMillis;

// ----------------------- HTML -----------------------
const char MAIN_page[] PROGMEM = R"=====(

//Webserver html//
)====="
;

// ----------------------------------------------------------

void handleRoot() {
  server.send_P(
200, "text/html", MAIN_page);
}

void handleSetColor() {
  colorHex = server.arg(
"hex");
  server.send(
200, "text/plain", "OK");
}

void handleSetText() {
  text1 = server.arg(
"t1");
  text2 = server.arg(
"t2");
  server.send(
200, "text/plain", "OK");
}

void handleSetToggle() {
  toggleState = (server.arg(
"state") == "1");
  server.send(
200, "text/plain", "OK");
}

void handleValues() {
  server.send(
200, "application/json", jsonVal);
}

void handleGetState() {
 
String json = "{";
  json +=
"\"color\":\"" + colorHex + "\",";
  json +=
"\"text1\":\"" + text1 + "\",";
  json +=
"\"text2\":\"" + text2 + "\",";
  json +=
"\"toggle\":" + String(toggleState ? "true" : "false");
  json +=
"}";
  server.send(
200, "application/json", json);
}

String readLine(Stream &port, unsigned long timeout = 1000) {
 
String line = "";
 
unsigned long start = millis();
 
while (millis() - start < timeout) {
   
while (port.available()) {
     
char c = port.read();
     
if (c == '\r') continue;
     
if (c == '\n') return line;
     
line += c;
     
if (line.length() > 256) return line;
    }
   
yield();
  }
 
return line;
}

void setup() {
 
Serial.begin(9600);

 
WiFi.softAP("SmartHome", "");

  server.on(
"/", handleRoot);
  server.on(
"/setColor", handleSetColor);
  server.on(
"/setText", handleSetText);
  server.on(
"/setToggle", handleSetToggle);
  server.on(
"/values", handleValues);
  server.on(
"/getState", handleGetState);

  server.
begin();
}

void loop() {
 
if(millis()-lastMillis >= 500) {
   
String paket = colorHex + ";" + text1 + ";" + text2 + ";" + toggleState + ";";
   
Serial.println(paket);
    lastMillis =
millis();
  }

  server.handleClient();
  data = readLine(
Serial);
 
if(data.indexOf("{") == 0) {
    jsonVal = data;
  }
}

 

Der komplette Code kann hier heruntergeladen werden.

Erklärung:

Wie auch im Code für den Nano, werden am Anfang die Libraries eingebunden und Objekte & globale Variablen initialisiert.

Hier wird auch der html-Code in den Speicher geladen. Die gesamte html-Datei wurde hier aus Übersichtlichkeitsgründen weggelassen.

Die folgenden Methoden sind die Callback Funktionen des Webservers, mit welchen die Eingaben bei einer Änderung ausgelesen und angezeigt werden.

Die readLine Funktion entspricht grundsätzlich der im Nano-Programm verwendeten. Der einzige Unterschied ist, dass hier die yield() Funktion verwendet wird, welche eine Ausführung von Funktionen im Hintergrund ermöglicht. Somit kommt es zu keinen Problemen mit dem Webserver durch blockierte Hintergrundprozesse.

Im setup() wird noch ein Accesspoint gestartet, damit Sie sich direkt mit dem D1mini verbinden können und so auch keine WLAN Verbindung notwendig ist.
Danach werden die Callback Methoden zugewiesen und der Webserver gestartet.

Der loop() ist wieder analog zum Programm des Nanos aufgebaut. Hier wird nur der empfangene String nicht ausgewertet, sondern direkt an den Server gesendet, da dieser bereits im json Format ist.

 

Nachdem beide Mikrocontroller geflasht sind, stecken Sie den D1 mini Aufbau in die freie UART Stiftleiste auf dem Nano-Shield. Achten Sie darauf, dass diese richtig angeschlossen ist (den GND Pin können Sie bei obiger Verdrahtung als Referenz verwenden.

Nach dem Hochladen verbinden Sie sich mit dem offenen Netzwerk “SmartHome”. Sollten Sie eine Benachrichtigung bekommen, dass das Netzwerk keinen Internetzugang hat, aktivieren Sie Verbindung beibehalten für das Netzwerk. Öffnen Sie, wenn Sie mit dem Netzwerk verbunden sind, den Browser auf dem verbundenen Gerät und geben Sie die Adresse 192.168.4.1 ein. Daraufhin wird die folgende Seite angezeigt, auf der Sie das smart-home Steuern können.

Abbildung 3: Screenshot vom Webserver

Fazit:

Nachdem Sie die einzelnen Teile des Projekts nun über einen Webserver steuern können, können Sie noch Automationen auf dem Nano einprogrammieren, um beispielsweise den Button als Steuerung zu verwenden. Achten Sie aber darauf, dass im loop() keine Blockierungen (while oder delay) verwendet werden, um die Verarbeitung der Daten des Webservers nicht zu unterbrechen.

Mit diesen Automatisierungen und eventuell weiteren Sensoren oder Modulen können Sie so Ihr eigenes kleines Smart-Home-Projekt umsetzen und erweitern.

 

Viel Spaß beim Nachbauen :)

 

Für Leser mit fortgeschrittenen Kenntnissen lohnt sich auch ein Blick in den Blog hack-a-tree, in welchem der Weihnachtsbaum Bausatz neu programmiert wird und Sie somit Ihre eigenen Muster programmieren können.

Projekte für anfängerSmart homeSpecials

Kommentar hinterlassen

Alle Kommentare werden von einem Moderator vor der Veröffentlichung überprüft

Empfohlene Blogbeiträge

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery