Internet – Pollux Labs https://polluxlabs.net Arduino, ESP32 & ESP8266 | Projekte & Tutorials Tue, 24 Jun 2025 09:09:03 +0000 de hourly 1 https://wordpress.org/?v=6.8.3 https://polluxlabs.net/wp-content/uploads/2020/05/cropped-pollux-labs-p-32x32.png Internet – Pollux Labs https://polluxlabs.net 32 32 So erzeugst du KI Bilder mit Python und deepAI https://polluxlabs.net/python-tutorials-und-projekte/so-erzeugst-du-ki-bilder-mit-python-und-deepai/ Fri, 27 Jan 2023 07:21:20 +0000 https://polluxlabs.net/?p=13559 Bilder, die von einer künstlichen Intelligenz wie DALL-E oder DeepAI „gemalt“ werden, sind in aller Munde. In diesem Tutorial erfährst du, wie du KI Bilder mithilfe eines Python Scripts erzeugst.

Du lädst dir hierfür die aktuelle Schlagzeile der BBC-Nachrichten von einer API und schickst diese an die künstliche Intelligenz von deepai.org – von dort erhältst du eine Illustration der Schlagzeile zurück auf deinen Computer, gemalt in einem Stil deiner Wahl.

Diese APIs benötigst du

In diesem Projekt kommen zwei Services zum Einsatz, die du über deren APIs ansteuerst: NewsAPI und DeepAI. Von ersterer fragst die aktuelle Schlagzeile der BBC ab. Hierfür benötigst du einen API Key, den du nach deiner kostenlosen Registrierung erhältst. Wie das geht, und wo du deinen API Key findest, haben wir in diesem Projekt beschrieben.

Mit DeepAI erzeugst du dann KI Bilder, indem du die Schlagzeile an deren API weiterleitest und als sogenannten Prompt verwendest. Das ist so etwas wie die „Malanweisung“, die du der künstlichen Intelligenz gibst. Hierfür kommt ein Diffusionsmodell zum Einsatz, das der Deutschlandfunk Kultur in diesem Beitrag anschaulich erklärt. Erstaunlich hierbei ist, dass die KI eigentlich kein Bild auf Basis deiner Anweisung erzeugt, sondern vielmehr aus einem großen Rauschen „freilegt“.

Aber zurück zur API von DeepAI. Auch um diese nutzen zu können, benötigst du einen kostenlosen Account dort. Du erhältst anschließend einige Gratis-Credits, die du bei Bedarf auch günstig aufstocken kannst. Nachdem du dein kostenloses Kontingent verbraucht hast, kostet dich ein Bild 5 Cent – ein Betrag, der den Spaß Wert ist, wie wir finden.

Deinen API Key von DeepAI findest du übrigens oben in deinem Profil. Auch diesen wirst du demnächst in deinem Python Script benötigen.

Bibliotheken installieren

Für dein Script benötigst du einige Bibliotheken, die du vielleicht noch nicht installiert hast: requests, newsapi und PIL. Du kannst sie mit diesen Befehlen installieren:

pip install requests
pip install newsapi-python
pip install Pillow

Du benötigst diese drei Bibliotheken für die API-Abfrage bei DeepAI und NewsAPI und um das Bild, das du zurück erhältst zu bearbeiten. Insgesamt importierst du zu Beginn des Scripts folgende Bibliotheken:

import requests
import webbrowser
import json
from newsapi import NewsApiClient
from PIL import Image
import os
import sys
import shutil
import random

Schlagzeilen von newsapi abrufen

Als nächstes besorgst du dir die neuesten Nachrichten von der BBC. Hier kommt die NewsAPI-Bibliothek zum Einsatz, die du gerade importiert hast. (Natürlich kannst du den Request auch anders gestalten.)

# NewsAPI
newsapi = NewsApiClient(api_key='DEIN API-Key von NewsAPI')

# Top-Schlagzeilen der BBC abrufen
headlines = newsapi.get_everything(sources='bbc-news',
                                   language='en',
                                   sort_by='publishedAt')

x = headlines.get('articles')
y = x[0]

# Die längere 'description' der Schlagzeile der Variable prompt zuweisen
print('Ich empfange die neueste BBC-Schlagzeile...')
prompt = y.get('description')

KI Bilder erzeugen

Danach kommt die künstliche Intelligenz ins Spiel. Um etwas Abwechslung ins Spiel zu bringen, bindest du vier verschiedene Stilrichtungen ein (galleries): „Old Style“, Pop Art, Renaissance, Abstrakt. Welcher Stil bei deiner Anfrage zum Einsatz kommt, bestimmst du mit einer Zufallszahl.

Je nachdem, welche Zahl gewürfelt wurde, steuerst du eine andere URL der API an:

# Zufällig eine von vier Stilrichtungen festlegen
randomGallery = random.randint(0,3)

if randomGallery == 0:
    galleryURL = 'https://api.deepai.org/api/old-style-generator'
elif randomGallery == 1:
    galleryURL = 'https://api.deepai.org/api/pop-art-generator'
elif randomGallery == 2:
    galleryURL = 'https://api.deepai.org/api/renaissance-painting-generator'
else:
    galleryURL = 'https://api.deepai.org/api/abstract-painting-generator'

print('Ich verwende den Stil von: ' + galleryURL)

r = requests.post(
    galleryURL,
    data={
        'text': prompt,
    },
    headers={'api-key': 'DEIN API-Key von DeepAI'}
)

url = r.json()
print(url['output_url'])

Wie du im Code oben siehst, dient die Description der BBC-Schlagzeile als prompt, den du in deinem Request an die API übermittelst. Ein mögliches Ergebnis im sogenannten „Old Style“ sieht dann so aus:

Prompt: Former Detroit Lions linebacker Jessie Lemonier dies at the age of 25, the National Football League team announce.

DeepAI liefert dir über die API immer eine Collage aus vier quadratischen Bildern zurück. In diesem Python Script schneiden wir das Bild oben links aus und speichern es ab – mit dem Prompt als Dateinamen. Natürlich kannst du es auch unverändert ausschneiden, oder jedes einzelne Quadrat ausschneiden und separat speichern.

# Bild herunterladen
def download_image(url, file_name, headers):
     response = requests.get(url, headers=headers)
     if response.status_code == 200:
        with open(file_name, "wb") as f:
            f.write(response.content)
     else:
        print(response.status_code)

headers = {
    "User-Agent": "Chrome/51.0.2704.103",
}

url = url['output_url']

# Dateinamen = Prompt festlegen
file_name = "{}.jpg".format(prompt)

download_image(url, file_name, headers)

# Bild zuschneiden
print('Ich schneide das Bild zu...')
img = Image.open('{}'.format(file_name))
box = (0, 0, 512, 512)
img = img.crop(box)
img.save('{}'.format(file_name))

Zuletzt bleibt nur noch eins: Das neue Bild zu öffnen und zu präsentieren:

img.show()

Das vollständige Python Script

Hier nun das vollständige Script. Vergiss nicht, deine API Keys von NewsAPI und DeepAi einzutragen, bevor du loslegst.

# Copyright 2023, Pollux Labs
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the Software without restriction, including without
# limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
# Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in all copies or substantial portions
# of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
# TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
# 
# https://polluxlabs.net/python/so-erzeugst-du-ki-bilder-mit-python-und-deepai/

import requests
import webbrowser
import json
from newsapi import NewsApiClient
from PIL import Image
import os
import sys
import shutil
import random

# NewsAPI
newsapi = NewsApiClient(api_key='DEIN API-Key von NewsAPI')

# Top-Schlagzeilen der BBC abrufen
headlines = newsapi.get_everything(sources='bbc-news',
                                   language='en',
                                   sort_by='publishedAt')

x = headlines.get('articles')
y = x[0]

# Die längere 'description' der Schlagzeile der Variable prompt zuweisen
print('Ich empfange die neueste BBC-Schlagzeile...')
prompt = y.get('description')


# Bild von DeepAI empfangen

# Zufällig eine von vier Stilrichtungen festlegen
randomGallery = random.randint(0,3)

if randomGallery == 0:
    galleryURL = 'https://api.deepai.org/api/old-style-generator'
elif randomGallery == 1:
    galleryURL = 'https://api.deepai.org/api/pop-art-generator'
elif randomGallery == 2:
    galleryURL = 'https://api.deepai.org/api/renaissance-painting-generator'
else:
    galleryURL = 'https://api.deepai.org/api/abstract-painting-generator'

print('Ich verwende den Stil von: ' + galleryURL)

r = requests.post(
    galleryURL,
    data={
        'text': prompt,
    },
    headers={'api-key': 'DEIN API-Key von DeepAI'}
)

url = r.json()
print(url['output_url'])


print('Ich male dein Bild...')

# Bild herunterladen
def download_image(url, file_name, headers):
     response = requests.get(url, headers=headers)
     if response.status_code == 200:
        with open(file_name, "wb") as f:
            f.write(response.content)
     else:
        print(response.status_code)

headers = {
    "User-Agent": "Chrome/51.0.2704.103",
}

url = url['output_url']

# Dateinamen = Prompt festlegen
file_name = "{}.jpg".format(prompt)

download_image(url, file_name, headers)

# Bild zuschneiden
print('Ich schneide das Bild zu...')
img = Image.open('{}'.format(file_name))
box = (0, 0, 512, 512)
img = img.crop(box)
img.save('{}'.format(file_name))

# Bild anzeigen
img.show()

Bringe das Projekt in dein Wohnzimmer

Zum Schluss noch eine Idee für ein Raspberry Pi Projekt: Verbinde ein quadratisches Display, z.B. das HyperPixel 4.0 Square, mit deinem Raspberry Pi. Beides kannst du in einen Bilderrahmen stecken und das Python Script automatisch bei jedem Boot laufen lassen.

Damit jedoch nicht immer das gleiche Bild im Bilderrahmen steckt, könntest du noch dafür sorgen, dass es z.B. jede Stunde ausgetauscht wird.

Zusammengebaut könnte das Ganze dann so ausschauen:

]]>
Countdown zum nächsten SpaceX Raketenstart https://polluxlabs.net/esp8266-projekte/countdown-zum-naechsten-spacex-raketenstart/ Sat, 20 Mar 2021 16:18:28 +0000 https://polluxlabs.net/?p=4485 Wichtiger Hinweis: Leider funktioniert dieses Projekt nicht mehr, da die hierfür benötigte API leider eingestellt wurde. Es ist trotzdem weiterhin online, denn vielleicht bringt es dich beim Durchlesen auf eine andere Idee. Falls du eine andere Möglichkeit kennst, den nächsten Start einer Rakete zu ermitteln, schreibe gerne an info@polluxlabs.net

Wenn du an einen Raketenstart denkst, kommt dir bestimmt vieles in den Sinn. Sicherlich auch der obligatorische Countdown. Wie wäre es, wenn du daheim die Sekunden zum nächsten Launch einer Rakete von SpaceX herunterzählst?

Elon Musks Weltraumunternehmen betreibt eine API, von der du unter anderem die Daten des nächsten Starts beziehen kannst. Hierfür benötigst du nur einen ESP8266. Den Countdown kannst du stilecht auf einem 7-Segment Display darstellen. Und für die Beleuchtung beim Lift-off eignet sich ein NeoPixel LED-Ring.

Fortgeschrittene

1 – 2 Stunden

ca. 15 €

Für dieses Projekt benötigst du (Mengen s. Beschreibung):

Noch ein Hinweis vorab: Genau auf die Sekunde wirst den Lift-off der Rakete leider nicht treffen. Das liegt weniger an deinem Projekt, sondern daran, dass die meisten Raketen nicht ganz pünktlich sind. 😉 Zumindest haben wir bei unseren Tests beobachtet, dass der tatsächliche Start von der Angabe in der API immer um ein paar Sekunden abweicht.

Grundlegende Tutorials

In diesem Projekt kommt einiges zum Einsatz, für das du auf Pollux Labs passende Tutorials findest:

Schaue zunächst in die oben genannten Tutorials, wenn du ein paar der Themen noch nicht kennst oder erfahren möchtest, wie du ein 7-Segment Display oder den NeoPixel LED-Ring anschließt.

Im Folgenden konzentrieren wir uns auf den Start der nächsten Rakete von SpaceX – bzw. auf die Daten, die du hierfür benötigst.

Die SpaceX API

SpaceX betreibt eine sehr große Datenbank, aus der du dich kostenlos bedienen darfst. Hier findest du beispielsweise Daten zu Raketen, Modulen und Startrampen – aber natürlich auch zu vergangenen und kommenden Raketenstarts. Du findest sogar die aktuelle Position des Tesla Roadsters, der in den Orbit geschossen wurde.

SpaceX Roadster im Orbit
Foto: SpaceX

All diese Daten kannst du über eine API abrufen und weiterverarbeiten – und zwar auch mit deinem ESP8266. Für dieses Projekt benötigst du also die Daten zum nächsten Raketenstart. Diese findest du unter folgender Adresse:

https://api.spacexdata.com/v4/launches/next

Wenn du diese URL in deinem Browser aufrufst, findest eine ganze Menge Daten im JSON-Format. Unter anderem auch den Zeitpunkt des nächsten SpaceX-Starts als Unixzeit. In diesem Fall der 24.3.2021 um 9:58 MEZ.

"date_unix":1616576280

Diese URL verwendest du in deinem Sketch, um mit Hilfe der aktuellen Uhrzeit die Dauer bis zum nächsten Start – und somit den Countdown – zu berechnen.

Die Daten abrufen

Du findest den gesamten Sketch am Ende des Projekts. An dieser Stelle steigen wir direkt beim Abruf der Daten von der SpaceX API ein.

Hierfür hinterlegst du zunächst zu Beginn des Sketchs die URL der API und den Port, der für die sichere Übertragung via HTTPS zuständig ist: 443.

const char* host = "https://api.spacexdata.com/v4/launches/next";
const int httpsPort = 443;

Als nächstes kommt der Loop. Hier erstellst du zunächst die Instanz http von HTTPClient und verbindest dich mit der API:

HTTPClient http;
client.connect(host, httpsPort);
http.begin(client, host);

Danach prüfst du, ob die Verbindung steht und speicherst die JSON-Daten, die du von der API erhältst, in der Variablen payload. Anschließend dekodierst du sie und „ziehst“ dir die oben genannte Zeitangabe als Unixtime. Diese Zeitangabe speicherst du in der Variablen launchTime.

if (http.GET() == HTTP_CODE_OK) {
  String payload = http.getString();
  DynamicJsonDocument doc(3072);
  deserializeJson(doc, payload);

  launchTime = doc["date_unix"]; //Startzeit speichern

Als nächstes berechnest du den Countdown. Hierfür benötigst du natürlich auch die aktuelle Uhrzeit. Diese hast du weiter oben im Sketch schon ermittelt und in der Variablen currentTime gespeichert (Schaue hierfür in den vollständigen Sketch).

countdown = launchTime - currentTime;

Den SpaceX Countdown anzeigen

Jetzt lässt du deinen Countdown laufen, bis die Startzeit erreicht wurde:

while (countdown != 0) {

Du zeigst zunächst die Sekunden, die es noch bis zum Start dauert, auf dem Display an. Hier kommt eine Funktion ins Spiel, die du im vollständigen Sketch findest:

drawDigits(countdown);

Danach ziehst du vom Wert in der Variablen countdown eine Sekunde ab und wartest mit deinem delay auch genau diese eine Sekunde, bevor du die nächste Zahl anzeigst.

countdown -= 1;
delay(1000);

Wenn der While-Loop ausgelaufen ist, die Variable countdown also eine Null enthält, löschst du das Display, startest dafür den LED-Ring und lässt ihn z.B. eine halbe Stunde angeschaltet.

lc.clearDisplay(0);

for (int i = 0; i < 12; i++) {
  pixels.setPixelColor(i, pixels.Color(255, 0, 0));
  pixels.show();
  delay(1);
}

delay(1800000); //30 Minuten

In diesem Beispiel leuchten alles LEDs auf dem Ring in einem satten Rot auf. Du kannst dir aber natürlich auch etwas raffinierteres überlegen!

Spacex Countdown ESP8266
Ein möglicher Aufbau für das Projekt

Und das war es auch schon! Zuletzt noch ein Hinweis: Wenn dein Delay am Ende des Sketchs ausgelaufen ist, folgt die nächste Abfrage der SpaceX API. Möglicherweise liegen dann aber noch keine neuen Daten vor. Bis das soweit ist, kann es mitunter einige Stunden oder auch Tage dauern – du könntest deinen ESP8266 also auch erst einmal gar keine neue Abfrage stellen lassen.

Sketch als .txt anschauen

#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecure.h>

WiFiClientSecure client;

//NTP
#include <NTPClient.h>
#include <WiFiUdp.h>
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);

//SpaceX API URL und Port
const char* host = "https://api.spacexdata.com/v4/launches/next";
const int httpsPort = 443;

//WLAN Zugangsdaten
const char* ssid = "NETWORK";
const char* password =  "PASSWORD";

//Variablen
long launchTime;
long currentTime;
long countdown;

//7-Segment-Display
#include <LedControl.h>
LedControl lc = LedControl(12, 15, 13, 1); //12=D6=DIN, 15=D8=CLK, 13=D7=CS
const int NUM_DIGITS = 8;

//NeoPixel LED-Ring
#include <Adafruit_NeoPixel.h>

int leds = 12; //Anzahl der LEDs
int ledPin = 14; //14=D5, Pin, an dem der NeoPixel angeschlossen ist

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(leds, ledPin, NEO_GRB + NEO_KHZ800);

void getCurrentTime() {

  timeClient.update();
  currentTime = timeClient.getEpochTime();
  
  Serial.print("Current Time= ");
  Serial.println(currentTime);
}

void drawDigits(int num) {
  for (int i = 0; i < NUM_DIGITS ; i++) {
    lc.setDigit(0, i, num % 10, false);
    num /= 10;
    if (num == 0)
      return;
  }
}

void setup() {
  Serial.begin(115200);
  client.setInsecure();

  //Einstellungen des 7-Segment-Displays
  lc.shutdown(0, false);
  lc.setIntensity(0, 8);
  lc.clearDisplay(0);

  //Einstellungen des NeoPixels
  pinMode (ledPin, OUTPUT);
  pixels.begin();
  pixels.setBrightness(255); //Helligkeit: 0 (aus) - 255

  for (int i = 0; i < 12; i++) {
    pixels.setPixelColor(i, pixels.Color(0, 0, 0));
    pixels.show();
    delay(1);
  }

  WiFi.begin(ssid, password); //Mit dem WLAN verbinden

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  delay(1000);
  Serial.println("Hello, world!");
}

void loop() {
  if ((WiFi.status() == WL_CONNECTED)) {

    getCurrentTime();

    HTTPClient http;
    client.connect(host, httpsPort);
    http.begin(client, host);

    if (http.GET() == HTTP_CODE_OK) {
      String payload = http.getString();
      DynamicJsonDocument doc(3072);
      deserializeJson(doc, payload);

      launchTime = doc["date_unix"]; //Startzeit speichern
      Serial.print("Launch Time: ");
      Serial.println(launchTime);

      countdown = launchTime - currentTime; //Countdown = Startzeit - aktuelle Zeit
    } else {
      Serial.print("Error on HTTP request (SpaceX): ");
      Serial.println(http.GET()); //Error Code
    }
  }

  while (countdown != 0) { //Solange die Startzeit nicht erreicht wurde
    Serial.print("Time Until Launch: ");
    Serial.println(countdown);
    drawDigits(countdown);
    countdown -= 1;
    delay(1000);
  }

  Serial.println("LAUNCH!"); // Startzeit = aktuelle Zeit
  lc.clearDisplay(0);

  for (int i = 0; i < 12; i++) {
    pixels.setPixelColor(i, pixels.Color(255, 255, 0));
    pixels.show();
    delay(1);
  }

  delay(1800000);
}
]]>
Gute oder schlechte Nachrichten? Mit einer Sentimentanalyse findest du es heraus. https://polluxlabs.net/esp8266-projekte/pruefe-die-nachrichten-mit-einer-sentimentanalyse/ Mon, 23 Nov 2020 17:12:21 +0000 https://polluxlabs.net/?p=4243 In diesem Projekt lädst du dir mit einem ESP32 aktuellen Schlagzeilen aus dem Internet und findest mit einer Sentimentanalyse heraus, ob sie positiv oder negativ sind. Ein NeoPixel LED-Ring zeigt dir dann an, ob die Nachrichtenlage gerade gut (grün), schlecht (rot) oder etwas dazwischen ist.

Fortgeschrittene

1 – 2 Stunden

ca. 12 €

Für dieses Projekt benötigst du (Mengen s. Beschreibung):

Die Basics

Vieles, was in diesem Projekt zum Einsatz kommt, haben wir bereits in Tutorials beschreiben. Wenn du etwas davon noch nicht kennst, wirf zunächst dort einen Blick hinein:

Im Folgenden konzentrieren wir uns darauf, mit einer Sentimentsanalyse herauszufinden, ob eine Nachricht gut oder schlecht ist – und das dann mit dem NeoPixel anzuzeigen.

Was ist eine Sentimentanalyse?

Für einen Menschen ist es normalerweise kein Problem zu beurteilen, ob die Stimmung (Sentiment) einer Aussage positiv, negativ oder irgendetwas dazwischen ist. Für einen Computer ist das etwas schwieriger, aber trotzdem möglich – mit den richtigen Algorithmen und Wörterbüchern.

Hierfür liest der Computer einen Text ein und beurteilt die Wörter und Wortzusammenhänge, die er dort vorfindet. Im Hintergrund steckt immer ein Wörterbuch, in dem Begriffe von Menschen bewertet wurden: Pech und Trauer sind negative Begriffe, Glück und Positiv hingegen – positive.

Aber so einfach ist es leider nicht: Oft steckt die Bedeutung einer Aussage nicht in einem einzelnen Wort, sondern in einer Wendung, die aus mehreren Wörtern besteht. Positiv mag zwar in den meisten Fällen etwas Gutes sein, wenn jedoch jemand auf ein Virus positiv getestet wurde, ist genau das Gegenteil der Fall.

Mehr über dieses spannende Thema findest du auf Wikipedia.

Der Aufbau des Projekts

Du musst im Prinzip nur deinen NeoPixel mit deinem ESP32 wie folgt verbinden:

NeoPixelESP32
VCC3v3
GNDGND
DI14

Natürlich kannst du hierfür einfach ein Breadboard verwenden. Etwas mehr Stimmung verleihst du mit einer Kugel und einem Sockel aus dem 3D-Drucker. Passende Plastikkugeln* findest du für wenig Geld im Bastelladen oder auf Amazon.

Die Schlagzeilen laden

Für dieses Projekt lädst du dir zunächst die aktuellen Schlagzeilen von einer kostenlosen API. Hierfür bietet sich der Service newsapi.org an. Erstelle dir dort zunächst einen kostenlosen Account, um deinen API Key zu erhalten, den du für die Abfrage der Nachrichten benötigst.

Danach kannst du z.B. länderspezifische Top Headlines abfragen, die dir als JSON zur Verfügung gestellt werden. Du kannst die Nachrichten jedoch auch nach Ländern, Suchbegriffen und Quellen filtern. Da die Sentimentanalyse, die wir später verwenden, kein Deutsch versteht, verwenden wir hier die Top Headlines der USA.

Die URL für den API Call lautet dann wie folgt – wobei du <<API-KEY>> durch deinen eigenen API Key ersetzen musst.

http://newsapi.org/v2/top-headlines?country=us&apiKey=<<API-KEY>>

Mit dieser Abfrage erhält dein ESP32 Daten im JSON-Format, die er – wie im oben genannten Tutorial beschrieben – mit der Bibliothek ArduinoJson verarbeiten und der Sentimentanalyse weitergeben kann.

Übrigens: Wenn du die aktuellen Nachrichten zum Corona-Virus analysieren möchtest, verwende die folgende URL (Covid ist in englischen Medien gängiger als Corona).

http://newsapi.org/v2/everything?q=covid&apiKey=<<API-KEY>>

Die Stimmung der Schlagzeilen bestimmen

Hier kommt eine weitere kostenlose API ins Spiel: meaningcloud.com – auch hier benötigst du einen kostenlosen Developer Account, der dir eine begrenzte (aber hier ausreichende) Anzahl von Abfragen zur Verfügung stellt. Für diesen Service benötigst du ebenfalls einen API Key, den du in der Abfrage-URL hinterlegen musst.

Diese URL sieht folgendermaßen aus:

http://api.meaningcloud.com/sentiment-2.1?key=<<API-KEY>>&of=json&txt=<<TEXT>>&lang=en

Wie du siehst, übergibst du die Schlagzeilen von newsapi.org in der URL an die API. Diese steckt in der Variable article, allerdings mit Leerzeichen zwischen den Wörtern, was in einer URL natürlich nicht funktioniert. Deshalb ersetzt du diese Leerzeichen wie folgt durch ein %20:

article.replace(" ", "%20");

Nun kannst du die URL für die Sentimentanalyse flexibel zusammenbauen:

http://api.meaningcloud.com/sentiment-2.1?key=<<API-KEY>>&of=json&txt=" + article + "&lang=en

Im Sketch passiert das in einem For-Loop insgesamt 15 Mal – für die 15 neuesten Schlagzeilen.

Die Ergebnisse der Sentimentanalyse

Jetzt wird es spannend: Die API spielt eine ganze Menge Daten im JSON-Format zurück, in denen uns hier aber nur die Stimmung der Schlagzeile interessiert. Hierfür gibt es fünf Werte:

Sehr positivP+
PositivP
NeutralNEU
NegativN
Sehr negativN+

Darüberhinaus gibt es noch den Wert NONE – falls keine Stimmung ermittelt werden konnte. Jedem dieser Werte ordnest du im Sketch eine Zahl zu: von 2 für P+ bis zu -2 für N+. Hier das Beispiel für eine sehr positive Schlagzeile:

if (score_tag == "P+") {
  sentiment += 2;
}

Diese Zahlen addierst du miteinander und erhältst dadurch einen Wert – den aktuellen Zustand der Welt. 😉

Den Gesamtwert als Farbe ausgeben

Theoretisch könnte sich der Gesamtwert der 15 Schlagzeilen zwischen -30 und +30 bewegen. In den meisten Fällen reicht jedoch eine Skala von -5 bis +5.

Diesen 11 Werten innerhalb der Skala ordnest du Farben zu, die du als RGB-Werte anlegst – und lässt deinen NeoPixel LED-Ring dann in der Farbe des Gesamtwerts leuchten. Wir haben uns für ein Farbspektrum von Rot zu Grün entschieden – mit Gelb in der Mitte für den neutralen Wert Null:

int minus5[] = {255, 0, 0};
int minus4[] = {255, 51, 0};
int minus3[] = {255, 102, 0};
int minus2[] = {255, 153, 0};
int minus1[] = {255, 204, 0};
int neutral[] = {255, 255, 0};
int plus1[] = {204, 255, 0};
int plus2[] = {153, 255, 0};
int plus3[] = {102, 255, 0};
int plus4[] = {51, 255, 0};
int plus5[] = {0, 255, 0};

Wenn du selbst die Farben bestimmten möchtest, eignet sich hierfür der Color Picker von Google.

Im Sketch fehlt nun nur noch etwas Code, um entsprechend des Gesamtwerts der Sentimentanalyse eine Farbe auszugeben. Für den Wert -4 zum Beispiel:

