Internet – Pollux Labs https://polluxlabs.net Arduino, ESP32 & ESP8266 | Projekte & Tutorials Sun, 04 Feb 2024 14:39:24 +0000 de-DE hourly 1 https://wordpress.org/?v=6.5.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 So erzeugst du KI Bilder mit Python und deepAI Weiterlesen »

]]>
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 Countdown zum nächsten SpaceX Raketenstart Weiterlesen »

]]>
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 Gute oder schlechte Nachrichten? Mit einer Sentimentanalyse findest du es heraus. Weiterlesen »

]]>
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.

___STEADY_PAYWALL___

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 Beleuchte deine LEGO Mondlandefähre, wenn der Mond am Himmel steht Weiterlesen »

]]>

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 Das Licht ein- und ausschalten mit Telegram Weiterlesen »

]]>
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

___STEADY_PAYWALL___

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 Video-Livestream mit der ESP32-CAM Weiterlesen »

]]>
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 Die aktuelle Temperatur per Telegram abfragen Weiterlesen »

]]>
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

___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 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 Überwache die Temperatur mit Telegram und einem ESP8266 Weiterlesen »

]]>
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 Beleuchte deine LEGO ISS im Rhythmus der echten Raumstation Weiterlesen »

]]>
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 diesem Tutorial 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):

Angebot
LEGO 21321 Ideas Internationale Raumstation
LEGO 21321 Ideas Internationale Raumstation
Verpackungsabmessungen (L x B x H): 6.9 x 26.2 x 38.2 Zm; Beschreibung der Altersgruppe:...
114,95 €
AZDelivery 5 x 5V RGB LED Ring Kompitabel mit WS2812B 12-Bit 38mm kompatibel mit Arduino inklusive E-Book!
AZDelivery 5 x 5V RGB LED Ring Kompitabel mit WS2812B 12-Bit 38mm kompatibel mit Arduino inklusive E-Book!
✅ 12 leuchtstarke LEDs. Einzeln adressierbar; ✅ Kompatibel mit Digispark u.v.m.; ✅...
16,99 €
Angebot
ELEGOO Steckbrett 6er Set 170 Tie Points Mini Breadboard Kit für Arduino
ELEGOO Steckbrett 6er Set 170 Tie Points Mini Breadboard Kit für Arduino
Diese Teile sind gut um ganz kleine Schaltungen oder nur einen Chip zu verdraten.; 6...
6,79 €
AZDelivery 3 x Jumper Wire Kabel 40 STK. je 20 cm M2M Male to Male kompatibel mit Arduino und Raspberry Pi Breadboard
AZDelivery 3 x Jumper Wire Kabel 40 STK. je 20 cm M2M Male to Male kompatibel mit Arduino und Raspberry Pi Breadboard
✅ Länge der Kabel: 20 cm / 120 Stück pro Einheit / 120 Stück insgesamt; ✅...
6,99 €

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 Eine Fotofalle mit der ESP32-CAM und Telegram Weiterlesen »

]]>
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.

]]>