switch (sentiment) {
  case -4:
    for (int i = 0; i < 12; i++) {
      pixels.setPixelColor(i, minus4[0], minus4[1], minus4[2]);
      pixels.show();
    }
    break;

Alle Werte von -5 und darunter (sowie +5 und darüber) fängst du davor schon mit einer If-Abfrage ab:

if (sentiment <= -5) {
  for (int i = 0; i < 12; i++) {
    pixels.setPixelColor(i, minus5[0], minus5[1], minus5[2]);
    pixels.show();
  }

Ganz am Ende des Sketchs fügst du noch einen Delay ein, der bestimmt, wann die nächste Abfrage der Schlagzeilen und die Sentimentanalyse erfolgen soll – z.B. alle 30 Minuten:

delay(1800000);

Hier nun der gesamte Sketch:

Sketch als .txt anschauen

//Libraries
#include <ArduinoJson.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <Adafruit_NeoPixel.h>

//Pin for the NeoPixel
int ledPin = 14;

//Initiate NeoPixel
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(12, ledPin, NEO_GRB + NEO_KHZ800);

//Colors
int minus5[] = {255, 0, 0};
int minus4[] = {255, 51, 0};
int minus3[] = {255, 102, 0};
int minus2[] = {255, 153, 0};
int minus1[] = {255, 204, 0};
int neutral[] = {255, 255, 0};
int plus1[] = {204, 255, 0};
int plus2[] = {153, 255, 0};
int plus3[] = {102, 255, 0};
int plus4[] = {51, 255, 0};
int plus5[] = {0, 255, 0};


// WiFi Credentials
const char* ssid = "WiFi SSID";
const char* password =  "PASSWORD";

String article;
int sentiment = 0;

void getSentiment() {

  HTTPClient http;

  http.begin("http://api.meaningcloud.com/sentiment-2.1?key=<<API-KEY>>&of=json&txt=" + article + "&lang=en");

  int httpCode = http.GET();

  if (httpCode == 200) {

    String payload = http.getString();

    const size_t capacity = 2*JSON_ARRAY_SIZE(0) + 7*JSON_ARRAY_SIZE(1) + 5*JSON_ARRAY_SIZE(2) + 2*JSON_ARRAY_SIZE(3) + JSON_ARRAY_SIZE(4) + 2*JSON_ARRAY_SIZE(5) + 2*JSON_ARRAY_SIZE(6) + JSON_ARRAY_SIZE(7) + 25*JSON_OBJECT_SIZE(4) + 4*JSON_OBJECT_SIZE(6) + 22*JSON_OBJECT_SIZE(7) + JSON_OBJECT_SIZE(8) + 2*JSON_OBJECT_SIZE(9) + 3*JSON_OBJECT_SIZE(10) + JSON_OBJECT_SIZE(11) + 3500;

    DynamicJsonDocument doc(capacity);

    DeserializationError error = deserializeJson(doc, payload, DeserializationOption::NestingLimit(11));

    if (error) {
      Serial.print(F("deserializeJson() Error: "));
      Serial.println(error.c_str());
      return;
    }

    JsonObject status = doc["status"];
    String score_tag = doc["score_tag"];

    Serial.println(score_tag);

    if (score_tag == "P+") {
      sentiment += 2;
    }
    else if (score_tag == "P") {
      sentiment += 1;
    }
    else if (score_tag == "N") {
      sentiment -= 1;
    }
    else if (score_tag == "N+") {
      sentiment -= 2;
    }
  }

  else {
    Serial.println("Bad HTTP Request");
  }
  http.end();
}

void setup() {
  pixels.begin();
  pixels.setBrightness(175);

  pinMode (14, OUTPUT); //LED Pin


  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting...");
  }
  Serial.println("Connected!");
}

void () {

  //reset sentiment count
  sentiment = 0;

  if ((WiFi.status() == WL_CONNECTED)) {

    HTTPClient http;

    http.begin("http://newsapi.org/v2/top-headlines?country=us&apiKey=<<API-KEY>>");

    int httpCode = http.GET();

    if (httpCode == 200) {

      String payload = http.getString();

      const size_t capacity = JSON_ARRAY_SIZE(20) + 20 * JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + 20 * JSON_OBJECT_SIZE(8) + 16600;
      DynamicJsonDocument doc(capacity);

      DeserializationError error = deserializeJson(doc, payload);

      if (error) {
        Serial.print(F("deserializeJson() Error: "));
        Serial.println(error.c_str());
        return;
      }

      //Save number of headlines
      int noHeadlines = doc["totalResults"];

      //Loop through headlines & get sentiment
      for (int i = 0; i < 15; i++) {

        //Get Headlines from Newsapi
        JsonArray articles = doc["articles"];

        JsonObject articles_number = articles[i];

        const char* articles_number_title = articles_number["title"];

        article = String(articles_number_title);
        Serial.println(article);
        
        article.replace(" ", "%20");
        Serial.println(article);

        getSentiment();
      }
      
      Serial.println("Loop done.");
      Serial.println(sentiment);

      //Show state on NeoPixel
      if (sentiment <= -5) {
        for (int i = 0; i < 12; i++) {
          pixels.setPixelColor(i, minus5[0], minus5[1], minus5[2]);
          pixels.show();
        }
      } else if (sentiment >= 5) {
        for (int i = 0; i < 12; i++) {
          pixels.setPixelColor(i, plus5[0], plus5[1], plus5[2]);
          pixels.show();
        }
      }

      switch (sentiment) {
        case -4:
          for (int i = 0; i < 12; i++) {
            pixels.setPixelColor(i, minus4[0], minus4[1], minus4[2]);
            pixels.show();
          }
          break;
        case -3:
          for (int i = 0; i < 12; i++) {
            pixels.setPixelColor(i, minus3[0], minus3[1], minus3[2]);
            pixels.show();
          }
          break;
        case -2:
          for (int i = 0; i < 12; i++) {
            pixels.setPixelColor(i, minus2[0], minus2[1], minus2[2]);
            pixels.show();
          }
          break;
        case -1:
          for (int i = 0; i < 12; i++) {
            pixels.setPixelColor(i, minus1[0], minus1[1], minus1[2]);
            pixels.show();
          }
          break;
        case 0:
          for (int i = 0; i < 12; i++) {
            pixels.setPixelColor(i, neutral[0], neutral[1], neutral[2]);
            pixels.show();
          }
          break;
        case 1:
          for (int i = 0; i < 12; i++) {
            pixels.setPixelColor(i, plus1[0], plus1[1], plus1[2]);
            pixels.show();
          }
          break;
        case 2:
          for (int i = 0; i < 12; i++) {
            pixels.setPixelColor(i, plus2[0], plus2[1], plus2[2]);
            pixels.show();
          }
          break;
        case 3:
          for (int i = 0; i < 12; i++) {
            pixels.setPixelColor(i, plus3[0], plus3[1], plus3[2]);
            pixels.show();
          }
          break;
        case 4:
          for (int i = 0; i < 12; i++) {
            pixels.setPixelColor(i, plus4[0], plus4[1], plus4[2]);
            pixels.show();
          }
          break;
      }
    }

    else {
      Serial.println("Bad HTTP Request");
    }

    http.end();
    Serial.println("Connection closed.");
  }
  //Wait for 30 minutes until next call
  delay(1800000);
}

Wie geht es weiter?

Hast du Lust auf mehr Daten und mehr Beleuchtung? In diesem Projekt baust du einen Würfel, der beginnt zu leuchten, wenn die International Space Station über ihm fliegt.

]]>
Beleuchte deine LEGO Mondlandefähre, wenn der Mond am Himmel steht https://polluxlabs.net/esp8266-projekte/beleuchte-deine-lego-mondlandefaehre-wenn-der-mond-am-himmel-steht/ Wed, 18 Nov 2020 14:13:52 +0000 https://polluxlabs.net/?p=4188

Du hast eine LEGO Mondlandefähre (Apollo 11 Lunar Lander), aber dir fehlt noch die richtige Beleuchtung? In diesem Projekt verbaust du unter der Landefähre einen LED-Ring, den du mit einem ESP8266 anschaltest, sobald der Mond aufgeht – und wieder ausschaltest, nachdem der Mond untergegangen ist.

Anfänger

1 – 2 Stunden

ca. 15 € + LEGO Mondlandefähre

Für dieses Projekt benötigst du (Mengen s. Beschreibung):

In diesem Projekt lernst du, wie du einen NeoPixel LED-Ring verwendest, die aktuelle Uhrzeit per WLAN abrufst und, am wichtigsten: herausfindest, ob der Mond bereits aufgegangen ist oder nicht.

lego lunar lander cover

Der Aufbau

Du benötigst nur wenige Bauteile, die du schnell miteinander verbunden hast. Die NeoPixel LED-Ringe werden meistens unverlötet geliefert, d.h. du musst zunächst drei Kabel an die Pins GND, VCC und DI löten.

Lege nun den Ring in die runde Aussparung (Krater?) der Bodenplatte. Diese eignet sich perfekt, um den NeoPixel unterzubringen. Wenn du vom Rand der Aussparung ein Teil entfernst, kannst du die drei Kabel hier unauffällig durchführen:

Verbinde deinen NeoPixel anschließend mit deinem ESP8266 wie folgt:

NeoPixelESP8266
GNDGND
VCC3v3
DID5

Der Sketch für die Beleuchtung der Mondlandefähre

Viele der Themen, die im folgenden Sketch wichtig sind, haben wir bereits in anderen Tutorials behandelt:

Falls du hiermit noch nicht vertraut bist, wirf dort zunächst einen Blick rein.

Steht der Mond am Himmel?

Schauen wir uns das Kernstück des Sketchs an: Um herauszufinden, ob der Mond bereits aufgegangen ist, verwendest du die Bibliothek MoonRise.h. Diese findest du wie du es von anderen Bibliotheken gewohnt bist, im Bibliotheksmanager.

Der große Vorteil dieser Bibliothek ist es, dass sie anhand deiner Koordinaten und des Zeitunterschieds zur Koordinierten Weltzeit (UTC) die Monddaten auf deinem ESP8266 berechnet. Du benötigst hier also keine API-Abfragen oder ähnliches.

Binde also zunächst die Bibliothek MoonRise.h am Anfang deines Sketchs ein und hinterlege deine Koordinaten sowie den Zeitunterschied zur UTC in Stunden. Hier das Beispiel für Karlsruhe in der Winterzeit:

#include <MoonRise.h>
const float latitude = 49.00;
const float longitude = 8.40;
const int offset = 1;

Anschließend benötigst du zwei Variablen: Eine für die aktuelle Uhrzeit und eine für den Zustand Mond sichtbar/nicht sichtbar.

long currentTime;
bool moonVisible;

Danach erstellst du das Objekt mr der Bibliothek MoonRise:

MoonRise mr;

Das war es auch schon mit den Vorbereitungen. Fehlen nur noch zwei Zeilen Code, um herauszufinden, ob der Mond am Himmel steht.

 mr.calculate(latitude, longitude, currentTime + offset);
 moonVisible = mr.isVisible;

Mit der Funktion mr.calculate berechnest du anhand deiner Koordinaten, der aktuellen Uhrzeit und des Zeitunterschieds den Stand des Monds. Ob der Mond von deinem Standort aus sichtbar ist, erfährst du mit der Funktion mr.isVisible. Das Ergebnis – entweder 1 oder 0 – speicherst du in der Variablen moonVisible.

Übrigens: Die Bibliothek hat noch weitere Funktionen. Mehr darüber erfährst du auf Github.

Schalte den NeoPixel ein

Solange in der Variablen moonVisible eine 0 gespeichert ist – der Mond also noch nicht sichtbar ist – bleibt der LED-Ring ausgeschaltet. Sobald dort jedoch eine 1 seht, beginnt er, deine LEGO Mondlandefähre zu beleuchten. Das machst du mit folgendem Code:

if (moonVisible) {
  for (int j = 0; j < 12; j++) {
    pixels.setPixelColor(j, pixels.Color(237, 235, 28));
    pixels.show();
  }
} else {
  for (int j = 0; j < 12; j++) {
    pixels.setPixelColor(j, LOW);
    pixels.show();
  }
}

Wie du siehst, schaltest du in einem For-Loop alle 12 LEDs hintereinander ein bzw. aus. In der Funktion pixels.Color() kannst du die Farbe des Lichts bestimmen – in unserem Fall ein warmes Weiß. Du kannst alle möglichen anderen Farben wählen, indem du z.B. den Color Picker von Google verwendest.

Zuletzt legst du noch einen Delay fest, der bestimmt, in welchen Abständen du berechnest, ob der Mond am Himmel sichtbar ist. Im folgendem Fall alle 100 Sekunden:

delay(100000);

Hier nun der vollständige Sketch:

Sketch als .txt anschauen

/*********
  Frederik Kumbartzki
  Complete project details at https://polluxlabs.net
*********/

//WI-FI Credentials
const char* ssid = "YOUR WI-FI NETWORK";
const char* password =  "YOUR PASSWORD";

//Coordinates
const float latitude = 00.00; //Your Latitude
const float longitude = 00.00; //Your Longitude
const int offset = 0; //Your offset to UTC in hours

#include <MoonRise.h> //MoonRise Library
#include <ESP8266WiFi.h> //Wi-Fi

//Get time
#include <NTPClient.h>
#include <WiFiUdp.h>

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");

#include <Adafruit_NeoPixel.h> //NeoPixel

//Times and Durations
long currentTime;
bool moonVisible;

//Moonrise Library
MoonRise mr;

//Initiate NeoPixel
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(12, 14, NEO_GRB + NEO_KHZ800); //14 = Pin D5 on the board

void setup() {

  pixels.begin();
  pixels.setBrightness(250); //NeoPixel Brightness: 0-255

  Serial.begin(115200); //Start Serial Monitor
  WiFi.begin(ssid, password); //Go online

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting...");
  }

  delay(1000);
  Serial.println("Hello, world!");

  timeClient.begin();
}

void loop() {

  timeClient.update();

  currentTime = timeClient.getEpochTime();

  Serial.print(currentTime);
  Serial.print(" - ");

  Serial.print("moon visible: ");
  Serial.println(moonVisible);

  mr.calculate(latitude, longitude, currentTime + offset); //Calculate Moonrise
  moonVisible = mr.isVisible; //1 if Moon is visible, 0 if not

  if (moonVisible) {
    for (int j = 0; j < 12; j++) { //Light up all 12 LEDs on NeoPixel
      pixels.setPixelColor(j, pixels.Color(237, 235, 28)); //Set NeoPixel color in RGB
      pixels.show();
    }
  } else {
    //Turn off NeoPixel if Moon isn't visible
    for (int j = 0; j < 12; j++) {
      pixels.setPixelColor(j, LOW);
      pixels.show();
    }
  }
  delay(100000); //Wait until next query
}

Wie geht es weiter?

LEGO beleuchten ist das Richtige für dich? Dann probiere etwas ähnliches mit der LEGO ISS, die anfängt zu leuchten, wenn die echte ISS über ihr fliegt.

]]>
Das Licht ein- und ausschalten mit Telegram https://polluxlabs.net/esp8266-projekte/das-licht-ein-und-ausschalten-mit-telegram/ Wed, 11 Nov 2020 07:11:02 +0000 https://polluxlabs.net/?p=4091 In diesem Projekt lernst du, wie du von deinem Smartphone aus eine Lichtquelle ein- und ausschalten kannst. Außerdem kannst du von dort aus abfragen, ob das Licht gerade an oder aus ist.

Für einen ersten Test verwendest du eine LED, die du an deinem ESP8266 anschließt. Wenn du später möchtest – und vorausgesetzt, du fühlst dich damit sicher – kannst du dich einer „richtigen“ Lampe zuwenden. Hierfür benötigst du dann ein Relais, das du per Telegram steuert und das wiederum den Stromkreis der Lampe öffnet und schließt.

Dieses Projekt ist der vierte Teil einer Serie und baut auf die Vorgängerprojekte auf. In diesem Artikel findest du alles zum Aufbau und den passenden Sketch; wir besprechen jedoch nicht alle Teile des Codes. Wenn du mehr Details erfahren möchtest, wirf bitte einen Blick in die folgenden Projekte:

  1. Ein stiller Alarm mit Telegram und einem ESP8266
  2. Überwache die Temperatur mit Telegram und einem ESP8266
  3. Die aktuelle Temperatur per Telegram abfragen

Falls du noch kein Projekt mit Telegram gebaut hast, lerne zunächst, wie du einen Telegram-Bot erstellst.

Anfänger

1 – 2 Stunden

ca. 10 €

Für dieses Projekt benötigst du (Mengen s. Beschreibung):

Der Aufbau des Projekts

Du benötigst für dieses Projekt deinen ESP8266, eine LED samt Widerstand (z.B. 220 Ohm), ein Breadboard und Kabel. Orientiere dich an folgendem Schema:

Aufbau LED steuern

Wie du oben siehst, verbindest du die Anode (langes Bein) der LED mit dem Pin D5 an deinem ESP8266. Die Kathode (kurzes Bein) verbindest du über einen Widerstand mit GND.

Der Sketch

Kopiere den folgenden Sketch in deine Arduino IDE, ergänze deine Daten und lade ihn auf deinen ESP8266.

Sketch als .txt anschauen

/*
   Das Licht ein- und ausschalten mit Telegram - polluxlabs.net
*/

//Bibliotheken
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>

// Deine WLAN-Zugangsdaten
const char* ssid = "NETZWERK";
const char* password = "PASSWORT";

// Den Telegram-Bot initialisieren
#define botToken "TOKEN"  // den Bot-Token bekommst du vom Botfather)

//Deine UserID
#define userID "USERID"

WiFiClientSecure client;
UniversalTelegramBot bot(botToken, client);

//Variable für das Licht
const int lightPin = 14; //Am ESP8266 Pin D5
bool lightState = LOW;

//Variable für die Anzahl der Anfragen
int numNewRequests;

//Variable für den Text der Anfrage, die du sendest
String text = "";

//UserID des Absenders
String chat_id = "";

//Name des Absenders
String from_name = "";

//Variable für die Willkommensnachricht
String welcome = "";

//Funktion fürs Verarbeiten neuer Anfragen
void handleNewRequests(int numNewRequests) {

  for (int i = 0; i < numNewRequests; i++) { //loopt durch die neuen Anfragen

    //Checkt, ob du die Anfrage gesendet hast oder jemand anderes
    chat_id = String(bot.messages[i].chat_id);
    if (chat_id != userID) {
      bot.sendMessage(chat_id, "Du bist nicht autorisiert!", "");
      continue;
    }

    // Anfragetext speichern
    text = bot.messages[i].text;
    Serial.println(text);

    from_name = bot.messages[i].from_name;

    if (text == "/start") {
      welcome = "Willkommen, " + from_name + ".\n";
      welcome += "Folgende Befehle kannst du verwenden: \n\n";
      welcome += "/lichtEin \n";
      welcome += "/lichtAus \n";
      welcome += "/status \n";
      bot.sendMessage(chat_id, "http://gph.is/1Rc70ke", "");
      bot.sendMessage(chat_id, welcome, "");
    }

    if (text == "/lichtEin") {
      lightState = HIGH;
      digitalWrite(14, lightState);
      bot.sendMessage(chat_id, "Das Licht ist an.", "");
    }

    if (text == "/lichtAus") {
      lightState = LOW;
      digitalWrite(14, lightState);
      bot.sendMessage(chat_id, "Das Licht ist aus.", "");
    }

    if (text == "/status") {
      if (digitalRead(lightPin)) {
      bot.sendMessage(chat_id, "Das Licht ist an.", "");
      }
      else {
        bot.sendMessage(chat_id, "Das Licht ist aus.", "");
      }
    }
  }
}

void setup() {

  Serial.begin(115200);
  client.setInsecure();

  pinMode(lightPin, OUTPUT);
  digitalWrite(lightPin, lightState);

  //Verbindung zum WLAN
  Serial.print("Verbinde mich mit: ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(300);
  }
  Serial.println("");
  Serial.println("Verbunden!");
}

void loop() {

  //checkt, ob eine neue Anfrage reinkam
  int numNewRequests = bot.getUpdates(bot.last_message_received + 1);

  while (numNewRequests) { //wird ausgeführt, wenn numNewRequests == 1
    Serial.println("Anfrage erhalten");
    handleNewRequests(numNewRequests);
    numNewRequests = bot.getUpdates(bot.last_message_received + 1);
  }
  delay(1000);
}

Was ist neu in diesem Sketch?

Viel musst du in deinem Code eigentlich nicht verändern, um statt der Temperaturabfrage das Licht ein- und auszuschalten. Werfen wir einen Blick auf die Details.

Zunächst benötigst du eine Konstante für den Pin, an dem die LED angeschlossen ist und eine Variable für den Zustand der LED – also ob sie an oder aus ist.

const int lightPin = 14; //Am ESP8266 Pin D5
bool lightState = LOW;

In der Setup-Funktion legst du den pinMode für den LED-Pin fest und weist der LED den Zustand zu, der in der Variablen lightState steht – also zu Beginn LOW – aus.

pinMode(lightPin, OUTPUT);
digitalWrite(lightPin, lightState);

Die Funktion handleNewRequests()

Diese Funktion kennst du ja bereits aus dem vorangegangenen Projekt. Hier werden deine Anfragen verarbeitet, die du von deinem Smartphone aus sendest.

Licht einschalten mit Telegram
Du kannst auch GIFs nutzen, sende dazu einfach die entsprechende URL. Im Sketch oben befindet sich schon eine.

In diesem Projekt gibt es drei Anfragen (oder Befehle), die du senden kannst: /lichtEin, /lichtAus und /status. Mit der letzten Anfrage fragst du ab, ob die LED gerade ein- oder ausgeschaltet ist und erhältst die entsprechende Antwort zurück.

Wenn du also deinem ESP8266 den Text /lichtEin sendest, setzt dieser die Variable lightState auf HIGH und schaltet die LED mit digitalWrite() ein. Zuletzt sendet er dir mit der bekannten Funktion bot.sendMessage() Feedback.

if (text == "/lichtEin") {
  lightState = HIGH;
  digitalWrite(14, lightState);
  bot.sendMessage(chat_id, "Das Licht ist an.", "");
}

Der Befehl /lichtAus funktioniert so ähnlich, nur dass er die LED natürlich ausschaltet. Wenn du /status sendest, prüft dein ESP8266, ob die LED ein- oder ausgeschaltet ist:

if (text == "/status") {
  if (digitalRead(lightPin)) {
  bot.sendMessage(chat_id, "Das Licht ist an.", "");
  }
  else {
    bot.sendMessage(chat_id, "Das Licht ist aus.", "");
  }
}

Wie geht es weiter?

Wie eingangs erwähnt, kannst du statt der LED ein Relais steuern. Je nachdem, welches Signal du diesem von deinem Smartphone aus sendest, öffnet und schließt das dann den Stromkreis eines anderen Geräts – z.B. einer Lampe oder einer Kaffeemaschine.

]]>
Video-Livestream mit der ESP32-CAM https://polluxlabs.net/arduino-tutorials/video-livestream-mit-der-esp32-cam/ Fri, 23 Oct 2020 06:23:00 +0000 https://polluxlabs.net/?p=3211 Mit der ESP32-CAM kannst du einfach und günstig deine Kameraprojekte umsetzen, wie z.B. unsere Fotofalle. Aber es müssen ja nicht immer nur Fotos sein – ein Video-Livestream geht auch!

In diesem Tutorial lernst du, wie du mit deiner ESP32-CAM einen Livestream aufsetzt, den du in deinem Browser aufrufen kannst. Hierfür benötigst du:

Vorbereitungen

Wenn du deine ESP32-CAM noch nie mit der Arduino IDE programmiert hast, musst du sie dort erst verfügbar machen. Da dieses Board keinen eigenen USB-Anschluss hat, benötigst du außerdem eine FTDI-Programmer, um deinen Sketch hochzuladen.

Wie beides funktioniert lernst du in diesem Tutorial hier bei uns. 🙂

Sobald die Verbindung von deinem Computer zur ESP32-CAM steht, kann es weitergehen.

Den Sketch hochladen

Die Konfiguration und das Hochladen des passenden Sketchs fallen in diesem Tutorial ziemlich angenehm aus: er befindet sich nämlich schon in deiner Arduino IDE. Wähle im Menü Datei -> Beispiele -> ESP32 -> Camera -> CameraWebServer. Daraufhin öffnet sich der Sketch, den du benötigst.

Zwei Kleinigkeiten musst du jedoch noch anpassen: Trage zunächst den Namen und das Passwort deines WLAN-Netzwerks ein.

Netzwerkdaten für den Videostream

Außerdem musst du noch das richtige Board auswählen. In unserem Fall (und in den meisten anderen Fällen auch) ist das AI Thinker. Lösche hierfür den Kommentar vor dem Board, sodass nur deines aktiv ist.

Board auswählen für den Video-Livestream

Lade nun den Sketch auf die ESP32-CAM. Vergiss nicht für den Upload die Pins IO0 und GND zu verbinden. Sobald der Code auf dem Board ist, trenne diese Verbindung wieder, starte deinen Seriellen Monitor und drücke zuletzt den RESET-Button auf dem Board.

Den Video-Livestream starten

Nun solltest du nach ein paar Sekunden (zwischenzeitliche Fehlermeldungen machen nichts) folgendes in deinem Seriellen Monitor sehen. Die IP-Adresse kann variieren.

Ausgabe im Seriellen Monitor

Klicke nun auf den Link oder kopiere dir die Adresse heraus und setze sie in deinem Browser ein. Du solltest nun auf der linken Seite eine ganze Reihe von Einstellungsmöglichkeiten sehen. Ganz unten befindet sich der Button Start Stream – ein Klick darauf startet den Stream.

Der Video-Livestream

Und das war es auch schon. Du kannst nun mit den Einstellungen experimentieren, um die bestmögliche Leistung zu erhalten. Außerdem hast du ganz unten auch die Option, eine Gesichtserkennung zu aktivieren, die wir hier jedoch nicht weiter behandeln.

Zwei Hinweise noch: Du kannst den Livestream nur aus deinem eigenen WLAN-Netz aus aufrufen. Dieses Tutorial ist zum Ausprobieren gedacht – wenn du die Kamera produktiv einsetzen möchtest, mache dir vorab Gedanken zur IT-Sicherheit.

]]>
Die aktuelle Temperatur per Telegram abfragen https://polluxlabs.net/esp8266-projekte/die-aktuelle-temperatur-per-telegram-abfragen/ Wed, 21 Oct 2020 19:01:15 +0000 https://polluxlabs.net/?p=3163 In diesem Projekt verwendest du Telegram, um bei deinem ESP8266 nachzufragen, wie hoch die aktuelle Temperatur ist. Sobald dein ESP8266 deine Anfrage erhalten hat, fragt er die aktuelle Temperatur beim Sensor BMP180 ab und sendet sie dir auf dein Smartphone.

Dieses Projekt ist der dritte Teil einer Serie und baut auf die Vorgängerprojekte auf. In diesem Artikel findest du alles zum Aufbau und den passenden Sketch; wir besprechen jedoch nicht alle Teile des Codes. Wenn du mehr Details erfahren möchtest, wirf bitte einen Blick in die folgenden Projekte:

  1. Ein stiller Alarm mit Telegram und einem ESP8266
  2. Überwache die Temperatur mit Telegram und einem ESP8266

Falls du noch kein Projekt mit Telegram gebaut hast, lerne zunächst, wie du einen Telegram-Bot erstellst.

Anfänger

1 – 2 Stunden

ca. 12 €

Für dieses Projekt benötigst du (Mengen s. Beschreibung):

Der Aufbau des Projekts

Wenn du das Vorgängerprojekt aufgebaut hast, dann musst du auf Seiten der Hardware nichts weiter tun – du kannst deinen Aufbau hier einfach weiterverwenden. 🙂

Aufbau des Temperatursensors

Im Sketch hat sich dafür einiges verändert:

Der Sketch

Kopiere den folgenden Sketch in deine Arduino IDE, ergänze deine Daten und lade ihn auf deinen ESP8266.

Sketch als .txt anschauen

/*
   Die Temperatur abfragen mit Telegram - polluxlabs.net
*/

//Bibliotheken
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>

#include <Wire.h>
#include <Adafruit_BMP085.h>

// Deine WLAN-Zugangsdaten
const char* ssid = "NETZWERKNAME";
const char* password = "PASSWORT";

// Den Telegram-Bot initialisieren
#define botToken "TOKEN"  // den Bot-Token bekommst du vom Botfather)

//Deine UserID
#define userID "USERID"

WiFiClientSecure client;
UniversalTelegramBot bot(botToken, client);

Adafruit_BMP085 bmp;

//Variable für die Temperatur
float temp;

//Variable für die Anzahl der Anfragen
int numNewRequests;

//Variable für den Text der Anfrage, die du sendest
String text = "";

//UserID des Absenders
String chat_id = "";

//Name des Absenders
String from_name = "";

//Variable für die Willkommensnachricht
String welcome = "";

//Funktion fürs Verarbeiten neuer Anfragen
void handleNewRequests(int numNewRequests) {

  for (int i = 0; i < numNewRequests; i++) { //loopt durch die neuen Anfragen

    //Checkt, ob du die Anfrage gesendet hast oder jemand anderes
    chat_id = String(bot.messages[i].chat_id);
    if (chat_id != userID) {
      bot.sendMessage(chat_id, "Du bist nicht autorisiert!", "");
      continue;
    }

    // Anfragetext speichern
    text = bot.messages[i].text;
    Serial.println(text);

    from_name = bot.messages[i].from_name;

    if (text == "/start") {
      welcome = "Willkommen, " + from_name + ".\n";
      welcome += "Mit folgendem Befehl fragst du die aktuelle Temperatur ab: \n\n";
      welcome += "/messen \n";
      bot.sendMessage(chat_id, welcome, "");
      bot.sendMessage(chat_id, "http://gph.is/2aLXZ8H", "");
    }

    if (text == "/messen") {
      temp = bmp.readTemperature();
      bot.sendMessage(chat_id, "Temperatur: " + String(temp) + " ºC", "");
    }
  }
}

void setup() {
  
  Serial.begin(115200);
  client.setInsecure();

  //Verbindung zum WLAN
  Serial.print("Verbinde mich mit: ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(300);
  }
  Serial.println("");
  Serial.println("Verbunden!");

  if (!bmp.begin()) {
    Serial.println("Kein Sensor gefunden! Checke die Verbindung.");
    while (1) {}
  }
}

void loop() {

  //checkt, ob eine neue Anfrage reinkam
  int numNewRequests = bot.getUpdates(bot.last_message_received + 1);

  while (numNewRequests) { //wird ausgeführt, wenn numNewRequests == 1
    Serial.println("Anfrage erhalten");
    handleNewRequests(numNewRequests);
    numNewRequests = bot.getUpdates(bot.last_message_received + 1);
  }
  delay(1000);
}

Was ist neu in diesem Sketch?

In diesem Sketch läuft einiges anders: In den zwei vorangegangenen Projekten hat dein ESP8266 nur Nachrichten gesendet, in diesem Projekt wartet er jedoch auf eine Nachricht von dir – die er dann selbst mit der aktuellen Temperatur beantwortet.

Dafür muss dein ESP8266 – im Gegensatz zu den vorherigen Projekten – die ganze Zeit mit deinem WLAN verbunden sein. Deshalb wandert der Code, mit dem du die Verbindung herstellst, direkt in die Setup-Funktion:

  Serial.print("Verbinde mich mit: ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(300);
  }
  Serial.println("");
  Serial.println("Verbunden!");

Schauen wir jetzt direkt in den Loop. Dort prüft dein ESP8266 alle 1000 Millisekunden, ob eine neue Anfrage vorliegt:

int numNewRequests = bot.getUpdates(bot.last_message_received + 1);

Wenn das der Fall ist, wird in der Variablen numNewRequests mithilfe der Funktion bot.getUpdates() die Anzahl der vorliegenden Anfragen gespeichert (im Normalfall eine 1, aber es können theoretisch ja auch mehrere vorliegen).

Das wiederum setzt den folgenden While-Loop in Gang, der die Funktion handleNewRequests() so oft aufruft wie Anfragen „abzuarbeiten“ sind. In diesem Loop wird auch die Variable numNewRequests aktualisiert – sobald hier wieder eine 0 enthalten ist, endet der Loop.

while (numNewRequests) {
  handleNewRequests(numNewRequests);
  numNewRequests = bot.getUpdates(bot.last_message_received + 1);
  }

Die Funktion handleNewRequests()

Kommen wir zum Kernstück des Sketchs. Diese Funktion handleNewRequests() erwartet bei Ihrem Aufruf ein Argument – nämlich die Anzahl der vorliegenden Anfragen, die in der Variablen numNewRequests steckt. Diese hast du beim Aufruf der Funktion im While-Lopp bereits mitgegeben:

handleNewRequests(numNewRequests);

Bei der Deklaration der Funktion taucht diese Variable wieder auf, um dann gleich weiterverarbeitet zu werden. Diesmal iterierst du mit einem For-Loop über die Anzahl der Anfragen, um sie eine nach der anderen abzuarbeiten:

void handleNewRequests(int numNewRequests) {
  for (int i = 0; i < numNewRequests; i++) { 

Innerhalb des Loops findet zuerst eine sehr wichtige Prüfung statt – nämlich ob die Anfrage überhaupt von einem autorisierten User (also von dir) stammt. Hierfür speicherst du die chat_id, die mit jeder Anfrage übergeben wird, in der gleichnamigen Variablen.

Anschließend prüfst du, ob diese mit deiner eigenen UserID übereinstimmt. Ist das nicht der Fall, erhält der Absender eine entsprechende Nachricht und der For-Loop wird mit continue abgebrochen:

chat_id = String(bot.messages[i].chat_id);
if (chat_id != userID) {
  bot.sendMessage(chat_id, "Du bist nicht autorisiert!", "");
  continue;
}

Wenn die Anfrage jedoch von dir stammt, speicherst du ihren Textinhalt und den Namen des Absenders (also wiederum deinen) ab:

text = bot.messages[i].text;
from_name = bot.messages[i].from_name;

Fehlen nur noch zwei If-Statements. Wenn du deinen Telegram-Bot zum ersten Mal startest, machst du das mit dem Text /start (den du natürlich auch senden kannst, wenn der Bot schon läuft). In diesem Fall erscheint eine kleine Begrüßungsnachricht mit einer Erklärung: Um die aktuelle Temperatur abzufragen, musst du deinem Bot (und damit deinem ESP8266) die Nachricht /messen schicken.

Begrüßung im Chat
Du kannst auch GIFs senden

Hier werden wieder Strings miteinander verbunden, diesmal mit dem Operator +=, der einfach die Variable welcome um weiteren Text erweitert. Auch beachtenswert: Mit \n kannst du einen Zeilenumbruch einfügen.

Am Ende des Statements findest du wieder die Funktion bot.sendMessage(), die du bereits kennengelernt hast. Diese taucht hier gleich zweimal auf: Einmal, um den String welcome zu senden und dann noch einmal, um ein GIF hinterherzuschicken. Wenn du spaßeshalber auch GIFs senden möchtest, reicht dafür einfach die entsprechende URL der Datei.

if (text == "/start") {
  welcome = "Willkommen, " + from_name + ".\n";
  welcome += "Mit folgendem Befehl fragst du die aktuelle Temperatur ab: \n\n";
  welcome += "/messen \n";
  bot.sendMessage(chat_id, welcome, "");
  bot.sendMessage(chat_id, "http://gph.is/2aLXZ8H", "");
}

Die zweite Abfrage kümmert sich um die Anfrage /messen, die mit der aktuellen Temperatur beantwortet werden soll. Auch das kennst du bereits aus den vorangegangenen Projekten:

if (text == "/messen") {
  temp = bmp.readTemperature();
  bot.sendMessage(chat_id, "Temperatur: " + String(temp) + " ºC", "");
}

Und das war es auch schon. Du hast in dieser Lektion gelernt, wie du nicht nur Nachrichten von deinem ESP8266 an deinen Telegram-Bot senden kannst, sondern auch von dort aus Sensordaten abrufen kannst.

Wie geht es weiter?

Du kannst natürlich nicht nur die Temperatur abfragen. Der Sensor BMP180 kann auch den Luftdruck ermitteln. Der Nachfolger BMP280 misst sogar die Luftfeuchtigkeit. Baue z.B. eine Wetterstation, bei der du die aktuellen Daten aus der Ferne abfragst.

Eine weitere Möglichkeit ist ein Feuchtigkeitssensor, den du neben eine Pflanze in die Erde steckst. Wenn du denkst, die Erde sei zu trocken, kannst du eine automatische „Gießkanne“ von deinem Smartphone aus steuern.

]]>
Überwache die Temperatur mit Telegram und einem ESP8266 https://polluxlabs.net/esp8266-projekte/ueberwache-die-temperatur-mit-telegram-und-einem-esp8266/ Mon, 19 Oct 2020 14:42:24 +0000 https://polluxlabs.net/?p=3147 In diesem Projekt überwachst du die Temperatur mit einem Sensor und deinem ESP8266. Sobald der Temperatursensor einen von dir festgelegten Wert ermittelt, sendet dein Microcontroller eine Nachricht an deinen Telegram-Bot.

Dieses Projekt ist der zweite Teil einer Serie: Inhaltlich baut es auf unserem Stillen Alarm mit Telegram auf. Schaue dort hinein, um mehr über die grundlegenden Funktionen des Sketchs zu erfahren. Auch in diesem Projekt wartet dein ESP8266 darauf, dass ein bestimmtes Ereignis eintritt. Allerdings wird er hier nicht durch einen Interrupt getriggert, sondern fragt selbst die Daten eines Temperatursensors ab.

Anfänger

1 – 2 Stunden

ca. 12 €

Für dieses Projekt benötigst du (Mengen s. Beschreibung):

Der passende Temperatursensor

In diesem Projekt verwenden wir den Sensor BMP180. Du kannst aber natürlich auch jeden anderen Temperatursensor verwenden – z.B. einen einfachen TMP36, einen DHT22 oder einen GY-906. Denke in diesem Fall daran, deinen Sketch entsprechend anzupassen.

In diesen Tutorials lernst du, wie du einen TMP36 und einen GY-906 anschließt und verwendest.

Der Aufbau des Projekts

Du benötigst nur deinen ESP8266, den Temperatursensor (in unserem Fall einen BMP180), ein Breadboard und Kabel. Orientiere dich beim Aufbau an diesem Schema:

Aufbau Temperatursensor am ESP8266

Der Sensor BMP180 wird per I²C angeschlossen. Am ESP8266 musst du deshalb zwingend die beiden Pins D1 und D2 verwenden. Schließe den Sensor wie folgt an:

BMP180ESP8266
VIN3v3
GNDGND
SDAD2
SCLD1

Der Sketch

___STEADY_PAYWALL___

Kopiere den folgenden Sketch in deine Arduino IDE, ergänze deine Daten und lade ihn auf deinen ESP8266.

Sketch als .txt anschauen

/*
   Die Temperatur überwachen mit Telegram - polluxlabs.net
*/

//Bibliotheken
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>

#include <Wire.h>
#include <Adafruit_BMP085.h>

// Deine WLAN-Zugangsdaten
const char* ssid = "NETZWERKNAME";
const char* password = "PASSWORT";

// Den Telegram-Bot initialisieren
#define botToken "DEIN TOKEN"  // den Bot-Token bekommst du vom Botfather)

//Deine UserID
#define userID "DEINE USERID"

WiFiClientSecure client;
UniversalTelegramBot bot(botToken, client);

Adafruit_BMP085 bmp;

//Variablen für die Temperatur
float temp;
float threshold = 27.00;

//Verbindung zum WLAN
void connectToWiFi() {
  Serial.print("Verbinde mich mit: ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(300);
  }
  Serial.println("");
  Serial.println("Verbunden!");
}

void setup() {
  Serial.begin(115200);
  client.setInsecure();

  if (!bmp.begin()) {
    Serial.println("Kein Sensor gefunden! Checke die Verbindung.");
    while (1) {}
  }
}

void loop() {
  temp = bmp.readTemperature();
  Serial.print("Temperatur = ");
  Serial.print(temp);
  Serial.println(" °C");

  if (temp > threshold) { //Die Temperatur, die überschritten werden muss
    connectToWiFi();
    bot.sendMessage(userID, "Temperatur zu hoch!  " + String(temp) + " °C", "");
    Serial.println("Temperatur zu hoch!");
    WiFi.disconnect();
    delay(300000);
  }
  delay(500);
}

Was ist neu in diesem Sketch?

Vieles im Code haben wir schon im Stillen Alarm verwendet. Ein paar Teile sind jedoch neu und diese schauen wir uns nun genauer an.

Zunächst benötigst du zwei weitere Bibliotheken. Wire.h ist für die Kommunikation per I²C zuständig. Diese Bibliothek ist standardmäßig bereits vorinstalliert. Damit du den Sensor BMP180 so einfach wie möglich verwenden kannst, existiert ebenfalls eine passende Bibliothek: Arduino_BMP085.h. Lass dich nicht vom Namen irritieren. Dort steht zwar BMP085 (das ist der Vorläufer des BMP180), sie funktioniert jedoch auch mit dem BMP180 problemlos.

Am Anfang deines Sketchs bindest du also zusätzlich diese beiden Bibliotheken ein:

#include <Wire.h>
#include <Adafruit_BMP085.h>

Ebenfalls zu Beginn des Sketchs erstellst du für den Sensor das Objekt bmp sowie zwei Variablen: eine für die gemessene Temperatur (temp) und eine für den Schwellenwert (threshold), bei dessen Überschreiten dein ESP8266 eine Nachricht an dich sendet. In unserem Beispiel setzen wir diesen Schwellenwert auf 27,00 °C. Da der BMP180 die Temperatur als Kommazahl ausgibt, benötigst du für diese Variablen den Dateityp float.

Adafruit_BMP085 bmp;
float temp;
float threshold = 27.00;

In der Setup-Funktion prüfst du, ob der Temperatursensor von deinem ESP8266 gefunden wurde und verwendet werden kann. Ist das nicht der Fall, wirst du im Seriellen Monitor darüber informiert und der Sketch begibt sich mit while(1) in eine Endlosschleife – friert also ein.

  if (!bmp.begin()) {
    Serial.println("Kein Sensor gefunden! Checke die Verbindung.");
    while (1) {}
  }

Solltest den obigen Text also in deinem Seriellen Monitor zu Gesicht bekommen, trenne deinen ESP8266 vom Strom und überprüfe deine Verkabelung. In den meisten Fällen sollte hier der Fehler liegen.

Der Loop

Im Loop fragst du die Temperatur im Halbsekundentakt ab und prüfst mit einem Schwellenwert, ob sie diesen überschritten hat.

temp = bmp.readTemperature();

Wenn das der Fall ist, verbindet sich dein ESP8266 mit dem Internet und sendet eine entsprechende Nachricht an dein Smartphone.

if (temp > threshold) { //Wenn die Temperatur über dem Schwellenwert liegt
    connectToWiFi();
    bot.sendMessage(userID, "Temperatur zu hoch!  " + String(temp) + " °C", "");

Die Funktion bot.sendMessage() besteht aus drei Teilen. Der mittlere ist die Nachricht selbst, die du hier jedoch aus zwei Strings und der Variablen temp „zusammenbaust“. Hierfür verbindest du die einzelnen Teilstrings einfach mit einem Pluszeichen – doch Vorsicht: In der Mitte befindet sich die Variable temp als float. Um den Wert in dieser Variablen senden zu können, musst du diese erst mit der Funktion String(temp) in einen String umwandeln.

Auf deinem Smartphone erscheint dann der Text: „Temperatur zu hoch! x °C“ – wobei das x für die gemessene Temperatur steht.

Zuletzt trennt dein ESP8266 die Verbindung zu deinem WLAN wieder und setzt sich für 5 Minuten (300.000 Millisekunden) zur Ruhe. Erst dann beginnt er wieder damit, alle 500 Millisekunden die Temperatur vom BMP180 abzufragen.

    WiFi.disconnect();
    delay(300000);
  }
  delay(500);
}

Sollte danach die Temperatur immer noch über dem Schwellenwert liegen, erhältst du eine weitere Nachricht.

Falls noch nicht geschehen, lade den Sketch auf deinen ESP8266 und probiere ihn gleich aus.

Das passende Gehäuse

Möchtest du das Projekt in einem kleinen Gehäuse unterbringen? Hier findest du passende 3D-Druck-Dateien, die du herunterladen und ausdrucken kannst.

Wie geht es weiter?

Im nächsten Teil der Serie wartest du nicht darauf, bis dein ESP8266 sich bei dir meldet, sondern fragst die Temperatur selbst von deinem Smartphone aus ab.

Statt eines Temperatursensors kannst du auch andere Sensoren einsetzen: So kannst du dich warnen lassen, wenn die Luft zu schlecht oder das Licht zu hell ist. Es gibt auch Sensoren, die Flammen erkennen können – solltest du diesen einsetzen, hoffen wir, dass du niemals eine entsprechende Nachricht erhältst!

]]>
Beleuchte deine LEGO ISS im Rhythmus der echten Raumstation https://polluxlabs.net/esp8266-projekte/beleuchte-deine-lego-iss-im-rhythmus-der-echten-raumstation/ Tue, 13 Oct 2020 18:32:13 +0000 https://polluxlabs.net/?p=2036 Hinweis: Leider ist dieses Projekt bis auf Weiteres nicht mehr umsetzbar, da die benötigte API zur Ermittlung der nächsten Überflüge nicht mehr online ist. Du kannst stattdessen mit Python den nächsten Überflug der ISS berechnen oder die aktuelle Position der ISS ermitteln und auf einer Weltkarte anzeigen.

Wie wäre es, wenn deine LEGO ISS aufleuchten würde, sobald die echte International Space Station über ihr fliegt? In diesem Projekt lässt du genau das Wirklichkeit werden. Du lernst, wie du den Zeitpunkt des nächsten Überflugs herausfindest, damit einen Countdown programmierst und dann im richtigen Moment einen NeoPixel LED-Ring aufleuchten lässt. Los geht’s! 🙂

Für dieses Projekt benötigst du – abgesehen von der LEGO ISS – nur wenige Bauteile. Damit das Projekt gut aussieht, verwenden wir zwei Boxen aus dem 3D-Drucker – eine für den ESP8266 und den NeoPixel, die andere für das 7-Segment-Display.

Fortgeschrittene

1 – 2 Stunden – ohne Aufbau der LEGO ISS 😉

ca. 20 € plus ggfs. Kosten für den LEGO-Bausatz und 3D-Druck

Für dieses Projekt benötigst du (Mengen s. Beschreibung):

Hinweis: Meistens werden die NeoPixel LED-Ringe unverlötet verkauft – du benötigst also noch einen Lötkolben plus Zubehör. Wenn du unsere Vorlagen für die Boxen verwenden möchtest, benötigst du auch einen 3D-Drucker und Filament.

Der Aufbau unter der LEGO ISS

Da die LEGO ISS auf einer Art Sockel steht, unter dem noch viel Platz ist, eignet sich dieser Ort besonders, um sie von unten zu beleuchten. Hier platzierst du also deinen ESP8266 und den NeoPixel-Ring. Das 7-Segment-Display für den Countdown bis zum nächsten Überflug liegt etwas abseits.

Aufbau ESP8266, Neopixel, Display unter der LEGO ISS

Auf dem Breadboard

Die Bauteile miteinander zu verbinden, dauert nur wenige Minuten. Verwende für den Aufbau die folgende Tabelle:

ESP8266 NeoPixel
3v3 VCC
GND GND
D5 IN
ESP8266 7-Segment-Display
3v3 VCC
GND GND
D6 DIN
D7 CS
D8 CLK

Noch zwei Hinweise: Wenn du unsere Vorlage für die Boxen aus dem 3D-Drucker verwendest, achte darauf, deinen ESP8266 an den glatten Rand des Mini-Breadboards zu setzen – die Seite, die keine Feder hat. Dann kannst du das USB-Kabel bequem durch ein Loch in der Box mit dem ESP8266 verbinden.

Unsere Box hat einen Innendurchmesser von 39 mm. Achte darauf, einen NeoPixel-Ring mit 37 mm Durchmesser zu verwenden. Diese werden jedoch teilweise fälschlicherweise mit einem Durchmesser von 39 mm verkauft. Egal wie, beide passen in die Box. 😉

So ungefähr sollte es aussehen, wenn du alles miteinander verbunden hast.

Die passenden Boxen

Natürlich kannst du dein Projekt auch „nackt“ unter deine LEGO ISS stellen. Allerdings sieht es aufgeräumter aus, wenn du deine Bauteile in Boxen unterbringst. Wenn du möchtest, kannst du unsere Vorlagen verwenden und sie mit einem 3D-Drucker ausdrucken. Hier findest du je zwei Boxen mit Deckel – eine für den ESP8266 samt NeoPixel und eine für das 7-Segment-Display.

Hinweis: Du kannst die Boxen natürlich in deiner Lieblingsfarbe ausdrucken – der Deckel der Box für den ESP8266 plus NeoPixel sollte jedoch transparent sein, damit das Licht durchscheinen und deine LEGO ISS von unten beleuchten kann.

Du findest unsere Vorlagen hier bei uns als Download.

Und so sehen die Bauteile in den Boxen aus. Wie du siehst führt ein Kabelstrang aus der Box für den ESP8266 zum 7-Segment-Display in der anderen Box. Wir haben hierfür 10 cm lange Kabel verwendet, aber die Wahl liegt natürlich bei dir.

Alle Bauteile in den passenden Boxen

Und das war es auch schon mit der Hardware. Weiter geht es mit dem Sketch.

Der passende Sketch

Schauen wir uns die wichtigsten Teile des Codes genauer an.

Die benötigten Bibliotheken

Für dieses Projekt benötigst du einige Bibliotheken, um z.B. das 7-Segment-Display, den NeoPixel-Ring zu steuern und die aktuelle Uhrzeit abzufragen. Installiere die folgenden Bibliotheken in deinem Bibliotheksmanager, falls sie noch nicht in deiner Arduino IDE verfügbar sind:

ArduinoJson.h
ESP8266HTTPClient.h
WiFiClientSecure.h
Adafruit_NeoPixel.h
LedControl.h
NTPClient.h
WiFiUdp.h

Den ESP8266 mit dem Internet verbinden

Für dieses Projekt muss dein ESP8266 mit dem Internet verbunden sein. Zu diesem Thema haben wir ein eigenes Tutorial, in dem du lernst, wie das geht. Übrigens: Solltest du noch nie einen ESP8266 mit der Arduino IDE programmiert haben, lies hier nach, wie du die beiden verbindest.

Den nächsten Überflug der ISS ermitteln

Damit die Beleuchtung deiner LEGO ISS im Rhythmus der echten funktioniert, benötigst du zuerst die Überflugsdaten. Hier kommt die API von open-notify.org ins Spiel. Mit ihr kannst du kostenlos den nächsten Transit für deinen Standort mit deinem ESP8266 abfragen.

Trage deshalb zu Beginn des Sketchs deine Koordinaten ein. Falls du diese nicht kennst, kannst du sie z.B bei geoplaner.de ermitteln. Deine Höhe ist optional – wenn du sie weißt, wird das Ergebnis ein klein wenig genauer, wenn nicht, rechnet die API einfach mit einer Höhe von 100 Metern. Allerdings muss die Höhenangabe größer als Null sein – sonst funktioniert die API-Abfrage nicht.

Hier sind die Daten für Karlsruhe eingetragen:

const float latitude = 49.00; //Dein Breitengrad
const float longitude = 8.40; //Dein Längengrad
const float altitude = 115.00; //Deine Höhe über Normalnull

Im Sketch befindet sich die Funktion apiCall() – hier werden die Überflugsdaten der ISS für deinen Standort bei der API von open-notify.org abgerufen und weiterverarbeitet.

Zunächst die Abfrage: Mit der Funktion http.begin() rufst du die Daten von der API-Adresse ab. Hierfür benötigst den Breiten- und Längengrad sowie optional die Höhe, die du bereits oben in den jeweiligen Konstanten hinterlegt hast. Die URL innerhalb der Funktion erweiterst du deshalb ganz einfach mit diesen hinterlegten Daten:

http.begin("http://api.open-notify.org/iss-pass.json?lat=" + String(latitude) + "&lon=" + String(longitude) + "&alt=" + String(altitude) + "&n=5");

Die fertige URL für das Beispiel Karlsruhe lautet dann wie folgt. Der Parameter n=5 bestimmt die Anzahl der nächsten Überflüge, die berechnet werden soll – hier also 5.

http://api.open-notify.org/iss-pass.json?lat=49&lon=8.4&alt=115&n=5

Die Antwort der API auswerten

Wenn du diese Adresse testweise in deinem Browser öffnest, erhältst du ungefähr folgende Antwort:

Antwort der API

Hierbei handelt es sich um Daten im JSON-Format, mit denen du noch nichts anfangen kannst. Was du benötigst, sind die Daten, die im Key response stecken: duration (die Dauer des Überflugs) und risetime (der Zeitpunkt, wann die ISS über den Horizont steigt und von deinem Standort aus theoretisch sichtbar wird).

Das Angaben duration und risetime sind insgesamt fünf Mal in der response enthalten, da du die Abfrage mit n=5 entsprechend gestartet hast. Alle fünf zusammen befinden sich paarweise in einem Array. Das erste Paar ist hierbei der nächste Überflug, das zweite der übernächste und so weiter. Später werden wir das benötigte Paar aus dem Array picken.

Zunächst speicherst du jedoch diese JSON-Daten als Ganzes in der Variablen payload ab:

String payload = http.getString();

Anschließend kommt die Bibliothek ArduinoJson ins Spiel. Auch hierfür haben wir ein eigenes Tutorial, weshalb wir das Parsen der JSON-Daten hier überspringen.

Vielmehr springen wir gleich zum Teil, in dem du die Dauer und den Zeitpunkt des nächsten Überflugs abspeicherst. Wie du im Code gleich hier unten siehst, picken wir den ersten Eintrag des oben genannten Arrays mit [0].

JsonArray response = doc["response"];
duration = response[0]["duration"];
riseTime = response[0]["risetime"];

Wie lange dauert es noch, bis die ISS kommt?

Du hast jetzt den Zeitpunkt des nächsten Überflugs, aber dein ESP8266 weiß noch nicht, wie lange es bis dahin noch dauert. Hierfür befindet sich im Sketch eine andere Funktion: getCurrentTime()

Hier verwendest du das Network Time Protocol (NTP). Auch hierfür gibt es das passende Tutorial bei uns, in dem du weitere Details erfährst. Du ermittelst in dieser Funktion also die aktuelle Uhrzeit – und speicherst diese in der Variablen currentTime ab.

Den Zeitpunkt bis zum Erscheinen der ISS berechnest du dann wie folgt:

timeUntilRise = riseTime - currentTime;

In der Variablen timeUntilRise befindet sich nun also die Dauer bis zum nächsten Überflug – in Sekunden. Noch ein Hinweis: Sowohl die aktuelle Uhrzeit currentTime als auch den Zeitpunkt des Überflugs riseTime rufst du als Unixzeit ab. Hierbei handelt es sich um die Sekunden, die seit dem 1. Januar 1970 vergangen sind. Das hat den Vorteil, dass du von Zeitverschiebung, Sommer- und Winterzeit unabhängig bist: In die Variable timeUntilRise kommen einfach die Sekunden bis zum nächsten Transit der ISS.

Was aber, wenn der Zeitpunkt riseTime schon überschritten wurde, die API aber noch diesen Zeitpunkt als nächsten Überflug ausgibt? Hier liegt der Wert in riseTime unterhalb der aktuellen Uhrzeit currentTime. In diesem Fall nimmst du den zweiten Eintrag der API-Antwort, den du entsprechend mit [1] auswählst.

if (timeUntilRise < 0) { 
  duration = response[1]["duration"];
  riseTime = response[1]["risetime"];

Der Countdown

Apropos nächster Transit: Auf dem 7-Segment-Display soll ja ein Countdown bis zum nächsten Überflug erscheinen. Auch diesen Teil sparen wir hier aus, da du in diesem Tutorial nachlesen kannst, wie du ein 7-Segment-Display im Sketch ansteuerst. In diesem Projekt erfährst du alles zum Thema Countdown mit diesem Display.

Die LEGO ISS beleuchten

Nun wird es Zeit für etwas Licht. Wenn also die echte ISS über den Horizont steigt, soll die LEGO ISS beleuchtet werden.

Die beleuchtete LEGO ISS

Hier kommt der NeoPixel-Ring mit seinen LEDs ins Spiel. Du wirst es erraten haben, auch hierfür haben wir bereits ein Tutorial, in dem du nachlesen kannst, wie du einen NeoPixel-Ring verwendest.

Allerdings gehst du in diesem Projekt einen Schritt weiter: Der LED-Ring soll nicht nur aufleuchten, sondern auch noch für die Dauer des Überflugs seine Farbe verändern. Hierfür benötigst du wieder die Variable duration, die du oben mit der Überflugsdauer befüllt hast.

Diese Variable kommt nun in der Funktion map() zum Einsatz. Hier berechnest du jede Sekunde einen neuen Farbwert, den alle 12 LEDs auf dem Ring annehmen sollen – von Blau zu Beginn des Überflugs bis zu einem tiefen Rot, kurz bevor die ISS wieder hinter dem Horizont verschwindet.

for (int i = duration; i >= 0; i--) {
  int colorRed = map(i, 0, duration, 200, 0);
  int colorBlue = map(i, 0, duration, 0, 200);
  //Die neuen Farben auf dem NeoPixel ausgeben
  for (int j = 0; j < 12; j++) {
    pixels.setPixelColor(j, pixels.Color(colorRed, 0, colorBlue));
    pixels.show();
  }
  delay(1000);
}

Die Funktion map() ist auf den ersten Blick nicht ganz leicht zu verstehen, aber die offizielle Arduino-Dokumention erhellt dieses Thema ziemlich gut.

Experimentiere mit den RGB-Werten für den NeoPixel etwas herum, um den Farbverlauf nach deinen Wünschen anzupassen. Oder lösche diese Funktion ganz, um die ISS in nur einer Farbe zu beleuchten.

Und das war es. 🙂

]]>
Eine Fotofalle mit der ESP32-CAM und Telegram https://polluxlabs.net/esp8266-projekte/eine-fotofalle-mit-der-esp32-cam-und-telegram/ Sun, 04 Oct 2020 09:43:39 +0000 https://polluxlabs.net/?p=2870 ESP32- und ESP8266-Boards sind zusammen mit Telegram eine tolle Kombination. Du kannst Daten blitzschnell auf dein Smartphone senden und von dort aus deinen Microcontroller steuern.

In diesem Projekt baust du eine Fotofalle mit einem speziellen ESP32-Board – der ESP32-CAM. Diese Falle schnappt zu, sobald sich jemand vor der Kamera bewegt. Dann nimmt sie ein Foto auf und sendet es umgehend an dein Smartphone.

Fotofalle mit ESP32-CAM und Telegram

Anfänger

1 Stunde

ca. 25 €

Für dieses Projekt benötigst du (Mengen s. Beschreibung):

Bevor du loslegen kannst, musst du noch ein paar Minuten in Vorbereitungen stecken.

Telegram vorbereiten

Zunächst benötigst du einen Account bei Telegram – und die dazugehörige App für dein Smartphone oder den Computer. Im Folgenden verwenden wir ein Smartphone. Telegram ist kostenlos, werbefrei und funktioniert so ähnlich wie WhatsApp. Allerdings hast du hier die Möglichkeit, Bots zu erstellen, mit denen du interagieren kannst.

In diesem Tutorial auf Pollux Labs lernst du, wie du deinen eigenen Telegram-Bot erstellst.

Die Fotofalle aufbauen

Die ESP32-CAM hat leider keinen USB-Port, weswegen du auf einen FTDI-Adapter zurückgreifen musst, um Sketches hochladen zu können. Wenn du hier noch keine Erfahrung sammeln konntest, informiere dich in diesem Tutorial darüber, wie du die ESP32-CAM programmieren kannst.

___STEADY_PAYWALL___

Wenn du den USB/Serial-Adapter verbunden hast, fehlt nur noch der Bewegungssensor. In diesem Projekt verwenden wir den PIR-Sensor HC-SR501, für den du nur einen Daten-Pin benötigst.

Orientiere dich beim Aufbau an diesem Schema:

Aufbau Fotofalle ESP32-CAM und PIR-Sensor

Hier noch einmal die Verbindungen übersichtlich dargestellt:

FTDI-AdapterESP32-CAM
GNDGND
VCC5V
TXDU0R
RXDU0T
HC-SR501ESP32-CAM
VCC3v3
GNDGND
OUTIO13

Hinweis: Im Schema oben findest du eine Brücke in Grau – denke immer daran, dass du diese benötigst, um einen Sketch hochzuladen. Sobald der Code auf deiner ESP32-CAM ist, trenne die Brücke und drücke den RESET-Button auf dem Board. Erst dann startet dein Sketch.

Das passende Gehäuse

Möchtest du die Fotofalle diskret aufbauen? Oder passt ein Breadboard nicht in das Design des Raums drumherum? Dann sind unsere Gehäuse die richtige Wahl:

Du kannst die .STL Dateien für die Gehäuse hier bei uns herunterladen.

Der Sketch

Für dieses Projekt haben wir einen Sketch von Random Nerd Tutorials als Ausgangspunkt genommen und diesen erweitert. Rui Santos verwendet hier die ESP32-CAM, um bei einer Bewegung ein Foto auf eine SD-Karte zu speichern.

Wir haben den Aufbau und den Code so modifiziert, dass dein Board das Foto an deinen Telegram-Bot, also an dein Smartphone sendet, sobald eine Bewegung erkannt wurde.

Du findest den gesamten Sketch auf Github als .txt und am Ende dieses Artikels.

Wichtige Anpassungen im Code der Fotofalle

Damit der Sketch bei dir funktioniert, musst du ein paar Kleinigkeiten anpassen. Trage zunächst die Zugangsdaten deines WLAN-Netzwerks ein, damit sich die ESP32-CAM damit verbinden kann.

Anschließend benötigst du deinen Token und die UserID, die du beim Erstellen deines Telegram-Bots erhalten hast.

const char* ssid = "NETWORK";
const char* password = "PASSWORD";
String BOTtoken = "TOKEN"; 
String CHAT_ID = "USERID";

Eine Besonderheit, die du nach deinen Wünschen anpassen kannst, ist die Zeit zwischen den Fotos. Im Loop findest du einen delay() von 20 Sekunden. Das ist die Zeitspanne, in der der Bewegungssensor nach einem gesendeten Foto keine weitere Bewegung registriert.

Je kürzer du diese Zeitspanne einstellst, desto mehr Fotos erhältst du – sofern sich weiterhin jemand vor der Kamera bewegt.

Ebenso kannst du die Empfindlichkeit deines HC-SR501 einstellen. An ihm findest du zwei Potis: Wenn du die Platine nach oben drehst, kannst du am linken von ihnen die Empfindlichkeit einstellen. Experimentiere hier ein wenig herum, um die passende Einstellung für dich zu finden.

Die Bibliothek UniversalTelegramBot

Die Bibliothek UniversalTelegramBot.h übernimmt die Kommunikation mit deinem Telegram-Bot. Du findest sie im Bibliotheksverwalter der Arduino IDE – diese kann jedoch veraltet sein. Deshalb empfehlen wir dir, die Bibliothek hier bei uns herunterzuladen.

Anschließend musst du diese Bibliothek in deinen Sketch einbinden, indem du im Menü der Arduino IDE Sketch -> Bibliothek einbinden -> .ZIP-Bibliothek hinzufügen wählst und die gerade heruntergeladene ZIP-Datei auswählst.

Noch ein Hinweis: Dieses Projekt dient dem Ausprobieren. Wenn du die Fotofalle produktiv einsetzen möchtest, mache dir vorab Gedanken über die IT-Sicherheit und achte darauf, keine Persönlichkeitsrechte zu verletzen!

Hier nun der gesamt Sketch zum Rauskopieren:

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/telegram-esp32-cam-photo-arduino/

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  Adapted by Pollux Labs – https://polluxlabs.net
*/

#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "esp_camera.h"
#include <UniversalTelegramBot.h>

const char* ssid = "NETWORK";
const char* password = "PASSWORD";

// Initialize Telegram BOT
String BOTtoken = "TOKEN";  // dein Bot-Token vom Botfather)

// Trage hier deine User-ID ein
String CHAT_ID = "CHAT-ID";

bool sendPhoto = false;

WiFiClientSecure clientTCP;
UniversalTelegramBot bot(BOTtoken, clientTCP);

//Pin of the motion sensor
#define PIR_PIN 13

//CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27

#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22


void configInitCamera() {
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;

  //init with high specs to pre-allocate larger buffers
  if (psramFound()) {
    config.frame_size = FRAMESIZE_UXGA;
    config.jpeg_quality = 10;  //0-63 lower number means higher quality
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;  //0-63 lower number means higher quality
    config.fb_count = 1;
  }

  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    delay(1000);
    ESP.restart();
  }

  // Drop down frame size for higher initial frame rate
  sensor_t * s = esp_camera_sensor_get();
  s->set_framesize(s, FRAMESIZE_CIF);  // UXGA|SXGA|XGA|SVGA|VGA|CIF|QVGA|HQVGA|QQVGA
}

String sendPhotoTelegram() {
  const char* myDomain = "api.telegram.org";
  String getAll = "";
  String getBody = "";

  camera_fb_t * fb = NULL;
  fb = esp_camera_fb_get();  
  if(!fb) {
    Serial.println("Camera capture failed");
    delay(1000);
    ESP.restart();
    return "Camera capture failed";
  }  
  
  Serial.println("Connect to " + String(myDomain));


  if (clientTCP.connect(myDomain, 443)) {
    Serial.println("Connection successful");
    
    String head = "--RandomNerdTutorials\r\nContent-Disposition: form-data; name=\"chat_id\"; \r\n\r\n" + CHAT_ID + "\r\n--RandomNerdTutorials\r\nContent-Disposition: form-data; name=\"photo\"; filename=\"esp32-cam.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n";
    String tail = "\r\n--RandomNerdTutorials--\r\n";

    uint16_t imageLen = fb->len;
    uint16_t extraLen = head.length() + tail.length();
    uint16_t totalLen = imageLen + extraLen;
  
    clientTCP.println("POST /bot"+BOTtoken+"/sendPhoto HTTP/1.1");
    clientTCP.println("Host: " + String(myDomain));
    clientTCP.println("Content-Length: " + String(totalLen));
    clientTCP.println("Content-Type: multipart/form-data; boundary=RandomNerdTutorials");
    clientTCP.println();
    clientTCP.print(head);
  
    uint8_t *fbBuf = fb->buf;
    size_t fbLen = fb->len;
    for (size_t n=0;n<fbLen;n=n+1024) {
      if (n+1024<fbLen) {
        clientTCP.write(fbBuf, 1024);
        fbBuf += 1024;
      }
      else if (fbLen%1024>0) {
        size_t remainder = fbLen%1024;
        clientTCP.write(fbBuf, remainder);
      }
    }  
    
    clientTCP.print(tail);
    
    esp_camera_fb_return(fb);
    
    int waitTime = 10000;   // timeout 10 seconds
    long startTimer = millis();
    boolean state = false;
    
    while ((startTimer + waitTime) > millis()){
      Serial.print(".");
      delay(100);      
      while (clientTCP.available()) {
        char c = clientTCP.read();
        if (state==true) getBody += String(c);        
        if (c == '\n') {
          if (getAll.length()==0) state=true; 
          getAll = "";
        } 
        else if (c != '\r')
          getAll += String(c);
        startTimer = millis();
      }
      if (getBody.length()>0) break;
    }
    clientTCP.stop();
    Serial.println(getBody);
  }
  else {
    getBody="Connected to api.telegram.org failed.";
    Serial.println("Connected to api.telegram.org failed.");
  }
  return getBody;
}

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
  // Init Serial Monitor
  Serial.begin(115200);

  //Set PIR
  pinMode(PIR_PIN, INPUT);

  // Config and init the camera
  configInitCamera();

  // Connect to Wi-Fi
  WiFi.mode(WIFI_STA);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  clientTCP.setCACert(TELEGRAM_CERTIFICATE_ROOT); // Add root certificate for api.telegram.org
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
}

void loop() {
  Serial.println(digitalRead(PIR_PIN));
  if (digitalRead(PIR_PIN)) {
    Serial.println("Preparing photo");
    sendPhotoTelegram();
    delay(20000);
  }
}

Lade den obigen Sketch nun auf deine ESP32-CAM hoch. Achte darauf, dass du die Brücke für den Upload schließt, sie danach wieder öffnest und das Board neustartest mit dem Reset-Button. Im Seriellen Monitor solltest du nun sehen, dass sich das Board mit deinem WLAN verbindet und anschließend auf eine Bewegung wartet – hier sollten in schneller Folge Nullen durch den Seriellen Monitor jagen, bis dein PIR-Sensor eine Bewegung erkannt hat. Daraufhin sendet dir die ESP32-CAM ein Foto der aktuellen Situation an deinen Telegram-Bot.

Mögliche Fehler

Solltest du eine Fehlermeldung im Zusammenhang mit TELEGRAM_CERTIFICATE_ROOT bekommen, lade die aktuelle Version der Bibltiothek UniversalTelegramBot herunter. Möglicherweise ist die Version auf unserem Server bereits veraltet und noch nicht rechtzeitig von uns aktualisiert worden. Auf GitHub findest du die neueste Version – klicke dort rechts oben auf Code und anschließend auf Download ZIP.

]]>
Eine ESP32-CAM (AI Thinker) mit der Arduino IDE programmieren https://polluxlabs.net/arduino-tutorials/eine-esp32-cam-ai-thinker-mit-der-arduino-ide-programmieren/ Fri, 02 Oct 2020 09:08:19 +0000 https://polluxlabs.net/?p=2802 Du möchtest Fotos aufnehmen und sie auf einer SD-Karte speichern, übers Internet verschicken oder gleich einen Video-Stream einrichten? Dann ist die ESP32-CAM eine tolle Sache! Es gibt da nur einen Umstand: Das Board hat keinen USB-Port. Also was tun?

In diesem Tutorial lernst du, wie du deine ESP32-CAM über einen USB/Serial-Adapter direkt in der Arduino IDE programmierst. Du benötigst hierfür:

AZDelivery Kompatibel mit FT232RL USB zu TTL Serial Adapter für 3,3V und 5V kompatibel mit Arduino inklusive E-Book!
AZDelivery Kompatibel mit FT232RL USB zu TTL Serial Adapter für 3,3V und 5V kompatibel mit Arduino inklusive E-Book!
✅ AZDelivery Adapter kompatibel mit FT232RL USB zu TTL Serial für 3,3V und 5V.
6,99 €

Vorbereitungen in der Arduino IDE

Wenn du die ESP32-CAM noch nicht mit deiner Arduino IDE verbunden hast, hole das schnell nach. In diesem Tutorial erfährst du, wie du ESP32-Boards verfügbar machst.

Wenn du das erledigt hast, findest du im Menü Werkzeuge > Board den Eintrag AI Thinker ESP32-CAM – den brauchst du später.

Programmieren über einen Adapter

Da du die ESP32-CAM nicht direkt an deinen Computer anschließen kannst, benötigst du einen Adapter, der die serielle Kommunikation per USB ermöglicht. Diese werden auch FTDI-Adapter genannt – nach dem Unternehmen FTDI, das sich auf diese Anwendungen spezialisiert hat. Ein bisschen wie Tempo also. 🙂

Diese Adapter gibt es in vielen Ausführungen von vielen Herstellern. Oben haben wir dir einen verlinkt, den du zwischen 3,3V und 5V umschalten kannst – was ganz praktisch ist.

Um nun also einen Sketch hochzuladen, verbinde deine ESP32-CAM und den FTDI-Adapter wie folgt:

ESP32-CAM mit FTDI-Adapter programmieren

Hier noch einmal die Verbindungen übersichtlich dargestellt:

FTDI-AdapterESP32-CAM
GNDGND
VCC5V
TXDU0R
RXDU0T

Wichtig: Wenn du einen Sketch hochlädst, musst du an deiner ESP32-CAM den Pin IO0 mit GND verbinden – im Schema oben hellblau dargestellt. Um den Sketch später auszuführen, trenne diese Verbindung wieder und drücke den Reset-Button.

Wenn du den Adapter und die ESP32-CAM wie oben beschrieben miteinander verkabelt hast, verbinde den Adapter mit deinem Computer. Wähle dann in der Arduino IDE das Board AI Thinker ESP32-CAM und den richtigen Port aus und lade deinen Sketch hoch.

Funktioniert nicht?

Der häufigste Fehler ist die fehlende Verbindung zwischen IO0 und GND, die du beim Upload herstellen musst. Wenn du hierfür ein Kabel verwendest, prüfe es auf seine Funktion.

Eine weitere Fehlerquelle kann auch das USB-Kabel sein: Kannst du damit Daten übertragen oder liefert es nur Strom? Manchmal kommt es auch zu Problemen, wenn das Kabel zu lang ist – probiere einfach mal ein anderes.

Wenn der Fehler woanders liegen muss, findest du möglicherweise in der recht umfangreichen Dokumentation bei Random Nerd Tutorials (Englisch) eine Lösung.

]]>
Deinen ESP32 mit der Arduino IDE programmieren https://polluxlabs.net/arduino-tutorials/deinen-esp32-mit-der-arduino-ide-programmieren/ Thu, 01 Oct 2020 13:52:35 +0000 https://polluxlabs.net/?p=2806 Der ESP32 ist so etwas wie der große Bruder des ESP8266. Mit ihm verfügst du nicht nur über WiFi, sondern kannst auch Bluetooth nutzen. Und das beste: Du kannst es ganz einfach mit deiner Arduino IDE programmieren – genauso wie deine Arduino-Boards. Ein paar Vorbereitungen musst du hierfür allerdings treffen.

Lerne hier, wie du in 5 Minuten deinen ESP32 in deiner Arduino IDE installierst und anschließend mit dem Programmieren loslegen kannst.

Dein Board in der Arduino IDE installieren

Öffne zuerst die Einstellungen deiner Arduino IDE. Dort findest du das Feld Zusätzliche Boardverwalter-URLs. Trage hier die folgende Adresse ein:

https://dl.espressif.com/dl/package_esp32_index.json
ESP32 URL in der Arduino IDE eintragen

Tipp: Wenn du dort schon die URL deines ESP8266 eingetragen hast, schreibe die des ESP32 einfach mit einem Komma getrennt dahinter. Dann verfügst du in der Arduino IDE über beide.

Schließe nun das Fenster mit einem Klick auf OK. Öffne als nächstes das Menü Werkzeuge und wähle dort den Menüpunkt Boards und anschließend Boardverwalter.

Suche in dem Fenster, das sich jetzt öffnet, nach ESP32. Vermutlich wirst du dort nur einen Eintrag finden. Noch ein Klick auf Installieren, kurz warten und das sollte es gewesen sein. 🙂

ESP32 im Boardverwalter
Das Paket für deinen ESP32 installieren

Einen Sketch auf den ESP32 hochladen

Schließe nun deinen ESP32 an und wähle im Menü unter Werkzeuge > Board dein Modell und den richtigen Port aus.

Unter Datei > Beispiele findest du unter WiFi den Sketch WiFiScan. Dieser eignet sich für einen ersten Test, denn er macht nichts anderes als die verfügbaren WLAN-Netzwerke in der Umgebung anzuzeigen.

Öffne also diesen Sketch und lade ihn auf deinen ESP32. Nach dem Upload findest du in deinem Seriellen Monitor (115200 Baud) die Netzwerke in der Umgebung.

Funktioniert nicht?

Solltest du beim Upload Probleme haben, probiere folgendes:

Halte den Button BOOT auf deinem ESP32 gedrückt und starte den Upload. Sobald in der Arduino IDE der Status „Connecting…“ erscheint, kannst du den Button wieder loslassen. Der Upload sollte jetzt durchlaufen.

]]>
Ein stiller Alarm mit Telegram und einem ESP8266 https://polluxlabs.net/esp8266-projekte/ein-stiller-alarm-mit-telegram-und-einem-esp8266/ Tue, 22 Sep 2020 21:04:52 +0000 https://polluxlabs.net/?p=2494 In diesem Projekt baust du dir einen Bewegungsmelder, der dir eine Nachricht schickt, wenn sich vor ihm jemand bewegt. Im Prinzip handelt es sich hierbei um einen stillen Alarm – also eine Alarmanlage, die keinen Lärm macht, sondern ganz diskret mitteilt, das etwas im Gang ist.

Zum Einsatz kommt hierbei der Sensor HC-SR501. Diese Art von Sensoren kennst du von den handelsüblichen Bewegungsmeldern, die das Licht anschalten, sobald jemand an ihm vorbeikommt.

Das ist ein sogenannter PIR-Sensor – PIR steht für Passive Infrared. Dieser Sensor erkennt also Infrarotstrahlung bzw. Wärme, die von Körpern abgestrahlt wird. Darüber hinaus springt er nur an, wenn sich dieser Körper bewegt – denn sonst würde er schließlich auch bei einer warmen Heizung Alarm schlagen.

Heißt also konkret: Sobald eine Person (oder auch eine Katze oder ein Hund) in die Reichweite des Bewegungsmelders gerät, registriert dieser die abgestrahlte Wärme sowie die Bewegung und gibt dir Bescheid.

Anfänger

1 – 2 Stunden

ca. 10 €

Für dieses Projekt benötigst du (Mengen s. Beschreibung):

Telegram vorbereiten

Zunächst benötigst du einen Account bei Telegram – und die dazugehörige App für dein Smartphone oder den Computer. Im Folgenden verwenden wir ein Smartphone. Telegram ist kostenlos, werbefrei und funktioniert so ähnlich wie WhatsApp. Allerdings hast du hier die Möglichkeit, Bots zu erstellen, mit denen du interagieren kannst.

Das machst du dir in diesem Projekt zunutze, indem du deinen ESP8266 mit deinem Telegram-Bot „sprechen“ lässt. Der Bot wiederum sendet dir daraufhin umgehend eine Benachrichtigung.

In diesem Tutorial auf Pollux Labs lernst du, wie du deinen eigenen Telegram-Bot erstellst.

Das Projekt aufbauen

Der Aufbau auf dem Breadboard geht ganz fix: Du musst nur den Bewegungssensor mit deinem ESP8266 verbinden:

Die Beschriftung der Pins am Sensor siehst du, wenn du die weiße Kappe abhebst. Verbinde den Sensor und deinen ESP8266 wie folgt:

HC-SR501ESP8266
GNDGND
OUTD5
VCC3v3

Das war es auch schon mit der Hardware. Werfen wir einen Blick auf den Code.

Der Sketch für den Bewegungsmelder

Nun wird es Zeit für etwas Code. Falls du noch nie einen ESP8266 mit der Arduino IDE verwendet hast: In diesem Tutorial lernst du, wie du deinen ESP8266 in der Arduino IDE verfügbar machen und programmieren kannst.

Die benötigten Bibliotheken

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>

Du benötigst insgesamt drei Bibliotheken. Zwei davon sollten bei dir schon vorinstalliert sein: ESP8266WiFi.h und WiFiClientSecure.h – du benötigst sie für die Verbindung zu deinem WLAN-Netzwerk und zum Senden der Daten.

Die Bibliothek UniversalTelegramBot.h übernimmt die Kommunikation mit deinem Telegram-Bot. Du findest sie im Bibliotheksverwalter der Arduino IDE –diese kann jedoch veraltet sein. Deshalb empfehlen wir dir, die Bibliothek hier bei uns herunterzuladen.

Anschließend musst du diese Bibliothek in deinen Sketch einbinden, indem du im Menü der Arduino IDE Sketch -> Bibliothek einbinden -> .ZIP-Bibliothek hinzufügen wählst und die gerade heruntergeladene ZIP-Datei auswählst.

Kopiere dir nun den folgenden Sketch und lade ihn auf deinen ESP8266.

Hinweis: Bevor dein Telegram-Bot Nachrichten empfangen kann, musst du ihn erst aufrufen und auf Start tappen. Das musst du allerdings nur einmal zu Beginn tun.

Sketch als .txt anschauen

/*
   Stiller Alarm mit Telegram - polluxlabs.net
*/

//Bibliotheken
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>

// Deine WLAN-Zugangsdaten
const char* ssid = "NETZWERKNAME";
const char* password = "PASSWORT";

// Den Telegram-Bot initialisieren
#define botToken "DEIN TOKEN"  // den Bot-Token bekommst du vom Botfather)

//Deine User ID
#define userID "DEINE USERID"

WiFiClientSecure client;
UniversalTelegramBot bot(botToken, client);

const int sensor = 14; // Pin des Bewegungssensors, auf dem ESP Pin D5
bool motion = false;

// Indicates when motion is detected
void IRAM_ATTR detectingMovement() {
  motion = true;
}

//Verbindung zum WLAN
void connectToWiFi() {
  Serial.print("Verbinde mich mit: ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(300);
  }
  Serial.println("");
  Serial.println("Verbunden!");
}

void setup() {
  Serial.begin(115200);
  client.setInsecure();

  // Verwendeter Pin
  pinMode(sensor, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(sensor), detectingMovement, RISING);
}

void loop() {

  if (motion == true) {
    connectToWiFi();
    bot.sendMessage(userID, "Hier bewegt sich etwas!", "");
    Serial.println("Bewegung erkannt");
    motion = false;
    WiFi.disconnect();
  }
}

Der Sketch Schritt für Schritt

Schauen wir uns nun ein paar wichtige Teile des Sketchs für deinen Bewegungsmelder genauer an.

Zunächst gibt es einige Daten, die du durch deine eigenen ersetzen musst: Deine WLAN-Zugangsdaten sowie dein Token und deine User ID von Telgram. Trage diese Daten hier ein:

const char* ssid = "DEIN WLAN-NETZWERK";
const char* password = "DEIN PASSWORT";
#define botToken "DEIN TOKEN"
#define userID "DEINE USER ID"

Anschließend erstellst du eine Instanz von WiFiClientSecure names client und ebenso einen bot mit deinem oben definierten botToken und dem client.

WiFiClientSecure client;
UniversalTelegramBot bot(botToken, client);

Jetzt fehlen noch eine Konstante und eine Variable. In ersteren legst du du den Pin fest, an dem der Sensor angeschlossen ist. Hinweis: Die Zahlen auf dem ESP8266 und im Sketch unterscheiden sich. Wenn du den Sensor am Pin D5 angeschlossen hast, entspricht das im Sketch der 14.

Die Variable motion setzt du hier zu Beginn des Sketchs auf false. Diese Variable kann zwei Zustände haben: false, wenn keine Bewegung erkannt wird und true, wenn genau das der Fall ist. Du benötigst also den Datentyp bool, der nur diese zwei Werte annehmen kann.

const int sensor = 14; // Pin des Sensors, am ESP8266 Pin D5
bool motion = false; // Variable für eine erkannte Bewegung

Die Funktionen im Sketch

Jetzt kommt die erste Funktion ins Spiel. Diese Callback-Funktion wird aufgerufen, sobald der Sensor eine Bewegung erkennt und eine 1 (HIGH) an deinen ESP8266 sendet.

Die Funktion macht nichts anderes als die gerade definierte Variable motion auf true zu setzen. Das wiederum setzt die Nachricht an deinen Telegram-Bot in Gang – was wir uns gleich genauer anschauen werden.

void IRAM_ATTR detectingMovement() {
  motion = true;
}

Zunächst steht im Sketch jedoch noch eine weitere Funktion, die deinen ESP8266 mit dem Internet verbindet, sobald eine Bewegung erkannt wurde.

void connectToWiFi() {
  Serial.print("Verbinde mich mit: ");
  Serial.println(ssid);

  WiFi.begin(ssid, password); //hast du zu Beginn hinterlegt
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(300);
  }
  Serial.println("");
  Serial.println("Verbunden!");
}

Die Setup-Funktion

Auch hier musst du noch ein paar grundlegende Dinge erledigen: Den seriellen Monitor starten, den client konfigurieren und den pinMode für den angeschlossenen Sensor festlegen. 

Mit der Funktion attachInterrupt definierst du die Bewegungsmeldung. Im ersten Parameter steht der Pin, an dem der Sensor angeschlossen ist. Im zweiten, was passieren soll, wenn etwas erkannt wurde: die Funktion detectingMovement() ausführen. Der dritte Parameter definiert, wann das passieren soll – nämlich wenn das Signal am Pin von LOW auf HIGH wechselt.


Genauere Erläuterungen dieser Funktion findest du in der Arduino-Referenz.

void setup() {
  Serial.begin(115200);
  client.setInsecure();
  pinMode(sensor, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(sensor), detectingMovement, RISING);
}

Der Loop

Hier kommt also der entscheidende Teil des Sketches. Der Loop läuft die meiste Zeit, ohne dass er irgendetwas ausführt. Erst wenn der Sensor ein Signal sendet und der Interrupt die Variable motion auf true setzt, wird die Bedinung im If-Statement erfüllt und einiges in Gang setzt.
Zunächst wird die Funktion connectToWiFi() aufgerufen und dein ESP8266 verbindet sich mit dem Internet.

Die Nachricht senden

Anschließend sendet er mit bot.sendMessage() eine Nachricht an deinen Telegram-Bot. 

Das ist sozusagen das Herzstück deines Sketchs. Die Funktion sendMessage() benötigt drei Argumente: 

  1. deine userID, die du oben im Sketch eingetragen hast
  2. eine Nachricht deiner Wahl als String
  3. den Parse Mode – Optional, lassen wir in diesem Projekte leer

Wenn also dein ESP8266 mit dem Internet verbunden ist, sollte nach wenigen Sekunden die Nachricht auf deinem Smartphone erscheinen.

Zuletzt wird die Variable motion wieder auf false gesetzt und die Verbindung zum Internet gekappt.

void loop() {

  if (motion == true) {
    connectToWiFi();
    bot.sendMessage(userID, "Hier bewegt sich etwas!", "");
    Serial.println("Bewegung erkannt");
    motion = false;
    WiFi.disconnect();
  }
}

Danach befindet sich dein Projekt wieder im Ausgangszustand und wartet auf die nächste Bewegung.
Falls noch nicht geschehen, lade den Sketch auf deinen ESP8266 und probiere ihn gleich aus. Und vergiss nicht: Vor dem ersten Test musst du deinen Bot zunächst einmalig starten, indem du auf start tappst.

Feinjustierung des Sensors

Auf der Unterseite des Sensors findest du zwei Potentiometer. Wenn du Sensor umdrehst, sodass die Platine nach oben zeigt, kannst du am linken Potentiometer die Empfindlichkeit einstellen. Experimentiere hiermit etwas, um die optimale Reichweite des Bewegungsmelders einzustellen.

Am rechten Potentiometer lässt sich einstellen, wie lange der Sensor ein HIGH-Signal sendet, bevor er wieder zurückgesetzt wird und neue Bewegungen erkennen kann. Diese Funktion nutzt du in diesem Projekt allerdings nicht, da der Sensor hier einen Interrupt triggert. Wie lange der Sensor das HIGH-Signal sendet, spielt hier keine Rolle.

Wie geht es weiter?

Du hast nun einen Bewegungsmelder, den du als stillen Alarm einsetzen kannst und der dir Nachrichten an deinen Telegram-Bot sendet. Im zweiten Teil dieser Projektserie überwachst du die Temperatur: Sobald ein von dir bestimmter Wert überschritten wurde, erhältst du eine Nachricht aufs Smartphone.

Auf pollux labs haben wir viele Tutorials und Projekte, die sich mit Temperatur- und anderen Sensoren beschäftigen.

Viel Spaß beim Ausprobieren! 🙂

]]>
Mehr Möglichkeiten mit IFTTT PRO https://polluxlabs.net/news/mehr-moeglichkeiten-mit-ifttt-pro/ Wed, 16 Sep 2020 11:15:45 +0000 https://polluxlabs.net/?p=2450 Der Service IFTTT (If This Then That) bietet seit kurzem ein PRO-Upgrade an. Wer sich dafür entscheidet, erhält die Möglichkeit, komplexere Anwendungen zu bauen. Bisher gab es nur die Möglichkeit, eine einzige Bedingung und eine daraus resultierende Aktion zu definieren.

Auch hier bei pollux labs haben wir eine Alarmanlage, die IFTTT nutzt: Ein Radar-Sensor registriert eine Bewegung, der angeschlossene ESP8266 triggert IFTTT und du erhältst eine Benachrichtigung.

Laut IFTTT können User mit PRO-Account also künftig sogenannte Applets bauen, die

  • mehrere Schritte ausführen
  • selbstständig Abfragen ausführen, um weitere Daten einzuholen
  • wiederum andere Applets triggern und
  • schneller ausgeführt werden

Leider gibt es auch eine Schattenseite: Der Gratis-Account mit Einführung von IFTTT PRO auf drei eigene Applets beschränkt. Vorgefertigte Applets von Unternehmen und anderen Usern kannst du jedoch weiterhin unbegrenzt nutzen. Auf der Webseite des Services findest du weitere Informationen.

Interessant ist die Preisgestaltung zur Einführung: Regulär wird der PRO-Account 9,99$ kosten. Momentan kannst du dir den Preis dafür jedoch selbst aussuchen – solange er über 1,99$ liegt. Dieses Angebot gilt bis zum 7. Oktober 2020. Einen Gratis-Testphase gibt es leider nicht.

Wenn du also eine Projektidee im Kopf hast, für die du IFTTT verwenden möchtest, die jedoch zu komplex für den Gratis-Account ist, könnte sich ein Test für dich lohnen.

]]>
Ein Dash Button mit Telegram und einem ESP8266 https://polluxlabs.net/esp8266-projekte/ein-dash-button-mit-telegram-und-einem-esp8266/ Tue, 15 Sep 2020 20:05:51 +0000 https://polluxlabs.net/?p=2395 In diesem Projekt baust du dir mit einem ESP8266 einen Dash Button, der dir auf Knopfdruck eine Nachricht an deinen Telegram Account sendet. Du kannst diese Nachricht auf deinem Smartphone überall empfangen – solange du Internet hast.

Anfänger

1 – 2 Stunden

ca. 10 €

Für dieses Projekt benötigst du (Mengen s. Beschreibung):

Telegram vorbereiten

Zunächst benötigst du einen Account bei Telegram – und die dazugehörige App für dein Smartphone oder den Computer. Im Folgenden verwenden wir ein Smartphone. Telegram ist kostenlos, werbefrei und funktioniert so ähnlich wie WhatsApp. Allerdings hast du hier die Möglichkeit, Bots zu erstellen, mit denen du interagieren kannst.

Das machst du dir in diesem Projekt zunutze, indem du deinen ESP8266 mit deinem Telegram-Bot „sprechen“ lässt. Der Bot wiederum sendet dir daraufhin umgehend eine Benachrichtigung.

Erstelle einen Telegram-Bot

Lade dir also – falls noch nicht geschehen – Telegram aus dem Play Store bzw. App Store auf dein Smartphone. Erstelle dir dort einen Account und suche anschließend unter Chats nach Botfather.

Botfather in Telegram

Öffne den Botfather und tappe anschließend auf Start. Nach seiner Begrüßung erhältst du eine Anleitung. Diese kannst du dir jetzt durchlesen, oder gleich auf /newbot tappen. Danach fragt dich der Botfather nach einem Namen für deinen Bot und einen Usernamen:

Einen neuen Bot in Telegram erstellen

Nachdem du die Namen vergeben hast, erhältst du eine Nachricht mit deinem Token. Den benötigst du später in deinem Sketch, um deinen ESP8266 mit deinem Telegram-Bot zu verbinden.

Den Token für deinen Telegram-Bot erhalten

Besorge dir deine User ID

Du hast jetzt einen Telegram-Bot erstellt. Jetzt benötigst du nur noch deine User ID, um dem Bot Nachrichten senden zu können. Auch das dauert nur wenige Sekunden.

Gehe in der Telegram-App wieder zu den Chats und such dort nach IDBot:

IDBot in Telegram suchen

Tappe nun auf IDBot und im folgenden Chat-Fenster auf /getid. Du erhältst umgehend eine Nachricht mit deiner User ID:

Und das waren auch schon die Vorbereitungen in Telegram. Halte deinen Token und deine User ID bereit, um sie später in den Sketch einzutragen. Und halte sie vor allem geheim, damit niemand anders deinen Bot verwendet.

Das Projekt aufbauen

Für den Aufbau auf deinem Breadboard benötigst du nur wenige Minuten. Orientiere dich einfach an diesem Schema:

Aufbau Dash Button mit Telegram

Der Button ist per Pull-Down-Widerstand am ESP8266 angeschlossen, damit er stabil eine 0 an deinen Microcontroller sendet, solange du ihn nicht drückst. Erst wenn das der Fall ist, empfängt dein ESP8266 ein Signal und sendet eine Nachricht an deinen Telegram-Bot.

Sobald die Nachricht gesendet wurde, leuchtet die LED kurz auf.

Der Sketch für den Dash Button

Nun wird es Zeit für etwas Code. Falls du noch nie einen ESP8266 mit der Arduino IDE verwendet hast: In diesem Tutorial lernst du, wie du deinen ESP8266 in der Arduino IDE verfügbar machen und programmieren kannst.

Die benötigten Bibliotheken

Für deinen Dash Button benötigst du insgesamt drei Bibliotheken. Zwei davon sollten bei dir schon vorinstalliert sein: ESP8266WiFi.h und WiFiClientSecure.h – du benötigst sie für die Verbindung zu deinem WLAN-Netzwerk und zum Senden der Daten.

Die Bibliothek UniversalTelegramBot.h übernimmt die Kommunikation mit deinem Telegram-Bot. Du findest sie im Bibliotheksverwalter der Arduino IDE –diese kann jedoch veraltet sein. Deshalb empfehlen wir dir, die Bibliothek hier bei uns herunterzuladen.

Anschließend musst du diese Bibliothek in deinen Sketch einbinden, indem du im Menü der Arduino IDE Sketch -> Bibliothek einbinden -> .ZIP-Bibliothek hinzufügen wählst und die gerade heruntergeladene ZIP-Datei auswählst.

Kopiere dir nun den folgenden Sketch, lade ihn auf deinen ESP8266 und probiere den Dash Button gleich aus!

Hinweis: Bevor dein Telegram-Bot Nachrichten empfangen kann, musst du ihn erst aufrufen und auf Start tappen. Das musst du allerdings nur einmal zu Beginn tun.

Sketch als .txt anschauen

/*
   Dash Button mit Telegram und einem ESP8266 - polluxlabs.net
*/

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>

// Deine WLAN-Zugangsdaten
const char* ssid = "DEIN WLAN-NETZWERK";
const char* password = "DEIN PASSWORT";

// Den Telegram-Bot initialisieren
#define botToken "DEIN TOKEN"  // den Bot-Token bekommst du vom Botfather)

//Deine User ID
#define userID "DEINE USER ID"

WiFiClientSecure client;
UniversalTelegramBot bot(botToken, client);

// Zustand des Buttons
int switchState = 0;

void setup() {
  Serial.begin(115200);
  client.setInsecure();

  // Verwendete Pins
  pinMode(13, INPUT); //Button
  pinMode(15, OUTPUT); //LED


  // Verbindung zum WLAN
  Serial.print("Verbinde mit mit: ");
  Serial.println(ssid);

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

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  Serial.println("");
  Serial.println("Verbunden!");

  bot.sendMessage(userID, "Bot gestartet", "");
}

void loop() {

  switchState = digitalRead(13);
  Serial.println(switchState);
  if (switchState) {
    bot.sendMessage(userID, "Button!", "");

    digitalWrite(15, HIGH);
    delay(200);
    digitalWrite(15, LOW);
    delay(200);
    digitalWrite(15, HIGH);
    delay(200);
    digitalWrite(15, LOW);
  }
}

Schauen wir uns nun ein paar wichtige Teile des Sketchs genauer an.

Zunächst gibt es einige Daten, die du durch deine eigenen ersetzen musst: Deine WLAN-Zugangsdaten sowie dein Token und deine User ID von Telgram. Trage diese Daten hier ein:

const char* ssid = "DEIN WLAN-NETZWERK";
const char* password = "DEIN PASSWORT";
#define botToken "DEIN TOKEN"
#define userID "DEINE USER ID"

Anschließend erstellst du eine Instanz von WiFiClientSecure names client und ebenso einen bot mit deinem oben definierten botToken und dem client.

WiFiClientSecure client;
UniversalTelegramBot bot(botToken, client);

Im Setup des Sketchs definierst du die beiden Pins, die du verwendest. Die 13 steht hierbei für den Pin D7 am ESP8266 und die 15 für den Pin D8.

  pinMode(13, INPUT); //Button
  pinMode(15, OUTPUT); //LED

Zuletzt startest du die Verbindung zum Internet. Sobald diese steht, sendet dein Sketch eine erste Nachricht mit dem Hinweis, dass der Bot gestartet wurde.

Im Loop wartet dein Sketch nun darauf, dass du den Button drückst. Sobald das der Fall ist, sendet die Funktion bot.sendMessage() eine Nachricht an den Telegram-Bot. Danach leuchtet die LED zwei Mal kurz auf.

  switchState = digitalRead(13);
  if (switchState) {
    bot.sendMessage(userID, "Button!", "");

    digitalWrite(15, HIGH);
    delay(200);
    digitalWrite(15, LOW);
    delay(200);
    digitalWrite(15, HIGH);
    delay(200);
    digitalWrite(15, LOW);
  }

Die Nachricht, die du senden möchtest, kannst du in der Funktion bot.sendMessage() natürlich selbst definieren.

Wie geht es weiter?

Du hast nun einen Dash Button, der Nachrichten an deinen Telegram-Bot senden kann. Eine ähnliches Projekt könnte ein z.B. ein Temperatursensor sein, der bei einer voreingestellten Temperatur einen Warnhinweis an dein Smartphone sendet.

Auf pollux labs haben wir viele Tutorials und Projekte, die sich mit Temperatur- und anderen Sensoren beschäftigen.

Viel Spaß beim Ausprobieren! 🙂

]]>
Mit dem Arduino JSON abrufen & dekodieren mit (ArduinoJson) https://polluxlabs.net/arduino-tutorials/json-abrufen-dekodieren-mit-arduinojson/ Sun, 02 Aug 2020 18:15:40 +0000 https://polluxlabs.net/?p=1999 Wenn du mit deinem ESP8266 oder ESP32* oder auch mit dem Arduino im Internet bist, dann sicher nicht ohne Grund. Vielleicht möchtest du Daten von einer API abrufen und in deinem Projekt weiterverwenden. In diesem Tutorial lernst du, wie du mit dem Arduino JSON lädst und mithilfe der Bibliothek ArduinoJson dekodierst (oder parst).

Hier verwenden wir einen ESP8266* – du kannst mit ein paar Anpassungen im Code aber auch jeden anderen Microcontroller verwenden, mit dem du ins Internet kommst. In diesem Tutorial auf pollux labs erfährst du, wie du deinen ESP8266 mit dem Internet verbindest.

Anschließend wirst du eine API kontaktieren und dir JSON-Daten herunterladen, die die aktuelle Anzahl von Menschen im Weltraum enthalten. Diese Daten wirst du lokal dekodieren (oder parsen) und in deinem Seriellen Monitor anzeigen.

Die Bibliothek ArduinoJson

Bevor du loslegen kannst, benötigst du die aktuelle Version der Bibliothek ArduinoJson. Hierbei handelt es sich um eine wirklich praktische Erweiterung, die dir die meiste Arbeit mit JSON abnimmt.

Hinweis: Dieses Tutorial bezieht sich auf die Bibliothek ArduinoJson bis zur Version 6.17 – in unserem kostenlosen ESP8266 Online-Kurs erklären wir, wie die neueste Version funktioniert.

Öffne also deinen Bibliotheksverwalter in der Arduino IDE und suche dort nach ArduinoJson. Installiere dir die neueste Version.

ArduinoJson Bibliothek

Binde die Bibliothek nun ganz oben in deinem Sketch ein:

#include <ArduinoJson.h>

Der API Call

Um herauszufinden, wie viele Astronauten gerade im Weltall sind, fragen wir eine API von open-notify.org ab – und zwar unter folgender URL:

  http://api.open-notify.org/astros.json

Wenn du diese URL kopierst und in deinem Browser öffnest, siehst du bereits die Rohdaten im JSON-Format. Recht am Anfang findest du „number“ und dahinter die aktuelle Anzahl Astronauten im Weltraum. Heute – am 2. August 2020 – sind das 5.

Um diese Zeichenkette auf deinen ESP8266 zu bekommen, benötigst du folgenden Code:

HTTPClient http; //Instanz von HTTPClient starten
http.begin("http://api.open-notify.org/astros.json"); //URL für die Abfrage
int httpCode = http.GET(); //Antwort des Servers abrufen
    if (httpCode == 200) { 
      String payload = http.getString(); //Daten in eine Variable speichern
      }

Jetzt befinden sich die Rohdaten, die du von der API geladen hast, in der Variable payload. Schön und gut, aber um diese Daten weiterverarbeiten zu können – z.B. die aktuelle Anzahl Astronauten auf einem Display anzuzeigen – musst du sie zunächst dekodieren. Und hier kommt wieder die Bibliothek ArduinoJson ins Spiel.

Mit dem Arduino JSON dekodieren

Mit dieser Bibliothek greifst du dir einzelne Daten aus dem JSON-String (den Rohdaten) und speicherst sie in Variablen deiner Wahl. Damit sie jedoch ihre Arbeit erledigen kann, muss sie zunächst wissen, wie groß die Rohdaten sind, um sich selbst genügend Arbeitsspeicher zu reservieren.

Hierfür gibt es einen praktischen Assistenten. Öffne zunächst die URL der API und kopiere dir mit Strg + A und Strg + C sämtliche Zeichen.

Öffne anschließend den Assistenten von ArduinoJson und füge sie dort ins linke Feld ein.

Anschließend siehst du unter dem Eingabefeld den Abschnitt Parsing program – hier befinden sich sämtliche Befehle und Informationen, die du nun benötigst. In der ersten Zeile steht die Speichermenge in der Konstanten capacity. In unserem Fall ist das

const size_t capacity = JSON_ARRAY_SIZE(5) + 5*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + 200;

Beachte hierbei: Sollte der JSON-String länger werden (weil z.B. ein ganzer Haufen Astronauten in den Weltraum aufbricht), dann benötigst du auch mehr Speicher für ArduinoJson. Ansonsten würde es zu einer entsprechenden Fehlermeldung kommen.

Der nächste Befehl, den du nun anpassen musst ist dieser:

deserializeJson(doc, payload);

Hier findest du die Variable payload, in der die Rohdaten von der API stecken. Mit der Funktion deserializeJson() werden diese nun dekodiert.

Anschließend kannst du sie deinen eigenen Variablen zuweisen. Wir beschränken uns hier ja auf die Anzahl Astronauten im Weltraum, weswegen wir nur eine Variable benötigen. Der Assistent von ArduinoJson schlägt dir bereits eine vor, deren Name auf dem Key („number“) in den JSON-Daten beruht.

int number = doc["number"];

Um zu prüfen, ob alles funktioniert hat, gibst du diese Variable nun in deinem Seriellen Monitor aus:

Serial.println(number);

Wir haben hier heute eine 5 stehen – welche Zahl hast du? Hier nun der gesamte Sketch zum Kopieren und Weiterverwenden:

#include <ESP8266WiFi.h> //WiFI
#include <ArduinoJson.h> //JSON
#include <ESP8266HTTPClient.h> //API-Abfrage

// WIFI-Zugangsdaten
const char* ssid = "NETZWERK";
const char* password =  "PASSWORT";

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password); //Internet-Verbindung starten

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  delay(1000);
  Serial.println("Hello, world!");
}

void loop() {
  if ((WiFi.status() == WL_CONNECTED)) {

    HTTPClient http; //Instanz von HTTPClient starten
    http.begin("http://api.open-notify.org/astros.json"); //Abfrage-URL
    int httpCode = http.GET(); //Antwort des Servers abrufen

    if (httpCode == 200) {
      String payload = http.getString(); //Daten in eine Variable speichern
      const size_t capacity = JSON_ARRAY_SIZE(5) + 5 * JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + 200;
      DynamicJsonDocument doc(capacity);
      deserializeJson(doc, payload);
      int number = doc["number"];
      Serial.println(number);
    }
  }
  delay(10000);
}

Wie geht es weiter?

Jetzt wo du weißt, wie du an Daten im JSON-Format herankommst und sie weiterverwendest, stehen dir ganz neue Möglichkeiten offen. Wie wäre es z.B. mit einer LEGO ISS, die leuchtet, wenn die echte ISS über ihr fliegt?

]]>
So verwendest du Bluetooth am ESP32 https://polluxlabs.net/arduino-tutorials/so-verwendest-du-bluetooth-am-esp32/ Thu, 30 Jul 2020 07:27:43 +0000 https://polluxlabs.net/?p=1845 Bluetooth ist allgegenwärtig und auch dein ESP32 kann damit umgehen. Lerne in diesem Tutorial, wie du Bluetooth Classic verwendest und Daten zwischen einem Smartphone und deinem ESP32 austauschst.

Für dieses Tutorial benötigst du nur einen ESP32 und ein Android-Smartphone, auf dem du die kostenfreie App Serial Bluetooth Terminal installieren kannst.

So machst du deinen ESP32 in der Arduino IDE verfügbar

Falls du deinen ESP32 bisher noch nicht mit der Arduino IDE programmiert hast, führe bitte erst die folgenden Schritte durch:

Öffne die Einstellungen der IDE und trage in des Feld Zusätzliche Boardverwalter-URLs folgenden Link ein.

https://dl.espressif.com/dl/package_esp32_index.json

Öffne anschließend den Boardverwalter unter Werkzeuge/Board. Suche dort nach ESP32 und installiere dir die neueste Version des gleichnamigen Pakets von espressif Systems. Und das war es auch schon – du solltest deinen ESP32 nun wie jedes andere Board in der Arduino IDE auswählen und verbinden können.

Der Sketch für deinen ESP32

Für ein grundlegendes Experiment mit Bluetooth benötigst du nur wenig Code:

#include "BluetoothSerial.h"

BluetoothSerial SerialBT;

void setup() {
  Serial.begin(115200);
  SerialBT.begin("ESP32test"); //Name des ESP32
  Serial.println("Der ESP32 ist bereit. Verbinde dich nun über Bluetooth.");
}

void loop() {
  if (Serial.available()) {
    SerialBT.write(Serial.read());
  }
  if (SerialBT.available()) {
    Serial.write(SerialBT.read());
  }
  delay(25);
}

Schauen wir uns die wichtigsten Teile genauer an: Zunächst bindest du die Bibliothek BluetoothSerial.h ein, die bereits in deiner Arduino IDE verfügbar ist und nicht extra installiert werden muss. Anschließend erstellst du eine Instanz namens SerialBT.

Im Setup startest du die serielle Kommunikation mit einer Baudrate von 115200 – achte darauf, dass dein Serieller Monitor auch auf diese Rate eingestellt ist. Anschließend initialisierst du Bluetooth und gibst deinem ESP32 den Namen ESP32test.

Im Loop befinden sich zwei Abfragen: Die erste prüft, ob du etwas in den Seriellen Monitor eingetragen und abgeschickt hast.

Wenn das der Fall ist, schickst du die Daten an den ESP32:

SerialBT.write(Serial.read());

In der zweiten Abfrage wird geprüft, ob der ESP32 etwas über Bluetooth empfangen hat. Diese Daten werden dann im Seriellen Monitor ausgegeben.

Ein erster Test

Gehen wir also zur Praxis über. Für diesen Test verbindest du ein Android-Smartphone mit deinem ESP32 und schickst Nachrichten von einem Gerät aufs andere.

Lade zunächst den obigen Sketch wie gewohnt auf deinen ESP32 und starte den Seriellen Monitor mit der Baudrate 115200. Sollte sich hier nichts tun, drücke den Reset- oder Enable-Button am ESP32. Anschließend sollte nach einigen Hardware-Informationen folgender Satz aus deinem Sketch angezeigt werden: Der ESP32 ist bereit. Verbinde dich nun über Bluetooth.

In den Bluetooth-Einstellungen deines Smartphone solltest du nun deinen ESP32 mit dem Namen ESP32test sehen und eine Verbindung herstellen können.

ESP32 mit dem Smartphone pairen

Falls noch nicht geschehen, lade dir die App Serial Bluetooth Terminal aus dem Play Store und öffne sie. Unter dem Menüpunkt Devices/Bluetooth Classic erscheint nun ebenfalls dein ESP32, mit dem du dich mit einem Tap verbinden kannst.

ESP32 im Serial Bluetooth Terminal auswählen

Zeit für etwas Konversation! Schreibe deinem ESP32 in der App eine Nachricht und sende sie ab. Dein Text wird auf der Gegenseite empfangen und im Seriellen Monitor ausgegeben.

Nachricht an einen ESP32 senden

In die andere Richtung funktioniert das genauso. Schreibe etwas in das Eingabefeld oben in deinem Seriellen Monitor und klicke auf Senden. Diese Nachricht wird dann von deinem ESP32 aus an dein Smartphone gesendet und dort angezeigt:

Nachricht vom ESP32 empfangen

Und das war auch schon dein erster Test. Wenn du Nachrichten hin und herschicken kannst, geht das natürlich auch mit allen anderen Daten.

Als nächstes kannst du einen Sensor an den ESP32 anschließen und dessen Daten in regelmäßigen Abständen an dein Smartphone senden. Oder andersherum mit deinem Smartphone z.B. eine LED an deinem Microcontroller an- und ausschalten. Wie du vom Smartphone aus Geräte steuert, lernst du auch in unserem Kurs Dein eigener ESP8266 Webserver.

]]>
ESP8266 programmieren mit der Arduino IDE https://polluxlabs.net/arduino-tutorials/esp8266-und-wemos-d1-mini-mit-der-arduino-ide-programmieren/ Thu, 14 May 2020 13:24:33 +0000 https://polluxlabs.net/?p=1621

Ein EPS8266 oder auch ein Wemos D1 Mini ist ein echter Gewinn für deine Projekte. Mit diesen Microcontrollern stößt du die Tür zum Internet of Things ganz weit auf! Und das beste: Du kannst ganz einfach mit deiner Arduino IDE deinen ESP8266 programmieren – genauso wie deine Arduino-Boards. Ein paar Vorbereitungen musst du hierfür allerdings treffen.

Lerne hier, wie du in 5 Minuten deinen EPS8266 oder D1 Mini in deiner Arduino IDE installierst und anschließend mit dem Programmieren loslegen kannst.

Deinen ESP8266 oder D1 Mini in der Arduino IDE installieren

Öffne zuerst die Einstellungen deiner Arduino IDE. Dort findest du das Feld Zusätzliche Boardverwalter-URLs. Trage hier die folgende Adresse ein:

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

Tipp: Wenn du dort schon die URL deines ESP32 eingetragen hast, schreibe die des ESP8266 einfach mit einem Komma getrennt dahinter. Dann verfügst du in der Arduino IDE über beide.

Schließe nun das Fenster mit einem Klick auf OK. Öffne als nächstes das Menü Werkzeuge und wähle dort den Menüpunkt Boards und anschließend Boardverwalter.

Suche in dem Fenster, das sich jetzt öffnet, nach ESP8266. Scrolle etwas nach unten, bis du den Eintrag ESP8266 by ESP8266 Community findest. Noch ein Klick auf Installieren, kurz warten und das sollte es gewesen sein. 🙂

Das Paket für dein ESP8266 installieren
Das Paket für dein ESP8266 installieren

Hinweis: Solltest du mit dem ESP8266 in der Arduino IDE Probleme beim Hochladen deiner Sketches haben, installiere probeweise eine frühere Version des Boards.

Deinen ESP8266 mit einem Sketch programmieren

Jetzt kannst du loslegen und deinen ESP8266 programmieren. Du hast ja bestimmt schon einmal die fest installierte LED auf einem Arduino blinken lassen – das funktioniert auch auf deinem ESP8266.

Erstelle also einen neuen Sketch mit folgendem Code:

/*
Blinkende LED
https://polluxlabs.net
*/

#define LED D0

void setup() {
 pinMode(LED, OUTPUT);
 }

void loop() {
 digitalWrite(LED, LOW);
 delay(500);
 digitalWrite(LED, HIGH);
 delay(500);
 }

Schließe nun deinen ESP8266 an den USB-Port deines Computers an. Wähle noch einmal im Menü den Punkt Werkzeuge und wähle unter Board den Eintrag NodeMCU 1.0 und den Port, an dem dein ESP8266 angeschlossen ist.

Für deinen Wemos D1 Mini* wähle den Eintrag LOLIN(WEMOS) D1. Falls du eine Pro- oder Lite-Version hast, wähle natürlich den entsprechenden Eintrag.

Lade jetzt den Sketch hoch. Wenn alles funktionert hat, blinkt die Onboard-LED im Halbsekundentakt.

Spannende ESP8266 Projekte

Zeit für etwas mehr Internet of Things? Hier sind ein paar spannende Projekte, die du mit deinem ESP8266 umsetzen kannst:

]]>
Dein eigener ESP8266 Webserver https://polluxlabs.net/esp8266-projekte/dein-eigener-esp8266-web-server/ Tue, 18 Feb 2020 14:42:26 +0000 https://polluxlabs.net/?p=1037 Der Microcontroller ESP8266 eignet sich nicht nur perfekt, um Daten aus dem Internet abzurufen und zu verarbeiten. Mit ein paar Zeilen Code baust du dir daraus deinen eigenen ESP8266 Webserver.

So kannst du mit deinem Smartphone oder Computer z.B. auf aktuelle Messdaten von Sensoren zugreifen, oder auch Bauteile an- und ausschalten – Internet of Things pur! 🙂

Weitere Bauteile findest du in unserem Online-Shop.

Der Code für deinen Webserver

Da ein Aufbau auf einem Breadboard bei diesem Projekt entfällt (du benötigst nur deinen Microcontroller), können wir gleich mit dem Sketch starten. Wenn du den ESP8266 bisher noch nicht verwendet hast, lies zunächst dieses Tutorial, um den ESP8266 mit der Arduino IDE programmieren zu können.

Die einzige Bibliothek, die du brauchst, ist die ESP8266WiFi.h – wenn du sie noch nicht installiert hast, hol das gleich in deinem Bibliotheksverwalter nach. Anschließend integrierst du sie ganz am Anfang deines Sketchs:

#include <ESP8266WiFi.h>

Ebenfalls noch vor der Funktion void Setup() hinterlegst du deine Zugangsdaten für dein WiFi-Netzwerk, legst den Port des Servers fest und definierst eine Variable:

// Daten des WiFi-Netzwerks
const char* ssid     = "Dein Netzwerkname";
const char* password = "Dein Passwort";

// Port des Webservers auf 80 setzen
WiFiServer server(80);

// Variable für den HTTP Request
String header;

Grundlegende Informationen darüber, wie ein HTTP Request – also der Abruf von Daten von einem Server – funktioniert, kannst du in diesem Beitrag nachlesen.

Den ESP8266 Webserver mit dem WLAN verbinden

In der Setup-Funktion startest du den Seriellen Monitor und verbindest deinen Server mit dem Internet. Sobald die Verbindung steht, gibt er im Monitor die IP-Adresse aus – diese kannst du in einem Browser auf deinem Computer oder Smartphone wie eine normale Internet-Adresse aufrufen.

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

  // Mit dem WiFi-Netzwerk verbinden
  Serial.print("Connecting to WiFi");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Lokale IP-Adresse im Seriellen Monitor ausgeben und Server starten
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

Der Loop – Server aufrufen und Daten abrufen

Jetzt ist es soweit: Du rufst den ESP8266 Webserver in deinem Browser auf. Dieser empfängt deinen HTTP Request und antwortet darauf mit einer einfachen Webseite. Mit einer sehr einfachen Webseite, wie du gleich sehen wirst. 🙂

Zunächst benötigst du eine Zeile Code, die dafür sorgt, dass dein Server auf Clients (also Aufrufe) wartet:

WiFiClient client = server.available(); 

Wenn das der Fall ist, erscheint eine entsprechende Meldung im Seriellen Monitor. Anschließend benötigst du eine neue Variable für den Text, den der Client mit seinem Request sendet:

if (client) {                        
    Serial.println("Client available");
    String currentLine = "";     

Jetzt folgt ein While Loop, der dafür sorgt, dass sowohl dein Server den HTTP Request empfangen kann als auch eine Antwort an den Client senden kann. Die Anfrage des Clients speicherst du – Byte für Byte – einer Hilfsvariablen (c), die wiederum Stück für Stück die Variable header füllt, die du ganz am Anfang des Sketchs definiert hast.

Sobald ein Zeilenumbruch (\n) kommt und der Client anschließend eine Leerzeile sendet (currentLine. length() == 0), ist die Anfrage beendet. Zeit für eine Antwort!

while (client.connected()) { 

      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        header += c;

        if (c == '\n') {

          if (currentLine.length() == 0) {

Der ESP8266 Webserver antwortet und sendet das HTML für die Webseite

Bevor die Webseite in deinem Browser erscheint, erhält dieser zunächst eine Statusmeldung vom Server: 200 OK steht hierfür für den geglückten Request. Danach kommt die Information, welche Daten gleich gesendet werden, nämlich Text in Form von HTML: Content-type:text/html. Danach noch die Info, dass die Verbindung geschlossen wird, sobald der Request vollständig abgeschlossen wurde – und eine Leerzeile.

client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();

Endlich Zeit für die Webseite. Wie angekündigt ist diese sehr einfach, denn sie besteht nur aus einer einzigen Überschrift. Aber das reicht ja für den Anfang. 🙂

Überschriften sind in HTML hierarchisch geordnet und erhalten ein entsprechendes Tag – von H1 bis H6. Üblicherweise hat jede Webseite (genau) eine H1-Überschrift für den Titel der Webseite.

Die Überschrift steht zwischen dem öffnenden <h1> und dem schließenden HTML-Tag </h1>. Im öffnenden Tag bringst du allerdings noch die Information unter, dass der Text zentriert auf dem Bildschirm erscheinen soll: align=\“center\“.

Noch ein Hinweis: Die umgedrehten Schrägstriche (Backslashes) benötigst du im Code, um die Anführungszeichen zu „maskieren“. Ansonsten würde die Arduino IDE sie als Teil von C++ interpretieren statt als Text, der über die Funktion client.println() von deinem ESP8266 Webserver ausgegeben wird.

Möchtest du mehr über HTML und CSS wissen? In weiteren Verlauf dieses Projekts lernst du die Grundlagen eines schicken Interfaces für den Server.

client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<link rel=\"icon\" href=\"data:,\"></head>");
client.println("<body><h1 align=\"center\">Hier spricht dein Server! :)</h1></body></html>");

Alles, was in deinem Sketch jetzt noch folgt, sind Abfragen für die Variable currentLine und etwas Code zum Beenden der Verbindung des Clients mit dem Server. Diese Zeilen findest du hier im vollständigen Sketch unten.

Der vollständige Sketch

// Library für WiFi-Verbindung
#include <ESP8266WiFi.h>

// Daten des WiFi-Netzwerks
const char* ssid     = "Dein Netzwerkname";
const char* password = "Dein Passwort";

// Port des Webservers auf 80 setzen
WiFiServer server(80);

// Variable für den HTTP Request
String header;

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

  // Mit dem WiFi-Netzwerk verbinden
  Serial.print("Connecting to WiFi");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Lokale IP-Adresse im Seriellen Monitor ausgeben und Server starten
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop() {
  WiFiClient client = server.available();   // Auf Clients (Server-Aufrufe) warten

  if (client) {                             // Bei einem Aufruf des Servers
    Serial.println("Client available");
    String currentLine = "";                // String definieren für die Anfrage des Clients

    while (client.connected()) { // Loop, solange Client verbunden ist

      if (client.available()) {
        char c = client.read();             // Ein (1) Zeichen der Anfrage des Clients lesen
        Serial.write(c);                    // und es im Seriellen Monitor ausgeben
        header += c;
        if (c == '\n') {                    // bis eine Neue Zeile ausgegeben wird

          // Wenn der Client eine Leerzeile sendet, ist das Ende des HTTP Request erreicht
          if (currentLine.length() == 0) {

            // Der Server sendet nun eine Antwort an den Client
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            // Die Webseite anzeigen
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\"></head>");
            client.println("<body><h1 align=\"center\">Hier spricht dein Server! :)</h1></body></html>");

            // Die Antwort mit einer Leerzeile beenden
            client.println();
            // Den Loop beenden
            break;
          } else { // Bei einer Neuen Zeile, die Variable leeren
            currentLine = "";
          }
        } else if (c != '\r') {  // alles andere als eine Leerzeile wird
          currentLine += c;      // der Variable hinzugefüht
        }
      }
    }
    // Variable für den Header leeren
    header = "";
    // Die Verbindung beenden
    client.stop();
    Serial.println("Client disconnected");
    Serial.println("");
  }
}

Erweitere deinen Webserver

Im Folgenden lernst, wie du mit deinem ESP8266 Webserver Geräte steuerst und die aktuelle Temperatur auf einer selbst erstellten Webseite ablesen kannst.

  • Einen Temperatursensor anschließen
  • Eine LED anschließen
  • Den Webserver einrichten und steuern
  • Wie warm ist es gerade?
  • Autoreload der Webseite
  • Die LED steuern
  • CSS und HTML für eine schönere Webseite
  • Eine feste IP-Adresse vergeben

Einen Temperatursensor anschließen

Natürlich gibt es eine Vielzahl von Sensoren, deren Daten du über einen Webserver überprüfen kannst. Wir möchten hier jedoch den wohl beliebtesten Anwendungsfall beschreiben – Temperaturdaten.

Hierfür gibt es auf dem Markt einige günstige Sensoren, die immer wieder zum Einsatz kommen und die sich bewährt haben. Du kannst sie im Handumdrehen anschließen und dank der passenden Bibliotheken ebenso einfach die Temperatur messen.

Schauen wir uns drei der bekanntesten Sensoren an: Den BMP180, den GY-906, den DHT22 und DHT11.

DEN BMP180 ANSCHLIESSEN

Diesen Sensor schließt du per I²C an deinem ESP8266 an. Wie du hier siehst, benötigst du hierfür die Pins D1 und D2.

ESP8266 Pinout

Orientiere dich beim Aufbau an folgender Skizze:

Anschluss BMP180 am ESP8266

DIE PASSENDE BIBLIOTHEK

Neben der bereits vorinstallierten Bibliothek Wire (für die Kommunikation per I²C), benötigst du noch eine weitere, um die Daten des Sensors problemlos auslesen zu können.

Öffne also den Bibliotheksmanager in der Arduino IDE und suche nach BMP180. Du findest nun eine Bibliothek namens Adafruit BMP085 Library – das ist die richtige, auch wenn sie ein anderes Modell im Namen trägt. Der BMP085 war das Vorgängermodell des BMP180, was die Kommunikation angeht, jedoch mehr oder weniger baugleich.

Die richtige Bibliothek: Adafruit BMP085 Library

Installiere nun diese Bibliothek und schließe den Bibltiotheksmanager.

DIE TEMPERATUR MESSEN

Jetzt kann es mit der Messung auch schon losgehen. Kopiere dir den folgenden Sketch und lade ihn auf deinen Arduino hoch:

#include <Wire.h>
#include <Adafruit_BMP085.h>

Adafruit_BMP085 bmp;
 
void setup() {
  Serial.begin(115200);
  if (!bmp.begin()) {
Serial.println("Sensor nicht gefunden!");
while (1) {}
  }
}
 
void loop() {
    Serial.print("Temperatur = ");
    Serial.print(bmp.readTemperature());
    Serial.println(" *C");
   
    Serial.println();
    delay(2000);
}

In deinem Seriellen Monitor sollten jetzt alle 2 Sekunden die Messwerte für die Temperatur in °C erscheinen. Sollte nichts erscheinen, überprüfe, ob die Baudrate im Sketch und im Seriellen Monitor übereinstimmt oder du SCL und SDA versehentlich verwechselt hast.

DEN GY-906 ANSCHLIESSEN

Im Prinzip schließt du diesen Sensor genauso an wie den BMP180 – er kommuniziert ebenfalls über I²C. Die Skizze für den Anschluss sieht also ganz ähnlich aus:

DIE PASSENDE BIBLIOTHEK

Auch für den GY-906 gibt es eine Bibliothek, die dir das Leben einfacher macht. Suche im Bibliotheksmanager nach Adafruit_MLX90614 und installiere die aktuelle Version.

MLX90614 bezieht sich auf den Sensor selbst – GY-906 ist hingegen die Bezeichnung des ganzen Bauteils.

DIE TEMPERATUR MESSEN

Kopiere dir den folgenden Sketch und lade ihn auf deinen Arduino hoch:

#include <Adafruit_MLX90614.h>
#include <Wire.h>

Adafruit_MLX90614 mlx = Adafruit_MLX90614();

void setup() {
  Serial.begin(115200);
  mlx.begin(); 
}

void loop() {
  Serial.print("Umgebung = "); Serial.print(mlx.readAmbientTempC());
  Serial.print("*C\tObjekt = "); Serial.print(mlx.readObjectTempC());       
  Serial.println("*C");

  Serial.println();
  delay(2000);
}

Wie du siehst, bindest du zu Beginn des Sketchs die Bibliotheken für den Sensor und die Kommunikation per I²C ein. Anschließend erstellst du ein Objekt der Bibliothek mit dem Namen mlx.

Sicherlich weißt du, dass der GY-906 eine Besonderheit hat (was ihn auch etwas teurer als andere Sensoren macht): Er misst nicht nur die Umgebungstemperatur, sondern per Infrarot auch jene von Objekten.

Deshalb befinden sich im Sketch zwei Abfragen – eine für die Temperatur um den Sensor herum – mlx.readAmbientTempC() – und eine für das Objekt “vor seiner Nase” – mlx.readObjectTempC. Welche Temperatur später bei deinem Webserver zum Einsatz kommen soll, ist natürlich dir überlassen.

DEN DHT22 ANSCHLIESSEN

Etwas aufwändiger ist der Anschluss des Sensors DHT22, denn hierfür benötigst du einen 10 kΩ Widerstand. Orientiere dich beim Anschluss an dieser Skizze:

Anschluss DHT22 am ESP8266

DIE PASSENDEN BIBLIOTHEKEN

Für den DHT22 musst du zwei Bibliotheken installieren, von denen du jedoch nur eine im Sketch einbinden musst. Öffne deinen Bibliotheksmanager. Suche dort zunächst nach Adafruit Unified Sensor und installiere die aktuelle Version. Die Versionsnummer in den folgenden Screenshots können abweichen.

Suche anschließend nach DHT22 und installiere die Bibliothek DHT sensor library.

DHT Sensor Library

DIE TEMPERATUR MESSEN

Kopiere dir den folgenden Sketch und lade ihn auf deinen Arduino hoch:

#include "DHT.h"

#define DHTPIN 4  
#define DHTTYPE DHT22

float temp;

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(115200);
  dht.begin();
}

void loop() {

  temp = dht.readTemperature();
 
  Serial.print("Temperatur: ");
  Serial.print(temp);
  Serial.println("*C");

  Serial.println();
  delay(2000);

}

Nachdem du die Bibliothek eingebunden hast, legst du den Pin fest, an dem der DHT22 angeschlossen ist. In unserem Sketch ist das der Pin 4. Der Sensor ist allerdings am ESP8266 an Pin D2 angeschlossen. Wieso dann die unterschiedlichen Zahlen?

Scrolle noch einmal nach oben zum Pin-Diagramm des ESP8266. Wie du dort sehen wirst, entspricht der Pin D2 dem GPIO 4 – diese Ziffer kommt im Sketch zum Einsatz.

In der nächsten Zeile legst du das Modell des Sensors fest – in unserem Fall also ein DHT22. Anschließend erstellst du ein Objekt der Bibliothek names dht, das später bei der Messung mit der Funktion dht.readTemperature() zum Einsatz kommt.

Der Rest des Sketchs dürfte für dich kein Problem sein. Achte jedoch darauf, dass die Baudrate von Sketch und Seriellem Monitor übereinstimmt.

DEN DHT11 ANSCHLIESSEN

Der Sensor DHT11 ist so etwas wie der “kleine Bruder” des DHT22. Er hat einen kleineren Messbereich und ist auch etwas ungenauer. Trotzdem ist er gerade bei Einsteigern beliebt. Und leichter anzuschließen ist er auch:

In obigen Beispiel-Sketch musst du für den DHT11 nur eine Zeile anpassen:

#define DHTTYPE DHT11

Eine LED anschließen

Im vorangegangenen Abschnitt hast du einen Temperatursensor angeschlossen, dessen Messdaten du später über deinen Webserver auslesen wirst. Aber so ein Webserver soll natürlich keine Einbahnstraße sein: Ebenso hast du die Möglichkeit, an deinen ESP8266 ein Gerät anzuschließen, das du vom Smartphone aus steuerst.

Hier sind deiner Phantasie kaum Grenzen gesetzt. Vielleicht möchtest du die Rollläden hoch- und herunterlassen oder die Heizung an- und ausschalten. Oder einfach nur das Licht.

In diesem Abschnitt und im weiteren Verlauf des Kurses beschäftigen wir uns mit einem “Gerät”, das du sicherlich schon oft verwendet hast: eine LED. 🙂 Erweitere also zunächst dein Projekt auf dem Breadboard um eine LED samt Vorwiderstand. Orientiere dich hierbei an folgender Skizze:

ESP8266 mit BMP180 und LED

Als Beispiel soll uns eine rote Standard-LED mit einer Spannung von 2,3 V und 20 mA Stromfluss dienen. Da dein ESP8266 3,3 V “liefert”, ergibt sich hieraus ein Vorwiderstand von 51 Ω.

Verbinde die Anode (langes Bein) der LED mit dem Pin D7 des ESP8266, damit du sie mit den späteren Sketches dieses Kurses ohne Bearbeitungen steuern kannst. Die Kathode kommt mit dem Vorwiderstand dazwischen an GND.

Hast du eine andere LED im Sinn? Mit diesem Rechner kannst du den richtigen Vorwiderstand berechnen.

SO STEUERST DU “GROSSE” GERÄTE

Die LED in diesem Abschnitt dient natürlich nur dem Verständnis. Sicherlich möchtest du stattdessen Geräte steuern, die mit 230 Volt versorgt werden. Auch das kannst du mit deinem ESP8266 umsetzen – allerdings benötigst du hierfür ein Relais.

Achte beim Kauf darauf, dass dieses mit den 3,3 V des ESP8266 funktioniert. Viele der erhältlichen Relais benötigen 5 V. Solltest du einen Wemos D1 Mini verwenden, kannst du sogar ein praktisches Relais-Shield darauf montieren.

Damit hast du die Grundlagen abgeschlossen. In den nächsten Abschnitten beschäftigen wir uns mit dem eigentlichen Webserver.

Den Webserver einrichten und steuern

WAS IST EIN SERVER?

Was ist eigentlich ein Server und was macht er? Lass uns dieses Thema zunächst ganz kurz betrachten.

Ein Server ist ein Computer – oder in unserem Fall ein Microcontroller – der von einem anderen Computer Anfragen nach Informationen erhält. Diese Anfragen bearbeitet er und wenn er die angeforderten Informationen besitzt, sendet er sie zurück an den Client.

Funktion eines Servers

In diesem Projekt dient bekanntlich dein ESP8266 als Server. Dein Client kann dann zum Beispiel das Gerät sein, auf dem du diesen Text gerade liest – also ein PC, Laptop, Tablet oder Smartphone.

Informationen können dann zum Beispiel “bloße” Messdaten sein oder auch eine Webseite, die diese Messdaten enthält.

Aber nicht nur das: Dein Webserver kann ebenso Befehle erhalten, die deinen ESP8266 dann etwas steuern lassen. So kannst du zum Beispiel die im vorherigen Abschnitt erwähnte LED an- oder ausschalten. Den neuen Status der LED (also AN oder AUS) kannst du dir dann zurücksenden lassen.

In den folgenden Abschnitten tasten wir uns langsam an dieses Thema heran. Zunächst starten wir, wie man jedes ordentliche Projekt startet: Mit einem “Hello world!” Danach fragen wir die Temperatur als blanke Zahl ab. Anschließend hübschen wir diese Messdaten mithilfe von HTML auf und bauen uns ein Interface.

Zuletzt wirst du selbst aktiv und schaltest das Licht über dieses Interface an und aus.

Los geht’s! 🙂

HELLO WORLD!

Zeit, um mit unserem Webserver zu beginnen. Zunächst lassen wir den Temperatursensor und die LED noch links liegen. Stattdessen stellt dein ESP8266 auf Anfrage eine Website bereit, die erst einmal nichts als ein einfaches “Hello World” enthält.

Hello World

Damit du diese Webseite aufrufen kannst, teilt dir dein ESP8266 im Seriellen Monitor die IP-Adresse mit, die du in einem Browser deiner Wahl aufrufen kannst.

Hinweis: Beachte bitte, dass du auf deinen Webserver nur zugreifen kannst, wenn sich dein Client im gleichen WLAN-Netzwerk befindet wie dein ESP8266. Darüber, wie du von überall auf der Welt auf deinen Server zugreifen kannst – und ob du das überhaupt solltest, sprechen wir am Ende dieses Artikels.

DER ANFANG DES SKETCHS

Du hast sicherlich schon gelernt, wie du deinen ESP8266 mit dem Internet verbindest. Ohne Netzwerk kein Server – deshalb benötigen wir auch in allen folgenden Sketches dieses Kurses eine Verbindung zu deinem WLAN.

Hier noch einmal in aller Kürze. Diesen Code benötigst du am Anfang des Sketchs:

//Bibliothek für die WLAN-Verbindung
#include <ESP8266WiFi.h>

//Zugangsdaten zu deinem WLAN-Netzwerks
const char* ssid     = "SSID";
const char* password = "PASSWORT";

___STEADY_PAYWALL___

Anschließend legst du den Port deines Webservers auf 80 fest. Dieser Port ist der Teil der Netzwerk-Adresse, an der dein Webserver auf eingehende Anfragen von Clients wartet.

//Port des Webservers auf 80 setzen
WiFiServer server(80);

DAS SETUP

Hier startest du zuerst den Seriellen Monitor. Achte später darauf, dass du dort dieselbe Baudrate eingestellt hast wie im Sketch.

Serial.begin(115200);

Anschließend stellt dein ESP8266 die Verbindung zu deinem WLAN-Netzwerk her:

WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Ich verbinde mich mit dem Internet...");
  }
  Serial.println("Ich bin mit dem Internet verbunden!");

Da dein ESP8266 nun mit dem Netzwerk verbunden ist, hat er dort auch eine IP-Adresse. Diese benötigst du später, um eine Anfrage an den Server zu schicken. Damit du weißt, wie sie lautet, gibst du sie im Seriellen Monitor aus und startest danach den Server:

Serial.println("IP-Adresse: ");
Serial.println(WiFi.localIP());
 
server.begin();

DER LOOP

Die bisherigen Einstellungen und Funktionen waren noch recht überschaubar. Im Loop findet nun die gesamte Kommunikation zwischen Server und Client statt.

Zunächst benötigen wir eine Zeile Code, mit der der ESP8266 nach eingehenden Anfragen “horcht”:

WiFiClient client = server.available();

Ob eine Anfrage eintrifft, fragst du mit einem If-Statement ab:

if (client) {

Nur dann – also wenn du die IP-Adresse in deinem Browser aufrufst – wird der weitere Code in void loop() ausgeführt. Zunächst gibst du eine entsprechende Meldung im Seriellen Monitor aus und erstellst einen String, in dem du die ankommenden Daten der Anfrage zeilenweise speicherst und prüfen wirst, ob sie zu Ende ist.

Serial.println("Anfrage von Client erhalten.");
String currentLine = ""; 

Solange der Client mit dem Server verbunden ist und Daten von ihm “reinkommen”, speicherst du diese Byte für Byte in der Variablen c und gibst sie im Seriellen Monitor aus.

while (client.connected()) {

  if (client.available()) {
    char c = client.read();
    Serial.write(c);

Dort kannst du die Anfrage Zeile für Zeile nachverfolgen. Apropos Zeilen: Interessant sind hier die Zeilenumbrüche und Leerzeilen. Wenn dein Server das Zeichen für eine New Line \n erhält, prüfst du, ob die Anfrage zu Ende ist.

Das ist etwas kompliziert, denn eine Anfrage endet immer mit einer Leerzeile, was nicht nur einem \n, sondern der Zeichenkombination \n\n entspricht. Aber eins nach dem anderen. Zunächst prüfst du ob ein \n hereinkommt:

if (c == '\n') {

oder etwas anderes außer einem Carriage Return \r. All diese “anderen” Bytes (also alles außer \n und \r) speicherst du in deiner Variablen für die aktuelle Zeile currentLine.

else if (c != '\r') {
  currentLine += c;
  }

Wenn das aktuelle Byte c der Anfrage jedoch \n lautet, greift das oben erwähnte If-Statement. Gleich danach folgt eine weitere Prüfung, ob die Variable currentLine einen Inhalt hat:

if (currentLine.length() == 0) {

Ist das nicht der Fall, kam offensichtlich noch kein \n\n – also noch keine Leerzeile. Deshalb wird die Variable currentLine wieder gelöscht und der Sketch springt zurück zur nächsten Zeile der Anfrage des Clients:

else {
  currentLine = "";
  }

Wenn jetzt jedoch wieder ein \n kommt, haben wir unsere Leerzeile – oder anders gesagt: Die Anfrage des Clients ist zu Ende! Dieses Prozedere mit den verschiedenen Schleifen ist auf den ersten Blick recht kompliziert – nimm dir deshalb ruhig Zeit und verfolge die Durchgänge im gesamten Sketch.

DER SERVER ANTWORTET

Nun ist also der Server mit seiner Antwort an den Client dran. Da mit deinem ESP8266 Webserver alles in Ordnung ist, lässt du ihn mit einem entsprechenden Status-Code antworten – nämlich 200:

client.println("HTTP/1.1 200 OK");

Es folgen Informationen zur Art des Contents, der gleich geliefert wird und darüber, dass der Server die Verbindung zum Client kappen wird, sobald er mit seiner Antwort fertig ist. Gefolgt von einer Leerzeile:

client.println("Content-type:text/html");
client.println("Connection: close");
client.println();

Nun kommt endlich unser “Hello world!”. Und zwar als HTML:

client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head>");
client.println("<body><h1 align=\"center\">Hello world!</h1></body></html>");

Sehr reduziertes HTML – abgesehen vom <head> befindet sich im <body> nur eine in deinem Browser zentrierte Überschrift <h1> mit unserer Nachricht.

Später erfährst du mehr über HTML ein und baust dir damit ein ansprechendes Interface, über das du mit deinem ESP8266 interagieren kannst.

An dieser Stelle war es das jedoch. Fast. Fehlt nur noch das Ende der Verbindung und eine Info hierüber in deinem Seriellen Monitor:

client.stop();
Serial.println("Verbindung beendet.");
Serial.println("");

Hier noch einmal der gesamte Sketch:

//Bibliothek für die WLAN-Verbindung
#include <ESP8266WiFi.h>

//Daten deines WLAN-Netzwerks
const char* ssid     = "Name deines Netzwerks";
const char* password = "Dein WLAN-Passwort";

//Port des Webservers auf 80 setzen
WiFiServer server(80);

void setup() {
  Serial.begin(115200); //Seriellen Monitor starten

  // Mit dem WLAN-Netzwerk verbinden
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Ich verbinde mich mit dem Internet...");
  }
  Serial.println("Ich bin mit dem Internet verbunden!");

  //Lokale IP-Adresse im Seriellen Monitor ausgeben und Server starten
  Serial.println("");
  Serial.println("IP-Adresse: ");
  Serial.println(WiFi.localIP());

  server.begin();
}

void loop() {
  WiFiClient client = server.available();   //Auf Clients (Server-Aufrufe) warten

  if (client) {                             //Bei einem Aufruf des Servers...
    Serial.println("Anfrage von Client erhalten.");
    String currentLine = "";                //...String definieren für die Anfrage des Clients

    while (client.connected()) { //Loop, solange Client verbunden ist

      if (client.available()) {
        char c = client.read();             // Ein (1) Zeichen der Anfrage des Clients lesen
        Serial.write(c);                    // und es im Seriellen Monitor ausgeben
        if (c == '\n') {                    // bis eine Neue Zeile ausgegeben wird

          //Wenn der Client eine Leerzeile sendet, ist das Ende des HTTP Request erreicht
          if (currentLine.length() == 0) {

            //Der Server sendet nun eine Antwort an den Client
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            //Die Webseite anzeigen
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head>");
            client.println("<body><h1 align=\"center\">Hello world!</h1></body></html>");

            //Die Antwort beenden
            client.println();
            //Den Loop beenden
            break;
          } else { //Bei einer neuen Zeile (keine Leerzeile) die Variable leeren
            currentLine = "";
          }
        } else if (c != '\r') {  //alles andere als eine Leerzeile wird
          currentLine += c;      //der Variablen hinzugefügt
        }
      }
    }
    //Die Verbindung beenden
    client.stop();
    Serial.println("Verbindung beendet.");
    Serial.println("");
  }
}

Wie warm ist es gerade?

Im letzten Abschnitt hast du einen Webserver in seiner einfachsten Form erstellt und ein einfaches Hello world! auf einer ebenso einfachen Webseite ausgegeben.

Lass uns nun einen Schritt weiter gehen. In diesem Abschnitt ermittelst du mithilfe deines Sensors die aktuelle Raumtemperatur. Wenn du die die IP-Adresse des Servers aufrufst erscheint diese dann auf der Webseite.

Die aktuelle Temperatur

PASSE DEN SKETCH AN

Die gute Nachricht: Du kannst den Großteil des Sketchs aus dem letzten Abschnitt einfach übernehmen. Hinzufügen musst du lediglich etwas Code für die Messung der Temperatur. Ebenso bedarf es ein paar Anpassungen der Webseite, die dein Server an deinen Client übermittelt.

Zunächst zur Temperatur. In diesem Abschnitt arbeiten wir weiter mit dem Sensor BMP180. Füge zu Beginn des Sketchs folgende Zeilen hinzu:

#include <Adafruit_BMP085.h>
Adafruit_BMP085 bmp;
float temp;

Mit der ersten Zeile integrierst du die Bibliothek für den Sensor. Die zweite erstellt das Objekt bmp. Anschließend benötigen wir noch eine Variable für die gemessene Temperatur.

Im Setup prüfst du, ob der Sensor verfügbar ist. Ist das nicht der Fall, begibt sich dein Sketch in eine Endlosschleife und wird nicht weiter ausgeführt:

if (!bmp.begin()) {
  Serial.println("Sensor nicht gefunden!");
  while (1) {}
}

Wir gehen natürlich davon aus, dass das nicht der Fall ist. Deshalb folgt nun die eigentliche Messung. Diese integrierst du im Loop – mitten in der Antwort des Servers an den Client. Das hat den Vorteil, dass du immer die aktuelle Temperatur erhältst, sobald du eine neue Anfrage stellst, also zum Beispiel einen Refresh im Browser machst.

temp = bmp.readTemperature();
Serial.print("Temperatur = ");
Serial.print(temp);
Serial.println(" *C");

ETWAS MEHR HTML FÜR DEINE WEBSEITE

Jetzt musst du nur noch die Antwort des Servers – also die Webseite etwas anpassen. Zunächst fügst du dem <head> der Webseite die Zeichencodierung UTF-8 hinzu, damit das Grad-Zeichen ° korrekt dargestellt wird:

client.println("<meta charset=\"utf-8\"></head>");

Anschließend ersetzt du Headline Hello world! durch Die aktuelle Temperatur und fügst direkt darunter einen neuen Absatz hinzu, der den Messwert deines Temperatursensors in der Variablen temp enthält:

client.println("<body><h1 align=\"center\">Die aktuelle Temperatur</h1>")
client.println("<p align=\"center\">");
client.println(temp);
client.println("°C</p>");
client.println("</body></html>");

TESTE DEINE NEUE WEBSEITE

Den gesamten Sketch findest du oben im Reiter Downloads. Lade ihn auf deinen ESP8266 und rufe die die IP-Adresse im Browser auf. Siehst du die aktuelle Temperatur?

Teste auch, ob sich die Temperatur verändert, wenn du deinen ESP8266 samt Sensor an einen anderen Ort stellst und eine neue Anfrage schickst.

Im nächsten Abschnitt integrierst du eine Funktion, die dir die “Arbeit” abnimmt – statt manuell die Webseite zu aktualisieren macht sie das von alleine.

Hier der gesamte Sketch:

//Bibliothek für die WLAN-Verbindung
#include <ESP8266WiFi.h>

//Bibliothek, Objekt und Variable für den Sensor BMP180
#include <Adafruit_BMP085.h>
Adafruit_BMP085 bmp;
float temp;

//Daten des WLAN-Netzwerks
const char* ssid     = "Name deines Netzwerks";
const char* password = "Passwort deines Netzwerks";

// Port des Webservers auf 80 setzen
WiFiServer server(80);

void setup() {
  Serial.begin(115200); //Seriellen Monitor starten

  if (!bmp.begin()) {
    Serial.println("Sensor nicht gefunden!");
    while (1) {}
  }

  //Mit dem WLAN-Netzwerk verbinden
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Ich verbinde mich mit dem Internet...");
  }
  Serial.println("Ich bin mit dem Internet verbunden!");

  //Lokale IP-Adresse im Seriellen Monitor ausgeben und Server starten
  Serial.println("");
  Serial.println("IP-Adresse: ");
  Serial.println(WiFi.localIP());

  server.begin();
}

void loop() {
  WiFiClient client = server.available();   //Auf Clients (Server-Aufrufe) warten

  if (client) {                             //Bei einem Aufruf des Servers...
    Serial.println("Anfrage von Client erhalten.");
    String currentLine = "";                //...String definieren für die Anfrage des Clients

    while (client.connected()) { //Loop, solange Client verbunden ist

      if (client.available()) {
        char c = client.read();             //Ein (1) Zeichen der Anfrage des Clients lesen
        Serial.write(c);                    //und es im Seriellen Monitor ausgeben
        if (c == '\n') {                    //bis eine Neue Zeile ausgegeben wird

          //Wenn der Client eine Leerzeile sendet, ist das Ende des HTTP Request erreicht
          if (currentLine.length() == 0) {

            //Der Server sendet nun eine Antwort an den Client
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            //Die Temperatur ermitteln
            temp = bmp.readTemperature();
            Serial.print("Temperatur = ");
            Serial.print(temp);
            Serial.println(" *C");

            // Die Webseite anzeigen
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<meta charset=\"utf-8\"></head>");
            client.println("<body><h1 align=\"center\">Die aktuelle Temperatur</h1>");
            client.println("<p align=\"center\">");
            client.println(temp);
            client.println("°C</p>");
            client.println("</body></html>");

            //Die Antwort beenden
            client.println();
            // Den Loop beenden
            break;
          } else { //Bei einer neuen Zeile (keine Leerzeile), die Variable leeren
            currentLine = "";
          }
        } else if (c != '\r') {  //alles andere als eine Leerzeile wird
          currentLine += c;      //der Variablen hinzugefüht
        }
      }
    }
    // Die Verbindung beenden
    client.stop();
    Serial.println("Verbindung beendet.");
    Serial.println("");
  }
}

Autoreload der Webseite

Wie wäre es, wenn du die Webseite mit der Antwort des Servers nicht selbst neu laden müsstest, um die aktuelle Temperatur zu erfahren? Kein Problem!

In diesem Abschnitt lernst du zwei Methoden kennen, die genau das für dich übernehmen.

AUTOREFRESH MIT EINEM META-TAG

Die erste Methode erfordert nur eine kleine Anpassung im HTML der Antwort deines Servers. Erweitere einfach den Head des HTML um folgende Information:

<meta http-equiv=\"refresh\" content=\"5\">

Der gesamte Head sollte dann wie folgt aussehen:

client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<meta charset=\"utf-8\"><meta http-equiv=\"refresh\" content=\"5\"></head>");

Jetzt lädt deine Webseite alle 5 Sekunden neu – und stellt somit eine neue Anfrage an deinen ESP8266, der daraufhin die Temperatur ermittelt und zurückgibt.

Das funktioniert im Prinzip ganz gut – allerdings kannst du damit einen Refresh höchstens einmal pro Sekunde ausführen. Wenn du häufigere Anfragen möchtest, um deine Daten quasi in Echtzeit zu erhalten, eignet sich ein kleines Script besser.

AUTOREFRESH MIT JAVASCRIPT

Mit dem folgenden Script kannst du deine Webseite häufiger als einmal pro Sekunde neu laden – theoretisch sogar jede tausendstel Sekunde. Das wäre jedoch sicherlich etwas zu viel des Guten.

Füge also statt des Meta-Tags von oben folgendes Script deinem Head hinzu:

<script>
  function refresh(refreshPeriod)
  {
      setTimeout('location.reload(true)', refreshPeriod);
  }
  window.onload = refresh(5000);
</script>

Der Head sollte dann in deinem Sketch so aussehen:

client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<meta charset=\"utf-8\">");
client.println("<script>function refresh(refreshPeriod){setTimeout('location.reload(true)', refreshPeriod);}");
client.println("window.onload = refresh(500);</script></head>");

Jetzt aktualisiert sich deine Webseite alle 500 Millisekunden von alleine. Diese Information findest du in refresh(500) – probiere es gleich einmal aus und ersetze diesen Wert durch andere. Siehst du, wie schnell sich die Temperatur im Browser verändert (vorausgesetzt sie verändert sich wirklich um deinen Sensor herum)?

Die LED steuern

Du kannst nun also die aktuelle Raumtemperatur auf der Webseite sehen, die dein Server dir unter seiner IP-Adresse zur Verfügung stellt. Wie wäre es, wenn du von dort aus auch das Licht – also deine LED – ein- und ausschalten könntest? Genau das setzen wir jetzt um.

Zunächst benötigen wir etwas Code für die LED. Zu Beginn des Sketchs legst du den Pin fest, an dem sie angeschlossen ist. Wir bleiben hier bei Pin D7 – den wir im Sketch mit der Zahl 13 ansteuern. Ebenso benötigen wir eine Variable für den Status der LED, also ob sie an oder aus ist:

const int led = 13;
String ledState = "aus";

Falls du noch nicht mit den verschiedenen Pins des ESP8266 und der Unterschiede in ihrer Bezeichnung vertraut bist, wirf einen kurzen Blick auf folgende Skizze. Hier findest du die wichtigsten Pins und ihre Nummer, mit der du sie in deinem Sketch ansteuerst.

ESP8266 Pinout

Im Setup des Sketchs legst du nun noch schnell den pinMode fest und schaltest die LED zu Beginn aus, so wie du es oben in der Variablen ledState auch festgehalten hast.

pinMode(led, OUTPUT);
digitalWrite(led, LOW);

Wie kannst du nun die LED von der Webseite aus an- und ausschalten? Hierfür bringst du dort zunächst einen Link unter, der deinen Befehl weiterleitet. Wenn die LED aus ist (also ledState auf “aus” steht), lautet der Ankertext des Links ANSCHALTEN. Wenn sie an ist entsprechend AUSSCHALTEN.

if (ledState == "aus") {
  client.println("<p align=\"center\"><a href=\"/led/on\">ANSCHALTEN</a></p>");
} else {
  client.println("<p align=\"center\"><a href=\"/led/off\">AUSSCHALTEN</a></p>");
  }

Ein kurzer Exkurs zu HTML: Ein Link wird hier mit dem Tag <a> begonnen und mit </a> wieder geschlossen. Zwischen diesen beiden Tags befindet sich der Ankertext, also das Wort, das du anklicken kannst.

Das Ziel des Links befindet sich im öffnenden Tag <a> hinter href= und wird mit Anführungsstrichen markiert. Im Code oben heißt das Linkziel also entweder “/led/on” oder “/led/off”.

Übrigens, sind dir die umgedrehten Schrägstriche (Backslashes) aufgefallen? Diese benötigst du in deinem Sketch, um die Anführungszeichen zu maskieren. Ansonsten würde z.B. im Befehl client.println() oben zu viele Anführungszeichen stehen, was unweigerlich zu einem Fehler führen würde.

Wenn du die IP-Adresse deines Servers nun aufrufst, sieht du folgende Webseite:

Aber noch einmal zurück zum Linkziel: Wenn du also den Link ANSCHALTEN klickst, wird “/led/on” hinter die IP-Adresse des Servers geschrieben, sodass sie z.B. so lautet:

http://192.168.0.242/led/on

Das können wir uns zunutze machen, wenn dein Server die Anfrage des Clients liest.

DEINEN BEFEHL IM HEADER AUSLESEN

Wie du ja bereits weißt, sendet dein Client eine ganze Reihe Informationen an deinen Server, wenn er eine Anfrage an ihn stellt. Nach deinem Klick auf den Link auch den Befehl /led/on bzw. /led/off.

Um diese Befehle zu empfangen, benötigst du zunächst zu Beginn des Sketchs eine gleichnamige Variable für den Header:

String header;

Wenn eine Anfrage reinkommt, verwendest du ja bereits die Variable c, um zu ermitteln, wann die Anfrage zu Ende ist. Hier integrierst du nun auch deinen String header, den du mit den übertragenen Daten füllst:

if (client.available()) {
  char c = client.read();
  Serial.write(c);
  header += c;
  if (c == '\n') {

Nun befindet sich im String header (nach deinem Klick auf den Link) entweder der Befehl /led/on oder /led/off.

Um herauszufinden welcher, machst du eine kleine Abfrage:

if (header.indexOf("GET /led/on") >= 0) {
  Serial.println("Die LED ist an");
  ledState = "an";
  digitalWrite(led, HIGH);
} else if (header.indexOf("GET /led/off") >= 0) {
  Serial.println("Die LED ist aus");
  ledState = "aus";
  digitalWrite(led, LOW);
}

Hier benutzt du die Funktion indexOf() – diese prüft, ob sich ein bestimmter String (hier z.B. “GET /led/on”) in einem anderen String befindet. Ist das nicht der Fall, ist ihr Ergebnis -1. Wenn sie ihn jedoch findet, gibt sie seine Position zurück. Diese ist uns eigentlich egal, Hauptsache das Ergebnis ist nicht -1, sondern >= 0. 🙂

Wenn du also die LED mit einem Klick angeschaltet hast, steht im header der String “GET /led/on”. In diesem Fall schaltest du die LED mit digitalWrite() an und setzt die Variable ledState auf “an”.

Das wiederum verändert den Ankertext des Links: Dieser wechselt von ANSCHALTEN auf AUSSCHALTEN. Und damit wirklich klar ist, was Sache ist, schreibt dein Server noch den Status der LED über den Link:

client.println("<p align=\"center\">Die LED ist " + ledState + ".</p>");

Und das war es auch schon. Probiere es gleich mal aus. Kannst du die LED über die Webseite an- und ausschalten?

Im nächsten Abschnitt hübschst du die Webseite etwas auf.

Hier der gesamte Sketch:

//Bibliothek für die WLAN-Verbindung
#include <ESP8266WiFi.h>

//Bibliothek, Objekt und Variable für den Sensor BMP180
#include <Adafruit_BMP085.h>
Adafruit_BMP085 bmp;
float temp;

//Daten des WLAN-Netzwerks
const char* ssid     = "Name deines Netzwerks";
const char* password = "Passwort deines Netzwerks";

//Port des Webservers auf 80 setzen
WiFiServer server(80);

//String für den Header
String header;

//Pin und Status der LED
const int led = 13; //Pin D7 am ESP8266
String ledState = "aus";


void setup() {
  Serial.begin(115200); //Seriellen Monitor starten

  pinMode(led, OUTPUT);
  digitalWrite(led, LOW);

  if (!bmp.begin()) {
    Serial.println("Sensor nicht gefunden!");
    while (1) {}
  }

  //Mit dem WLAN-Netzwerk verbinden
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Ich verbinde mich mit dem Internet...");
  }
  Serial.println("Ich bin mit dem Internet verbunden!");

  // Lokale IP-Adresse im Seriellen Monitor ausgeben und Server starten
  Serial.println("");
  Serial.println("IP-Adresse: ");
  Serial.println(WiFi.localIP());

  server.begin();
}

void loop() {
  WiFiClient client = server.available();   //Auf Clients (Server-Aufrufe) warten

  if (client) {                             //Bei einem Aufruf des Servers...
    Serial.println("Anfrage von Client erhalten.");
    String currentLine = "";                //...String definieren für die Anfrage des Clients

    while (client.connected()) { //Loop, solange Client verbunden ist

      if (client.available()) {
        char c = client.read();             //Ein (1) Zeichen der Anfrage des Clients lesen
        Serial.write(c);
        header += c;
        if (c == '\n') {


          //Wenn der Client eine Leerzeile sendet, ist das Ende des HTTP Request erreicht
          if (currentLine.length() == 0) {

            //Der Server sendet nun eine Antwort an den Client
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            //die Led an- und ausschalten
            if (header.indexOf("GET /led/on") >= 0) {
              Serial.println("Die LED ist an");
              ledState = "an";
              digitalWrite(led, HIGH);
            } else if (header.indexOf("GET /led/off") >= 0) {
              Serial.println("Die LED ist aus");
              ledState = "aus";
              digitalWrite(led, LOW);
            }

            //Die Temperatur ermitteln
            temp = bmp.readTemperature();
            Serial.print("Temperatur = ");
            Serial.print(temp);
            Serial.println(" *C");

            //Die Webseite anzeigen
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<meta charset=\"utf-8\"></head>");
            client.println("<body><h1 align=\"center\">Die aktuelle Temperatur</h1>");
            client.println("<p align=\"center\">");
            client.println(temp);
            client.println("°C</p>");

            client.println("<p align=\"center\">Die LED ist " + ledState + ".</p>");

            if (ledState == "aus") {
              client.println("<p align=\"center\"><a href=\"/led/on\">ANSCHALTEN</a></p>");
            } else {
              client.println("<p align=\"center\"><a href=\"/led/off\">AUSSCHALTEN</a></p>");
            }

            client.println("</body></html>");

            //Die Antwort beenden
            client.println();
            //Den Loop beenden
            break;
          } else { // Bei einer neuen Zeile (keine Leerzeile), die Variable leeren
            currentLine = "";
          }
        } else if (c != '\r') {  //alles andere als eine Leerzeile wird
          currentLine += c;      //der Variablen hinzugefüht
        }
      }
    }
    //Variable header leeren
    header = "";
    // Die Verbindung beenden
    client.stop();
    Serial.println("Verbindung beendet.");
    Serial.println("");
  }
}

CSS und HTML für eine schönere Webseite

Du hast nun eine einfache Webseite, auf der du die aktuelle Temperatur siehst und die LED steuern kannst. Allerdings sieht sie sehr nach den Anfängen des World Wide Webs aus. Lass uns also ein paar Minuten Zeit investieren und sie etwas aufmöbeln.

Am Ende dieses Abschnitts sieht deine Webseite folgendermaßen aus:

Webseite mit neuem Layout

Du siehst zwei Karten – eine für die Temperatur und eine für die Steuerung der LED. Statt eines einfachen Links befindet sich auf letzterer ein Button. Beachte bitte, dass sich das Aussehen des Buttons je nach Browser verändern kann.

DAS CSS

Bisher haben wir kaum CSS (Cascading Style Sheets) verwendet. Das ändert sich jetzt, aber keine Angst – es hält sich trotzdem im Rahmen. 🙂 Folgende Informationen benötigen wir für die Webseite:

<style>
    html {
      font-family: Helvetica;
    }

    h1,
    p {
      text-align: center;
    }

    a {
      color: black;
      text-decoration: none;
    }

    div {
      margin: 10px auto 10px auto;
      padding: 10px;
      height: 80px;
      width: 200px;
      background-color: aliceblue;
      border: 1px solid lightgray;
    }
  </style>

Allerdings ahnst du es vielleicht bereits, diese Informationen zum Styling der Webseite musst du im Sketch etwas anders unterbringen – nämlich so wie du es mit den anderen HTML-Tags auch gemacht hast: Innerhalb der verschiedenen client.println() Funktionen. Achte bitte darauf, folgende Zeilen noch vor dem schließenden </head> Tag unterzubringen.

client.println("<style>");
client.println("html { font-family: Helvetica;} h1, p {text-align: center;}");
client.println("a { color: black; text-decoration: none;}");
client.println("div { margin: 10px auto 10px auto; padding: 10px; height: 80px; width: 200px; background-color: aliceblue; border: 1px solid lightgray;}");
client.println("</style>");

DAS HTML

Den Head der Webseite hast du nun um das neue Styling erweitert. Nun kommt der Body dran. Folgendes HTML musst du hier integrieren:

<div>
  <p>Raumtemperatur</p>
  <p> (temp) </p>
</div>
<div>
  <p>LED</p>
  <button style="margin-left:50px;"><a href="/led/on">ANSCHALTEN</a>
  </button>
  <button style="margin-left:45px;"><a href="/led/off">AUSSCHALTEN</a>
  </button>
</div>

Die Variable temp siehst du im obigen Code fett gedruckt – dort dient sie nur als Erinnerung, dass sie dort hinein muss. In deinem Sketch sieht dieses HTML dann so aus:

client.println("<body><div><p>Raumtemperatur</p>");
client.println("<p>");
client.println(temp);
client.println("°C</p></div>");

client.println("<div><p>LED</p>");

if (ledState == "aus") {
  client.println("<button style=\"margin-left:50px;\"><a href=\"/led/on\">ANSCHALTEN</a></button>");
} else {
  client.println("<button style=\"margin-left:45px;\"><a href=\"/led/off\">AUSSCHALTEN</a></button>");
}

client.println("</div></body></html>");

Wie du siehst, befindet sich hier wieder die If-Abfrage, die je nachdem, ob die LED an oder aus ist, einen anderen Button ausspielt. Das Styling für die Buttons – genauer gesagt ihre Abstände nach links – befinden sich direkt im <button> Tag. Achte in diesem Fall bitte auf die korrekte Maskierung der Anführungsstriche mit dem Backslash \.

Und das war es schon. Lade den Sketch mit dem aktualisierten CSS und HTML auf deinen ESP8266 und schau dir deine neue Webseite gleich einmal an.

Hier der gesamte Sketch:

//Bibliothek für die WLAN-Verbindung
#include <ESP8266WiFi.h>

//Bibliothek, Objekt und Variable für den Sensor BMP180
#include <Adafruit_BMP085.h>
Adafruit_BMP085 bmp;
float temp;

//Daten des WLAN-Netzwerks
const char* ssid     = "Name deines Netzwerks";
const char* password = "Passwort deines Netzwerks";

//Port des Webservers auf 80 setzen
WiFiServer server(80);

//String für den Header
String header;

//Pin und Status der LED
const int led = 13; //Pin D7 am ESP8266
String ledState = "aus";


void setup() {
  Serial.begin(115200); //Seriellen Monitor starten

  pinMode(led, OUTPUT);
  digitalWrite(led, LOW);

  if (!bmp.begin()) {
    Serial.println("Sensor nicht gefunden!");
    while (1) {}
  }

  //Mit dem WLAN-Netzwerk verbinden
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Ich verbinde mich mit dem Internet...");
  }
  Serial.println("Ich bin mit dem Internet verbunden!");

  //Lokale IP-Adresse im Seriellen Monitor ausgeben und Server starten
  Serial.println("");
  Serial.println("IP-Adresse: ");
  Serial.println(WiFi.localIP());

  server.begin();
}

void loop() {
  WiFiClient client = server.available();   // uf Clients (Server-Aufrufe) warten

  if (client) {                             //Bei einem Aufruf des Servers...
    Serial.println("Anfrage von Client erhalten.");
    String currentLine = "";                //...String definieren für die Anfrage des Clients

    while (client.connected()) { //Loop, solange Client verbunden ist

      if (client.available()) {
        char c = client.read();             //Ein (1) Zeichen der Anfrage des Clients lesen
        Serial.write(c);
        header += c;
        if (c == '\n') {


          //Wenn der Client eine Leerzeile sendet, ist das Ende des HTTP Request erreicht
          if (currentLine.length() == 0) {

            //Der Server sendet nun eine Antwort an den Client
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            //die Led an- und ausschalten
            if (header.indexOf("GET /led/on") >= 0) {
              Serial.println("Die LED ist an");
              ledState = "an";
              digitalWrite(led, HIGH);
            } else if (header.indexOf("GET /led/off") >= 0) {
              Serial.println("Die LED ist aus");
              ledState = "aus";
              digitalWrite(led, LOW);
            }

            //Die Temperatur ermitteln
            temp = bmp.readTemperature();
            Serial.print("Temperatur = ");
            Serial.print(temp);
            Serial.println(" *C");

            // Die Webseite anzeigen
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<meta charset=\"utf-8\">");
            client.println("<style>");
            client.println("html { font-family: Helvetica;} h1, p {text-align: center;}");
            client.println("a { color: black; text-decoration: none;}");
            client.println("div { margin: 10px auto 10px auto; padding: 10px; height: 80px; width: 200px; background-color: aliceblue; border: 1px solid lightgray;}");
            client.println("</style>");
            client.println("</head>");
           
            client.println("<body><div><p>Raumtemperatur</p>");
            client.println("<p>");
            client.println(temp);
            client.println("°C</p></div>");

            client.println("<div><p>LED</p>");
            if (ledState == "aus") {
              client.println("<button style=\"margin-left:50px;\"><a href=\"/led/on\">ANSCHALTEN</a></button>");
            } else {
              client.println("<button style=\"margin-left:45px;\"><a href=\"/led/off\">AUSSCHALTEN</a></button>");
            }

            client.println("</div></body></html>");

            //Die Antwort beenden
            client.println();
            // Den Loop beenden
            break;
          } else { //Bei einer neuen Zeile (keine Leerzeile) die Variable leeren
            currentLine = "";
          }
        } else if (c != '\r') {  //alles andere als eine Leerzeile wird
          currentLine += c;      //der Variablen hinzugefüht
        }
      }
    }
    //Variable header leeren
    header = "";
    //Die Verbindung beenden
    client.stop();
    Serial.println("Verbindung beendet.");
    Serial.println("");
  }
}

Eine feste IP-Adresse vergeben

Wechselt die IP-Adresse deines ESP8266 nach jedem Neustart? Das kannst du leicht beheben, indem du ihm in deinem eine feste IP zuweist. Hierfür benötigst du nur ein paar Zeilen Code.

Hinweis: Die IP-Adresse, die du verwenden möchtest, muss in deinem Netzwerk natürlich noch verfügbar sein und sich im entsprechenden Gateway befinden.

Nehmen wir an, dein ESP8266 hat bisher die Adresse 192.168.0.242 zugewiesen bekommen und ist darunter erreichbar. Du möchtest diese nun jedoch manuell auf 192.168.0.171 festlegen.

Feste IP-Adresse im Seriellen Monitor

Um diese IP-Adresse festzulegen, füge deinem Sketch noch vor der Setup-Funktion folgende Zeilen hinzu. Hier legst du die IP-Adresse 192.168.0.171 im Gateway 192.168.0.1 fest:

IPAddress local_IP(192, 168, 0, 171);
IPAddress gateway(192, 168, 0, 1);

IPAddress subnet(255, 255, 0, 0);

Innerhalb der Setup-Funktion verwendest du diese Daten nun für die Konfiguration. Achte hierbei darauf, folgende Zeile noch vor der Funktion WiFi.begin() unterzubringen:

WiFi.config(local_IP, gateway, subnet);

Nach dem Upload besitzt dein ESP8266 nun die oben festgelegte IP-Adresse in deinem Netzwerk. Möchtest du mehr über dieses Thema wissen? In diesem Wiki-Beitrag erfährst du mehr.

Hinweise zur IT-Sicherheit

Zum Ende möchten wir noch auf ein wichtiges Thema hinweisen: IT-Sicherheit.

Den Webserver, den du gebaut hast, kannst du zunächst nur aus deinem eigenen WLAN-Netzwerk ansteuern. Und das ist auch erstmal ganz gut so. Denn so können nur Menschen mit dem passenden Schlüssel auf die Daten des Servers zugreifen – vorausgesetzt dein WLAN-Netzwerk ist sicher.

Zunächst möchten wir dich darauf hinweisen, dass die gängigen ESP8266-Module nur für Hobbyprojekte ausgelegt sind. Das heißt im Umkehrschluss, dass du niemals sicherheitsrelevante Informationen damit verarbeiten solltest.

Das gilt insbesondere, wenn du auf deinen Webserver auch von außerhalb deines eigenen WLAN-Netzes zugreifen möchtest. Dann könnte jeder auf ihn zugreifen – nicht nur du. Natürlich gibt es auch hierfür diverse Sicherheitsmaßnahmen, mit denen du das zumindest erschweren kannst – aber dennoch, diese solltest du nur umsetzen, wenn du genau weißt, was du tust.

An dieser Stelle können wir dir leider keine weiteren Hinweise und Sicherheitslösungen an die Hand geben, da dieses Thema den Rahmen dieses Artikels sprengen würde und sich auch rasant weiterentwickelt.

Für den Einstieg in dieses Thema können jedoch diese zwei Artikel dienen:

Sicherheit? Sicherheit!

Sicherheit in der IoT

]]>
Die aktuelle Uhrzeit mit einem ESP8266 abfragen https://polluxlabs.net/esp8266-projekte/die-aktuelle-uhrzeit-mit-einem-esp8266-abfragen/ Mon, 10 Feb 2020 22:28:30 +0000 https://polluxlabs.net/?p=1001 Wenn du mit einem ESP8266* arbeitest und ohnehin damit im Internet bist, gibt es eine einfach Möglichkeit, die aktuelle Uhrzeit herauszufinden: Mit der Bibliothek NTPClient.h

Hinweis: Das funktioniert natürlich auch mit einem ESP32 oder einem Arduino mit WiFi Shield – hier konzentrieren wir uns allerdings auf den ESP8266 und den passenden Sketch.

Zunächst brauchst du eine Verbindung ins Internet. Lerne hier, wie du deinen ESP8266 mit dem Internet verbindest.

Wenn du im Internet bist, kann es losgehen. Du benötigst die folgenden drei Bibliotheken. Die erste benötigst du, um deinen ESP8266 mit dem Internet zu verbinden. Die Bibliothek <NTPClient.h> verbindet dich mit dem Network Time Protocol und mit <WiFiUdp.h> sorgst du für die richtige Datenübertragung mit dem User Datagram Protocol.

#include <ESP8266WiFi.h> 
#include <NTPClient.h>
#include <WiFiUdp.h>

Wenn du mehr über die Technik hinter dieser Methode erfahren möchtest, erfährst du alles Wichtige über das Network Time Protocol bei Wikipedia.

Übrigens: Wenn du eine Real Time Clock verwenden möchtest, erfährst du in diesem Tutorial, wie du eine RTC anschließt.

Abfrage von Wochentag und Uhrzeit

Die Bibliothek <NTPClient.h> bietet dir die Möglichkeit, ganz einfach Daten wie den Wochentag oder auch die Stunde, Minute und Sekunden abzufragen. Die Zeitzone für die das geschieht, ist UTC. Diese liegt – in der Winterzeit – eine Stunde hinter der Mitteleuropäischen Zeit (MEZ), weshalb du diese Zeitverschiebung in deinem Sketch (in Sekunden) definieren musst. Vorsicht: Wenn wir Winterzeit haben, sind das 3600 Sekunden – in der Sommerzeit 7200, da die UTC dann zwei Stunden hinter der MEZ liegt.

const long utcOffsetInSeconds = 3600;

Für den Fall, dass du auch den aktuellen Wochentag abrufen möchtest, erstellst du dir vorsorglichen ein entsprechendes Array:

char daysOfTheWeek[7][12] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};

Nun erstellst du zwei Instanzen der UDP- und NTP-Bibliothek inklusive der notwendigen Parameter wie z.B. der oben definierten Zeitverschiebung:

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);

Nachdem sich dein ESP8266 in der Setup-Funktion mit dem Internet verbunden hast, kannst du deinen NTP Client mit timeClient.begin() initialisieren und im Loop deines Sketches mit timeClient.update() eine Abfrage durchführen lassen. Diese Funktion besorgt sich die aktuelle Uhrzeit und verarbeitet sie, sodass sie in einem lesbaren Format ausgegeben werden kann.

Die Daten kannst du anschließend mit ein paar weiteren Funktionen in deinem Seriellen Monitor ausgeben. Die aktuelle Uhrzeit z.B. so:

Serial.print(timeClient.getFormattedTime());

Den aktuellen Wochentag kannst du mit Hilfe dieser Funktion und deinem oben erstellen Array der Wochentage abrufen:

Serial.print(daysOfTheWeek[timeClient.getDay()]);

Hier nun der vollständige Sketch zum Rauskopieren und Ausprobieren:

#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

const char *ssid     = "Name deines WiFi-Netzwerks";
const char *password = "Dein WiFi-Passwort";

//Zeitverschiebung UTC <-> MEZ (Winterzeit) = 3600 Sekunden (1 Stunde)
//Zeitverschiebung UTC <-> MEZ (Sommerzeit) = 7200 Sekunden (2 Stunden)
const long utcOffsetInSeconds = 3600;


char daysOfTheWeek[7][12] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);

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

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Ich verbinde mich mit dem Internet...");
  }
  
  Serial.println("Ich bin mit dem Internet verbunden!");

  timeClient.begin();
}

void loop() {
  timeClient.update();

  Serial.print(daysOfTheWeek[timeClient.getDay()]);
  Serial.print(", ");
  Serial.println(timeClient.getFormattedTime());

  delay(1000);
}

Die Unix Time abfragen

Die Abfrage der Uhrzeit in obigem Format ist schön und gut, wenn du sie z.B. auf einem Display verständlich anzeigen möchtest. Wenn du jedoch mit der Zeit Berechnungen durchführen möchtest, z.B. für einen Countdown, eignet sie sich nicht besonders.

Hier kommt die Unix Time (auch Epoch Times, deutsch: Unixzeit) ins Spiel. Das sind ganz einfach die vergangenen Sekunden seit dem 1. Januar 1970, 00:00 Uhr UTC.

Ein Beispiel? Der 24. August 2020, 08:00 UTC entspricht der Zahl 1598256000. Ein weiterer Vorteil der Unix Time ist, dass sie überall auf der Welt identisch ist und du dich nicht mit Zeitzonen herumschlagen musst.

Um die Unixzeit abzufragen, benötigst du die Funktion getEpochTime(). Ergänze den obigen Sketch wie folgt, um sie im Seriellen Monitor auszugeben:

Serial.println(timeClient.getEpochTime());

Ein spannendes Projekt, bei dem du die Uhrzeit abfragst, ist ein Würfel, der leuchtet, wenn die ISS über ihm fliegt. Auch hier verwendest du die Unix Time, um den Countdown bis zum Überflug zu berechnen – allerdings kommt die Zeit in diesem Projekt nicht von einem NTP-Server, sondern von einer anderen API.

Apropos NTP: Hier findest du eine Übersicht weiterer Funktionen der Bibliothek <NTPClient.h>.

]]>
Einen ESP8266 oder ESP32 mit dem Internet verbinden https://polluxlabs.net/esp8266-projekte/einen-esp8266-oder-esp32-mit-dem-internet-verbinden/ Wed, 29 Jan 2020 21:36:11 +0000 https://polluxlabs.net/?p=991 Stoße die Tür zum Internet of Things weit auf! Wenn du für dein Projekt eine Verbindung zum Internet benötigst, leisten dir die beiden Controller ESP8266* und ESP32* gute Dienste. Du benötigst hierfür nur ein WLAN-Netzwerk, die passenden Zugangsdaten und ein paar Zeilen Code.

Bevor du loslegen kannst, musst du deine ESP8266 oder ESP32 in deiner Arduino IDE installieren. Wie das geht, erfährst du in diesem Tutorial auf heise.de.

Die passende Bibliothek

Je nachdem, ob du mit einem ESP8266 oder mit einem ESP32 ins Internet möchtest, brauchst du eine passende Bibliothek. Für ersteren ist das die ESP8266WiFi, für den ESP32 die Bibliothek WiFi.h.

Beide Bibliotheken sollten in deiner Arduino IDE bereits verfügbar sein – sofern du dort dein Board installiert hast. Du kannst sie wie folgt am Anfang deines Sketchs – noch vor der Setup-Funktion – einbinden:

#include <ESP8266WiFi.h>
#include <WiFi.h>

Deine Zugangsdaten

Beide Bibliotheken funktionieren auf ähnliche Art und Weise. Bevor sich dein Controller mit deinem WLAN-Netzwerk verbinden kann, benötigt er die passenden Zugangsdaten. Auch diese legst du am Anfang deines Sketchs zum Beispiel in unveränderlichen Konstanten fest:

const char* ssid = "Name deines WLAN-Netzwerks";
const char* password =  "Dein WLAN-Passwort";

Und ab ins Internet!

Jetzt kann es losgehen. Es gibt mehrere Möglichkeiten, die Verbindung einzurichten und im Seriellen Monitor darzustellen. Zentral ist jedoch immer die Funktion WiFi.begin() und dass diese bestenfalls im Setup deines Sketchs ausgeführt wird, damit für den Loop alles vorbereitet ist.

So könnte der Verbindungsaufbau aussehen:

void setup() {
 
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Ich verbinde mich mit dem Internet...");
  }
  Serial.println("Ich bin mit dem Internet verbunden!");
}

Zunächst die Funktion WiFi.begin(), der du deine Zugangsdaten als Argumente mitgibst. Der anschließende While Loop wird solange ausgeführt, wie die Verbindung zum Internet noch nicht steht (WiFi.status() != WL_CONNECTED) und schreibt jede Sekunde in den Seriellen Monitor, dass die Verbindung aufgebaut wird. Sobald diese steht, erhältst du die Erfolgsmeldung im Seriellen Monitor.

Und das war’s, du bist drin! 🙂

Spannende Projekte

Jetzt, wo deine Verbindung ins Internet steht, probiere sie doch gleich mal mit diesen Projekten aus:

]]>
Erinnerung an deinen Regenschirm mit dem ESP8266 https://polluxlabs.net/esp8266-projekte/erinnerung-an-deinen-regenschirm-mit-dem-esp8266/ Mon, 13 Jan 2020 21:17:44 +0000 https://polluxlabs.net/?p=786 Hast du schon einmal deine Wohnung verlassen und bist dann auf der Straße im Regen gestanden? Dafür, dass das nicht noch einmal passiert, sorgst du mit diesem Projekt.

Mit einem ESP8266 rufst du über eine API die aktuelle Wetterlage ab und zeigst auf einem OLED-Display an, ob es regnet, schneit oder die Sonne scheint. Falls du draußen einen Regenschirm benötigst, erinnert dich das Display und eine LED daran, deinen Regenschirm mitzunehmen.

Ach ja: Damit dein ESP8266 nicht den ganzen Tag im Internet verbringt und ständig die Wetterdaten abruft, integrierst du noch eine Radar-Modul. So kannst du dein Projekt zum Beispiel an der Wohnungstür platzieren und es nur dann anspringen lassen, wenn du dich ihm näherst. So wirst du genau zur richtigen Zeit erinnert. 🙂

Anfänger

1 – 2 Stunden

ca. 20 €

Für dieses Projekt benötigst du (Mengen s. Beschreibung):

Der Aufbau

So ungefähr sollte das fertig aufgebaute Projekt aussehen:

Setze zuerst deinen ESP8266 auf dein Breadboard. Ich empfehle hierfür ein NodeMCU Lua Amica, denn das ist schmal genug, dass du an den Pinouts noch Kabel einstecken kannst. Die neuere Version namens Lolin ist da im Nachteil und deshalb für Projekte auf Breadboards eher ungeeignet. Anschließend verbindest du deinen Microcontroller mit diesem 3 Bauteilen:

OLED-Display

In diesem Projekt verwendest du ein kleines OLED-Display mit I²C-Anschluss. Setze dein Display auf das Breadbaord und verbinde es zunächst mit einem der GND-Pins und einem 3,3V-Ausgang am Microcontroller. Anschließend verbindest du den Display-Pin SCL mit D1 und den Pin SDA mit D2. Mit den beiden Pins D1 und D2 kannst du per I²C mit deinem Display kommunizieren.

Radar-Modul RCWL-0516

Dieser Sensor ist ein einwandfreier Bewegungssensor mit einer Reichweite von 5 bis 7 Metern. Das Tolle an diesem Modul ist, dass es sogar Bewegungen durch ein Hindernis (zum Beispiel eine Box) erkennen kann.

Der Anschluss ist kinderleicht: Neben dem üblichen Anschluss von GND und 3,3V verbindest du den Pin OUT mit dem Pin D7 an deinem ESP8266.

Die LED

Nun zur allerleichtesten Übung, der LED. Verbinde die Anode (langes Bein) mit dem Pin D6 und die Kathode (kurzes Bein) mit Erde. Vergiss nicht, einen Widerstand zwischenzuschalten!

Der Code für dein Projekt

Etwas komplexer wird es jetzt, denn zunächst musst du dich für eine -kostenlose- API registrieren, von der du die aktuelle Wetterlage an deinem Wohnort (oder an jedem anderen Ort der Erde) abrufen kannst.

Registriere dich zunächst auf https://openweathermap.org. Für einen Account benötigst du nur einen Usernamen, eine E-Mail-Adresse und ein Passwort. In deinem persönlichen Bereich hast du unter dem Menüpunkt API keys nun die Möglichkeit einen solchen API key zu erstellen. Diesen benötigst du später in deinem Arduino Sketch für die API-Abfrage der Wetterdaten. Wenn du das gemacht hast, kann es mit dem Code weitergehen.

Die benötigten Bibliotheken

Für dieses Projekt benötigst du 7 Bibliotheken. 3 hiervon musst du evtl. erst noch installieren, um sie nutzen zu können: Adafruit GFX, Adafruit 1306 und ArduinoJSON. Falls du sie bisher in deiner Arduino IDE noch nicht installiert hast, hole das am besten gleich nach. Klicke hierfür auf den Menüpunkt Werkzeuge und anschließend auf Bibliotheken verwalten. Anschließend öffnet sich der sogenannte Bibliotheksverwalter, in dem du nach den jeweiligen Bibliotheken suchen kannst. Installiere jeweils die neueste Version.

Wenn du damit fertig bist, bindest du sie noch vor der Funktion void setup() am Anfang deines Sketchs ein:

#include <Wire.h> //I2C-Verbindung
#include <Adafruit_GFX.h> //OLED-Display
#include <Adafruit_SSD1306.h> //OLED-Display

#include <ESP8266WiFi.h> //WiFI
#include <ArduinoJson.h> //JSON
#include <ESP8266HTTPClient.h> //API-Abfrage
#include <WiFiClient.h> //API-Abfrage

Zugangsdaten zum Internet und OLED-Display

Damit sich dein ESP8266 mit dem Internet verbinden kann, musst du deine Zugangsdaten hinterlegen. Gleich dahinter folgt etwas Code für die Kommunikation mit deinem Display:

// WIFI-Zugangsdaten
const char* ssid = "Dein Netzwerkname";
const char* password =  "Dein Passwort";


//OLED-Display
#define SCREEN_WIDTH 128 // Breite des Displays in Pixeln
#define SCREEN_HEIGHT 64 // Höhe des Displays in Pixeln

//Angaben zum OLED-Display und der Kommunikation per I2C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

Icons für alle (wichtigen) Wetterlagen

Auf deinem Display sollen später Icons erscheinen, die das aktuelle Wetter symbolisieren: Klarer Himmel, Wolken, Schnee, Nebel – und ein Regenschirm für Regen und Gewitter. Die Deklarationen dieser Icons im Code sind sehr lang. Deshalb findest du sie nicht an dieser Stelle, sondern im gesamten Arduino-Sketch, den du unten findest.

Die Setup-Funktion

In der Funktion void setup() definierst du die beiden Pins für die LED und den Radar-Sensor, bereitest du die Verbindung zum Seriellen Monitor vor, gibst die Adresse deines Displays an und legst die Schriftgröße und -farbe fest. 🙂

void setup() {

  pinMode (12, OUTPUT); //LED Pin (am ESP8266 D6)
  pinMode (13, INPUT); //Radar Pin (am ESP8266 D7)

  Serial.begin(115200); //Verbindung zum Seriellen Monitor

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Display-Addresse: 0x3C
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }

  display.setTextSize(1); //Schriftgröße
  display.setTextColor(SSD1306_WHITE); //Farbe
  display.clearDisplay();
}

Der Loop

In der Funktion void loop() arbeitet dein Radar-Modul. Alle 100 Millisekunden prüft es, ob sich etwas in der Nähe bewegt. Ist das der Fall, verbindet sich dein ESP8266 mit dem Internet und startet die Abfrage der Wetterdaten von Openweather. Solange das nicht der Fall ist, läuft der Loop immer weiter und das OLED-Display bleibt dunkel.

void loop() {
  delay(100);
  if (digitalRead(13) == HIGH) { //Bewegung erkannt?
    Serial.println("Movement detected.");
    if (WiFi.status() != WL_CONNECTED) { //Nicht verbunden -> Verbindung herstellen
      WiFi.begin(ssid, password);

      while (WiFi.status() != WL_CONNECTED) { 
        delay(1000);
        display.clearDisplay();
        display.setCursor(0, 10);
        display.println("Connecting to WiFi..."); //Verbindungsstatus anzeigen
        display.display();
      }

      display.clearDisplay();
      display.setCursor(0, 10);
      display.println("Connected to WiFi!"); //Verbindungsstatus anzeigen
      display.display();
      delay(1000);
    }

    apiCall(); //Funktion apiCall() aufrufen
  } else { //Keine Bewegung erkannt? 
    if (WiFi.status() == WL_CONNECTED) { //dann die bestehende Verbindung beenden
      WiFi.disconnect();
      Serial.println("Disconnected from WiFi");
    }
    digitalWrite(12, LOW);
  }
}

Die Funktion apiCall()

Diese Funktion ist das Herzstück deines Codes! Hier startest du die Abfrage bei der API (ein sogenannter API Call), verarbeitest die in deinem ESP8266 ankommenden Daten und zeigst abhängig vom Wetter ein entsprechendes Icon auf deinem Display an. Zusätzlich gibst du noch die aktuelle Temperatur aus und lässt bei Regen die LED leuchten.

Dieser Code ist nicht ganz einfach. Deshalb schauen wir ihn uns Schritt für Schritt an:

Als allererstes definierst du natürlich die Funktion selbst und schreibst eine If-Abfrage, innerhalb der sich der gesamte folgende Code abspielt. Mit dieser Abfrage stellst du sicher, dass dieser nur ausgeführt wird, wenn die Verbindung zum Internet steht. Denn ohne Internet keine Wetterdaten. 🙂

void apiCall() {

  if ((WiFi.status() == WL_CONNECTED)) { //Netzwerkstatus checken

Wetterdaten abrufen und verarbeiten

Nun kommt die Abfrage bei Openweather. Hierfür verwendest du eine URL, in der die Art der Abfrage (aktuelles Wetter) und der gewünschte Ort definiert sind. Am Ende der URL steht dein API key, den du zu Beginn erstellt hast. Nähere Informationen erhältst du in der Dokumentation von Openweather.

Eine mögliche URL für die Abfrage des Berliner Wetters könnte so aussehen:

http://api.openweathermap.org/data/2.5/weather?q=Berlin,de&units=metric&appid=DEIN API KEY"

Trage hinter q= die Stadt ein, deren Wetter du haben möchtest. Alternativ kannst du auch die Koordinaten deines Standorts verwenden. Um diese herauszufinden, eignet sich die Webseite geoplaner.de – dort kannst du einen beliebigen Ort eingeben und dessen Koordinaten herausfinden (im gelben Kasten). Für Berlin würde die URL dann wie folgt lauten:

http://api.openweathermap.org/data/2.5/weather?lat=52.51&lon=13.39&units=metric&appid=DEIN API KEY"

Jetzt folgt ein Check, ob die Abfrage funktioniert hat. In diesem Fall erhältst du vom Server die Antwort 200. Also schreibst du eine If-Abfrage, die allen folgenden Code nur ausführt, wenn die Server-Antwort positiv ausgefallen ist und du die gewünschten Daten erhalten hast.

Danach speicherst du diese Daten in der Variable payload und verarbeitest sie mit Hilfe der Bibliothek ArduinoJson. Die Erklärung, wie das genau funktioniert, würde den Rahmen hier sprengen. Nähere Erläuterungen findest du im Projekt Ein Newsticker per API Call & JSON und auf der Webseite des Entwicklers dieser Bibliothek.

    if (httpCode == HTTP_CODE_OK) { //Ist die Antwort des Servers 200?

      String payload = http.getString(); //Daten in eine Variable speichern
      
      DynamicJsonDocument doc(1024);

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

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

In der Variable payload befinden sich nun die Wetterdaten im JSON-Format. Wie diese aussehen, kannst du sehen, wenn du die URL zur Abfrage aus deinem Sketch in deinem Browser aufrufst. Hier ein Beispiel für Berlin am Abend des 13. Januar 2020:

{"coord":{"lon":13.41,"lat":52.52},"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03n"}],"base":"stations","main":{"temp":3.2,"feels_like":-1.49,"temp_min":1.11,"temp_max":5,"pressure":1017,"humidity":86},"visibility":10000,"wind":{"speed":4.1,"deg":180},"clouds":{"all":40},"dt":1578947701,"sys":{"type":1,"id":1275,"country":"DE","sunrise":1578899517,"sunset":1578928632},"timezone":3600,"id":2950159,"name":"Berlin","cod":200}

Etwas schwer zu lesen, oder? 😉 Für deinen ESP8266 ist das jedoch kein Problem. Die Bibliothek ArduinoJson stellt dir hierfür alles zur Verfügung. Kurz gesagt, kannst du mit einer paar Zeilen Code genau die Daten herausfischen, die du brauchst. Über allem steht ein For-Loop, der dafür sorgt, das die kommenden Anzeigen und Animationen drei Mal angezeigt werden, bis das Display wieder erlischt:

      //Wetterlage und Temperatur ausgeben
      for (int j = 0; j < 3; j++) { // 3x Animation durchlaufen lassen bis zur nächsten Messung
        //Wetterdaten auslesen anhand von ID
        JsonObject weather_0 = doc["weather"][0];
        int weather_0_id = weather_0["id"]; // Wetter-ID
        Serial.println(weather_0_id);

Aus den Daten hast du jetzt die ID des aktuellen Wetters herausgelesen. Openweather vergibt nämlich jeder Wetterlage eine eigene dreistellige ID. So hat leichter Regen zum Beispiel die ID 500. Herabrieselnde Vulkanasche hingegen die ID 762! Alle IDs findest du hier.

Wetterdaten auf dem Display zeigen

Jetzt folgen eine Reihe von If-Abfragen, die das zum Wetter passende Icon auf deinem Display zeigen und animieren. Hier exemplarisch der ID-Bereich „Wolken“ – das sind alle IDs zwischen 801 und 804. Nähere Erläuterungen findest du in den Kommentaren im Code. Interessant ist der For-Loop: Hier verschiebst du das Icon nach links, indem du es 128 Mal (die Breite des Icons) immer einen Pixel weiter links anzeigst. Das erzeugt den Eindruck einer Animation.

        if (weather_0_id > 800 && weather_0_id < 900) {
          //Cloud anzeigen und wegschieben
          display.clearDisplay(); //Display löschen
          display.drawBitmap(0, 0, clouds, 128, 64, WHITE); //Icon zeichnen...
          display.display(); //...und anzeigen
          digitalWrite(12, LOW); //LED ausschalten, da kein Regen
          delay(2000);
          for (int i = 0; i > -128; i--) { //Das Icon aus dem Display "schieben"
            display.clearDisplay();
            display.drawBitmap(i, 0, clouds, 128, 64, WHITE);
            display.display();
            delay(1);
          }

Es folgen weitere Abfragen per else if{} für die anderen Wetterlagen, die du unten im gesamten Sketch findest.

Jetzt fehlt noch die Anzeige der Temperatur. Auch diese liest du aus den JSON-Daten aus und bringst sie animiert auf dein Display:

//Temperatur anzeigen und animieren
        JsonObject main = doc["main"];
        int main_temp = (int)main["temp"]; // Daten in ein INT umwandeln und in Variable speichern
        String temp = String(main_temp) + " C"; //C für Celsius anhängen
        display.setTextSize(3); //Schriftgröße erhöhen
        display.setCursor(25, 20);
        display.println(temp);
        display.display();
        delay(2000);
        for (int i = 25; i > -144; i--) { //Animation
          display.clearDisplay();
          display.setCursor(i, 20);
          display.println(temp);
          display.display();
          delay(1);
        }

Zuletzt setzt du die Schriftgröße wieder auf 1 und schließt alle offenen Klammern. Das allerletzte else bezieht sich auf die Abfrage, ob die Antwort des Servers positiv (also 200) war und gibt eine Fehlermeldung zurück, falls das nicht so war.

Hier nun der vollständige Sketch. Wenn du ihn kopierst und verwendest, achte unbedingt darauf, deine eigenen WLAN-Daten und deinen API key von Openweather in die markierten Stellen einzutragen.

Wie geht es weiter?

Du hast jetzt ein Gerät gebaut, das dich an deinen Regenschirm erinnert. Integriere es in eine Box und versorge den ESP8266 zum Beispiel mit einer Powerbank über USB mit Strom. Diese Box kannst du in der Nähe deiner Wohnungstür platzieren, damit dich dein Projekt genau im richtigen Moment vor dem Regen draußen warnt.

Du denkst größer und an deinen eigenen Wetter-Server? Dann lerne hier, wie du deinen ESP8266 in einen Web Server verwandelst. Oder wie wäre es mit einer ESP8266 Wetterstation, die Daten auf einem Raspberry Pi sammelt und visualisiert?

Beachte jedoch: Zu 100% kannst du dich leider nicht auf die Wetterdaten aus dem Internet verlassen. Manchmal ist vielleicht ein prüfender Blick aus dem Fenster doch sicherer. 😉

]]>
Ein Newsticker per API Call & JSON https://polluxlabs.net/esp8266-projekte/ein-newsticker-per-api-call-json-und-esp32/ Mon, 25 Nov 2019 15:43:52 +0000 https://polluxlabs.net/?p=407

Du möchtest die neuesten Schlagzeilen direkt in deinem Seriellen Monitor lesen? Dann wird es Zeit für deinen eigenen Newsticker!

In diesem Projekt verbindest du deinen ESP32 mit dem Internet, rufst über einen API Call die aktuellen Nachrichten ab, parst JSON-Daten und gibst die Schlagzeilen in deinem Seriellen Monitor aus.

Wir konzentrieren uns in diesem Projekt zunächst auf die Software. Sobald dein Newsticker funktioniert, kannst du ihn um ein Display erweitern, um die Nachrichten dort anzuzeigen.

Hinweis: Für dieses Projekt benötigst du einen ESP32, den du schon für ein paar Euro kaufen kannst. Ein Board aus der Arduino- oder ESP8266-Familie hat für den Newsticker vermutlich zu wenig Arbeitsspeicher. Wenn du diesen Controller bisher noch nicht verwendet hast, wirf zunächst einen Blick in dieses Tutorial.

Der Code für deinen Newsticker

Als allererstes benötigst du drei Bibliotheken, die du wie gewohnt in deinem Sketch gleich zu Beginn lädst:

#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

Die ersten beiden Bibliotheken sollten in deiner Arduino IDE bereits vorinstalliert sein. Falls nicht, kannst du sie unter Werkzeuge/Bibliotheken verwalten hinzufügen.

Die Bibliothek ArduinoJson.h vom Entwickler Benoit Blanchon findest du in deinem Bibliotheksverwalter, indem du einfach nach „ArduinoJson“ suchst und installierst.

Bibliothek ArduinoJson.h

Bevor es richtig losgehen kann, trage als nächstes deine WLAN-Zugangsdaten in den Sketch ein:

const char* ssid = "Name deines WLAN-Netzwerks";
const char* password =  "Dein WLAN-Passwort";

Die Setup-Funktion

In der Funktion void setup() verwendest du Code, um deinen ESP32 mit dem Internet zu verbinden:

void setup() {
 
  Serial.begin(115200);
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Ich verbinde mich mit dem Netzwerk...");
  }
 
  Serial.println("Ich bin mit dem Netzwerk verbunden!");
}

Hier startest du Verbindung zu deinem Seriellen Monitor und rufst die Funktion WiFi.begin() auf, die dich mit Hilfe deiner Zugangsdaten mit deinem WLAN-Netzwerk verbindet. Sobald die Verbindung steht, informiert dich dein Controller hierüber im Seriellen Monitor.

Die News abrufen, verarbeiten und ausgeben

Jetzt wird es spannend! In der Funktion void loop() rufst du alle 10 Sekunden eine Funktion auf, die die aktuellen Schlagzeilen von einer API als JSON abruft, sie verarbeitet und in deinem Seriellen Monitor ausgibt:

void loop() {
  apiCall();
  delay(10000);
}

Du kannst den Inhalt der Funktion apiCall() natürlich auch direkt in deinem Loop schreiben. Für mehr Übersichtlichkeit ist sie in diesem Projekt jedoch eigenständig angelegt.

Mit dem Internet verbinden und die JSON-Daten per API Call abrufen

Schauen wir uns diese Funktion also Schritt für Schritt an.

void apiCall(){

  if ((WiFi.status() == WL_CONNECTED)) {

Du definierst zunächst natürlich die Funktion selbst. Dann startest du mit einer If-Abfrage, um herauszufinden, ob dein ESP32 tatsächlich mit deinem WLAN-Netzwerk verbunden ist. Ist das der Fall, geht es weiter.

HTTPClient http;
 
http.begin("https://newsapi.org/v2/top-headlines?country=us&apiKey=API_KEY");

Zuerst erstellst du eine Instanz von HTTPClient mit dem Namen http. Diesen Namen verwendest du im folgenden Code als Präfix für alle Funktionen, die du verwendest.

Da wäre als erstes http.begin(). Als Parameter gibst du dieser Funktion die URL zur API mit, von der du die News abrufen möchtest. Und an dieser Stelle müssen wir einen kurzen Abstecher machen.

Beim Anbieter News API kannst du dich als Privatperson kostenlos registrieren, um dort aktuelle Schlagzeilen abzurufen. Hinweis: Leider hat News API den Service für internationale Medien eingestellt – es ist nur noch die Abfrage US-amerikanischer Schlagzeilen möglich. Falls du an deutschsprachigen Nachrichten interessiert bist, wirf einen Blick in dieses Raspberry Pi Projekt.

Webseite News API

Die Registrierung geht schnell und unkompliziert. Anschließend erhältst du deinen eigenen API Key, den du benötigst, um die Nachrichten abrufen zu dürfen.

Wichtig: Auf newsapi.org findest du deinen API Key, indem du auf deine E-Mail-Adresse rechts oben klickst. Diesen Key musst du im Sketch in Zeile 14 an die URL anhängen, indem du API_KEY durch deinen Key ersetzt:

https://newsapi.org/v2/top-headlines?country=us&apiKey=API_KEY

Achte darauf, beim Einsetzen deines Keys keine anderen Zeichen zu überschreiben. Ohne API Key oder mit einer fehlerhaften URL funktioniert die Abfrage nicht.

Klicke danach auf den Menüpunkt Get started und anschließend im linken Menü auf Top headlines. Auf den Kacheln, die du jetzt siehst, findest du verschiedene Beispiele für API-Abfragen:

API Calls Beispiele

Neben dem grünen Label GET siehst du bereits die fertige URL für die Funktion http.begin() in deinem Sketch. Praktisch: Dein API Key ist auch schon integriert.

Klicke dich ein wenig durch das Angebot des Anbieters und probiere verschiedene URLs aus! Im Code oben ist eine URL für die Top-Schlagzeilen aus US-amerikanischen Medien integriert, aber du kannst diese nach Belieben austauschen. So kannst du zum Beispiel reine Business News abrufen oder auch nur Schlagzeilen zu einem bestimmten Suchbegriff.

Aber zurück zum Code: Um den API Call auszuführen, benötigst du zunächst die Funktion http.GET(). Diese erhält einen Status Code zurück, den du in einer Variable speicherst. Und weiter geht’s:

int httpCode = http.GET();

if (httpCode == 200) {
    Serial.println(httpCode);

Wenn du eine gültige Antwort vom News API Server bekommst, lautet der Status Code 200. Nur dann kann der Sketch weitermachen. Auf Wikipedia erfährst du mehr über Status Codes.

Bei einer erfolgreichen Abfrage (mit dem Status 200 also) erhältst du JSON-Daten, die die News sowie weitere Metadaten enthalten. Wie diese Daten in ihrer Rohform aussehen, kannst du herausfinden, indem du die URL aus deinem Code in einem Browser aufrufst. 🙂

Damit kannst du natürlich erst mal wenig anfangen, denn so die Nachrichten zu lesen, macht keinen Spaß. Also musst du diese JSON-Daten verarbeiten – bzw. parsen. Was das alles bedeutet? Auch beim Thema JSON und Parsing hilft dir Wikipedia weiter.

Zunächst speicherst du die Rohdaten in einer Variable des Typs String, um sie danach zu verarbeiten:

String payload = http.getString();

Die JSON-Daten parsen

Jetzt wird es ernst – und auch etwas knifflig. Um es nicht zu kompliziert zu machen, sollen vorerst einfache Erklärungen ausreichen. In der Dokumentation der Bibliothek ArduinoJson erfährst du alle Details, wenn du möchtest.

Also in aller Kürze: Damit dein ESP32 die Daten verarbeiten kann, müssen wir erst einmal den hierfür benötigten Speicherbedarf berechnen. Das machst du am einfachsten, indem du den offiziellen Assistenten der Bibliothek verwendest.

Rufe dafür die URL, die du weiter oben im Sketch eingetragen hast, in einem Browser auf. Markiere dann den gesamten Text, kopiere ihn und setze ihn in das linke Feld Input ein. Im Feld Parsing program darunter findest du anschließend die Zeile Code, die du für deinen Sketch brauchst:

Speicherbedarf ArduinoJson

In diesem Projekt ist das diese:

const size_t capacity = JSON_ARRAY_SIZE(20) + 20*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + 20*JSON_OBJECT_SIZE(8) + 19020;

Anschließend folgen einige Funktionen und Abfragen, um die JSON-Daten zu verarbeiten und diese Verarbeitung bei einem Fehler zu stoppen:

DynamicJsonDocument doc(capacity);

DeserializationError error = deserializeJson(doc, payload);
        
if (error) {
   Serial.print(F("deserializeJson() hat nicht funktioniert: "));
   Serial.println(error.c_str());
   return;
   }

Jetzt bist du fast am Ziel! Im Hintergrund hat dein Sketch bereits die JSON-Daten strukturiert und die verschiedenen Inhalte mehreren Konstanten (const) zugewiesen. Du musst dir nur noch die Rosinen rauspicken.

In diesem Projekt ist das der Titel der neuesten Nachricht. Du wählst zunächst das Array articles aus den Rohdaten aus. Hieraus wiederum den ersten, also neuesten Artikel articles[0] und von diesem wiederum den Titel [„title“]. Zuletzt gibst du diesen title, also deine Schlagzeile, im Seriellen Monitor aus:

JsonArray articles = doc["articles"];

JsonObject articles_0 = articles[0];

const char* articles_0_title = articles_0["title"];

Serial.println(articles_0_title);
}

Was jetzt noch fehlt, sind ein else{} bei einem Status Code, der nicht 200 entspricht – du erinnerst dich an diese Abfrage weiter oben? Und eine Funktion, mit der wir den API-Call wieder beenden:

else {
  Serial.println("Fehlerhafter HTTP-Request");
  }
 
http.end(); //Free the resources
}
}

Das war’s! In deinem Seriellen Monitor sollte jetzt alle 10 Sekunden die neueste Schlagzeile aus der von dir per URL definierten Nachrichtenquelle erscheinen. Hier nun der gesamte Sketch:

#include <ArduinoJson.h>
#include <WiFi.h>
#include <HTTPClient.h>

// WLAN-Daten
const char* ssid = "WLAN-NETZWERK";
const char* password =  "PASSWORT";

void apiCall(){
  if ((WiFi.status() == WL_CONNECTED)) {
 
    HTTPClient http;
 
    http.begin("https://newsapi.org/v2/top-headlines?country=us&apiKey=API_KEY");
    
    int httpCode = http.GET();
 
    if (httpCode == 200) {

        Serial.println(httpCode);
 
        String payload = http.getString();
        
        const size_t capacity = JSON_ARRAY_SIZE(20) + 20*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + 20*JSON_OBJECT_SIZE(8) + 19020;
        
        DynamicJsonDocument doc(capacity);

        DeserializationError error = deserializeJson(doc, payload);
        
        if (error) {
           Serial.print(F("deserializeJson() hat nicht funktioniert: "));
           Serial.println(error.c_str());
           return;
           }

        JsonArray articles = doc["articles"];

        JsonObject articles_0 = articles[0];

        const char* articles_0_title = articles_0["title"];

        Serial.println(articles_0_title);
        }
 
        else {
          Serial.println("Fehlerhafter HTTP-Request");
          }
 
        http.end();
        }
  }

void setup() {
 
  Serial.begin(115200);
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Ich verbinde mich mit dem Netzwerk...");
  }
 
  Serial.println("Ich bin mit dem Netzwerk verbunden!");
}
 
void loop() {
  apiCall();
  delay(10000);
}

Funktioniert nicht?

Wenn in deinem Seriellen Monitor keine Nachrichten erscheinen, prüfe bitte folgende Fehlerquellen:

  • Hast du in den Zeilen 6 und 7 deine WLAN-Daten eingetragen?
  • Hast du in der URL in Zeile 14 deinen API Key von newsapi.org eingetragen?
  • Sind alle verwenden Bibliotheken auf dem neuesten Stand?

Wie geht es weiter?

Mach deinen neuen Newsticker smart und baue noch einen Geräuschsensor dazu, um immer dann die News abzurufen, wenn du in die Hände klatschst. Lerne hier, wie du einen Geräuschsensor am Arduino (oder ESP32) verwendest.

Natürlich kannst du auch ein Display installieren und die Schlagzeilen darauf anzeigen lassen, damit du nicht auf deinen Seriellen Monitor angewiesen bist. Sicher fallen dir noch viele weitere Optimierungen ein! 🙂

]]>