Projektdokumentation - Internet of Things mit dem NanoESP

IoTeaTimer
Internet of Things Tea Timer
General Overnight
31. Januar 2016
ii
Inhaltsverzeichnis
Inhalt
iii
1 Projektvorstellung
1.1 Funktionsweise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Anwendung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
1
2
2 Aufbau der Schaltung
2.1 Begründung der gewählten Anschlussbelegung . . . . . . . . . . . . . . . . . .
2.2 Die Alarmtöne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.1 Die Tonauswahl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
3
4
4
3 Die Software
3.1 Software-Features . . . . . . . . .
3.1.1 Modularisierung . . . . .
3.1.2 Tests und Debugging . . .
3.1.3 Kommentare im Quelltext
5
5
5
6
6
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4 Geplante Weiterentwicklung
7
A Schaltpläne
9
B Quelltext-Listings
11
C Verwendete Bauteile
29
iii
iv
INHALTSVERZEICHNIS
Kapitel 1
Projektvorstellung
Abbildung 1.1: Internet of Tea
Der IoTeaTimer löst folgendes Problem. Je nach Art, muss ein echter oder Kräutertee drei
bis 15 Minuten ziehen. Erfolgt die Teezubereitung nicht dort, wo er getrunken wird (etwa im
Arbeitszimmer), sondern beispielsweise in der Küche, dann kann er leicht vergessen werden
und viel zu lange ziehen.
Handelsübliche Kurzzeitmesser lösen das Problem nur unbefriedigend. Zuallererst müssen
sie bei jedem Raumwechsel mitgenommen werden. Gerade bei modernen, elektronischen
Geräten besteht dabei die Gefahr, dass die Zeiteinstellung versehentlich verändert wird, weil
der Gerätedesigner die Bedienungselemente ausgerechnet in alle nutzbaren Griffflächen oder
deren unmittelbare Nähe gelegt hat1 Bei den im Handel erhältlichen Kurzzeitmessern ist
darüber hinaus meist auch das Umstellen der Zeiten aufwändig und lästig, wenn verschiedene
1
Die Bedienelemente in den Griffflächen sind ein ähnlich verbreitetes und benutzerfreundliches“ Feature
”
wie die streng monochrome Beschriftung (schwarz auf schwarz oder weiß auf weiß), auf die Douglas Adams
im Hitchhiker’s Guide to the Galaxy“ angespielt hat und die auch auf dem Breadboard Syb-46 zu finden ist.
”
Möglicherweise ist das eine Art Produktdarwinismus, der die Absatzmärkte für besonders hässliche, explizit
als barrierefrei vermarktete Produkte sichern soll, anstatt alle benutzerfreundlich zu gestalten.
1
2
KAPITEL 1. PROJEKTVORSTELLUNG
Teesorten im Wechsel zubereitet oder die Timer auch für andere Zwecke eingesetzt werden.
Dabei sind eigentlich meist nur wenige, immer gleiche Zeiten nötig.
1.1
Funktionsweise
Um die beschriebenen Probleme zu lösen erlaubt der IoTeaTimer mehrere voreingestellte
Alarmzeiten auf Tastendruck zu aktivieren. Weiterhin signalisiert er den Ablauf der Zeit nicht
nur lokal, per Signalton und LED. Er stellt einen WLAN Access Point zur Verfügung, an dem
sich andere Geräte anmelden können und dann über einen UDP-Broadcast benachrichtigt
werden. Dadurch kann der IoTeaTimer (wie auch die im Haus oder der Wohnung verteilten
Empfänger) immer an seinem Platz verbleiben. So sind die Geräte immer griffbereit und es
wird kein Alarm übersehen bzw. überhört, weil gerade niemand im Raum ist.
Als Empfänger für die Alarmmeldungen eignet sich besonders die Geräte aus dem Schwesterprojekt IoTPager, das ebenfalls auf Basis des nanoESP realisiert ist. Dieser erzeugt die
gleichen Alarmsignale wie der IoTeaTimer.
1.2
Anwendung
Nach dem Einschalten (dem Anschließen der Stromversorgung) oder einem Reset meldet sich
der IoTeaTimer mit einem Dreiklang, sobald das Gerät betriebsbereit ist. Ab diesem Zeitpunkt
kann über die beiden Taster ein Timer gestartet werden.
In der ersten Version aktiviert jeder der beiden Taster einen Timer unterschiedlicher Länge
und es kann nur jeweils ein Timer laufen. Dies wird in der zweiten Version geändert (siehe
Kapitel 4).
Die RGB-LED signalisiert durch ihre Farbe, welche voreingestellte Alarmzeit gewählt
wurde (Rot: 5 min, Grün: 15 min). Sie wechselt dabei im Sekundentakt zwischen der vollen
und einer reduzierten Helligkeit, die vom Verhältnis der Restlaufzeit zur Gesamtzeit abhängt.
Das heißt, sie leuchtet zunächst praktisch stetig und beginnt dann immer stärker zu blinken.
Kurz vor dem Ablauf des Timers alarmiert der IoTeaTimer alle Geräte, die sich an seinem Access Point angemeldet haben und auf den entsprechenden Timerablauf warten. Die
Benachrichtigungen werden per UDP an die Ports 1070 (roter Timer), 1071 (gelber Timer),
1072 (grüner Timer) oder 1073 (blauer Timer) gesendet. Anschließend spielt er für 20 Sekunden eine Tonsequenz ab und lässt die LED in der Farbe des ablaufenden Timers blinken. Das
präzise Ende des Timeouts fällt mit dem Ende der Tonsequenz zusammen.
Tipp Ein versehentlich aktivierter Timer kann durch Drücken des Reset-Tasters auf dem
Pretzelboard deaktiviert werden.
Kapitel 2
Aufbau der Schaltung
Der Zusammenbau des IoTeaTimers beginnt mit dem Einsetzen des nanoESP in das Breadboard. Dies geschieht in etwas anderer Weise als beim IoT-Adventskalender 2015. Anstatt in
die Reihen D und H, werden die Reihen E und I genutzt. Das lässt oberhalb des Pretzelboards
mehr Raum, um die Taster so zu platzieren, dass sie keine ungenutzten Eingänge schalten.
Abbildung 2.1: Aufbau des IoTeaTimers auf einem Breadboard
Die obere Verbindungsleiste wird über eine Drahtbrücke mit dem Masseanschluss an Pin 4
des Pretzelboards verbunden (Spalte 20, Reihe X und A).
Der erste Taster wird mit zwei verbunden Anschlüssen auf der rechten Seite in die Spalte 20
3
4
KAPITEL 2. AUFBAU DER SCHALTUNG
gesetzt (Reihe B und D), in der auch der Masse-Pin des Pretzelboards steckt. Die anderen
beiden Anschlüsse stecken dann in der Spalte 17 (Pin D3).
Für den kollisionsfreien Einbau des zweiten Tasters muss ein Anschlussbeinchen hochgebogen werden. Er steckt mit einem Paar seiner verbundenen Anschlüsse in den Spalten 19
und 16 der Verbindungsleiste am oberen Rand des Breadboards (Masseanschluss). Das Beinchen links unten würde dadurch normalerweise mit dem Ausgang D5 des nanoESP verbunden
werden (Spalte 16), der aber für die RGB-LED benötigt wird. Damit der Taster trotzdem gut
im Breadboard hält, werden die Anschlüsse mit einer Zange flach gedrückt und der Taster
auf dem Board mit einem Tropfen Heißkleber fixiert.
Die RGB-LED kann mit ihrem Masse-Anschluss direkt in der oberen Verbindungsschiene sitzen. Drei 1 kΩ-Widerstände verbinden schließlich die Ausgänge D5, D6 und D9 des
Pretzelboards mit den Anoden der RGB-LED.
2.1
Begründung der gewählten Anschlussbelegung
Die Taster sind an die Pins D3 und D4 angeschlossen, da diese als einzige eine Interruptsteuerung ermöglichen. Das wird in der vorliegenden Version zwar noch nicht genutzt, soll aber bei
einer späteren Erweiterung eine schnelle Reaktion auf Benutzereingaben sicherstellen. Durch
diese Wahl geht zwar einer der knappen PWM-Ausgänge verloren, sie vermeidet aber auch
Probleme durch Interferenzen zwischen PWM- und Tonausgabe, die laut Datenblatt beim
Anschluss des Piezo-Summers an Pin D3 entstehen können.
RGB-LED und Piezo-Summer benötigen PWM-Ausgänge. Für ihren Anschluss bleiben
also noch die Ausgänge D5 und D6 sowie D9 und D10. Die RGB-LED soll mit veränderlicher
Helligkeit betrieben werden und muss daher über Pulsweitenmodulation (PWM) gesteuert
werden. Die Wahl des Ausgangs D10 für den Summer führt zum Anschluss der LED über die
aufeinanderfolgenden Ausgänge D5 (rot), D6 (grün) und D9 (blau).
2.2
Die Alarmtöne
Ohne einen Resonanzkörper erzeugt ein Piezo-Signalgeber nur extrem leise Töne und eignet sich in dieser Form nicht für eine praktische Anwendung im IoTeaTimer. Eine deutliche
Steigerung der Lautstärke lässt sich schon durch eine Befestigung mit Klebeband auf einer
ebenen Fläche erreichen. Eine weitere Verbesserung bringt die Montage des Summers über einem Hohlraum. Die optimale Befestigung erfolgt laut Datenblatt eines Herstellers im Zentrum
der kreisförmigen Scheibe. Praktikabler ist die zweitgünstigste Montageart, das Befestigen am
äußersten Rand.
Für den Einbau des Summers in den IoTeaTimer wird mit einem 26 mm Forstnerbohrer
ein etwa 5 mm tiefes Loch in die Grundplatte aus 10 mm Sperrholz gebohrt (siehe Bild 2.2).
Da der Piezo-Summer aus dem IoT-Adventskalender einen Durchmesser von 27 mm hat,
ergibt sich ein Überstand von einem halben Millimeter. Die vom Forstnerbohrer erzeugte
Zentrierbohrung wird mit einem 3 mm Bohrer durchgebohrt. Im praktischen Versuch zeigt
das einen etwas besseren Klang. Das kleine Loch lässt sich für einen Vergleich sehr leicht
2.2. DIE ALARMTÖNE
5
schließen und öffnen. Zum Testen erfolgt die Befestigung des Summers zunächst mit einem
breiten, transparenten Klebestreifen (siehe Bild 2.3).
Abbildung 2.2: Die Grundplatte für den IoTeaTimer
2.2.1
Die Tonauswahl
Im Vergleich mit einem Lautsprecher bleibt der Frequenzgang des Summers auch nach dem
Einbau in ein Gehäuse sehr ungleichmäßig. Er hängt zudem stark vom verwendeten Modell
und von der Art des Einbaus ab. Daher sollte die Alarmtonsequenz schon unabhängig vom
persönlichen Geschmack individuell angepasst werden. Um das zu vereinfachen sind in der
Datei mytones.h Makros für den brauchbaren Frequenzbereich enthalten, die eine Ausgabe
von Tönen anhand der Namen aus der Tonleiter ermöglichen.
6
KAPITEL 2. AUFBAU DER SCHALTUNG
Abbildung 2.3: Einbau des Piezo-Summers
Kapitel 3
Die Software
Die Implementation des IoTeaTimers nutzt einen Ansatz, der die Anpassung der Software und auch die Entwicklung ganz neuer Projekte auf einfache Art erleichtert, ohne eigene
Bibliotheken zu definieren. Dazu sind in IoTeaTimer.ino (siehe Listing B.1)
1. zunächst alle Code-Bestandteile an den Dateianfang gerückt, die lokal anzupassen oder
häufig zu ändern sind.
2. folgen danach projektspezifische Funktionen, in denen die Funktionalitäten gekapselt
sind, die aus der Hauptschleife (void loop() {...} ) aufgerufen werden. So bleiben diese
generischen Funktionen kurz und lassen sich leicht anpassen, wenn der Quelltext für ein
geändertes oder neues Projekt übernommen wird.
3. sind immer gleiche Code-Teile, die üblicherweise von Projekt zu Projekt mitgenommen
werden, in eigene Dateien ausgelagert, die über Präprozessor-Direktiven (#include ” ... ”)
eingebunden werden1 .
3.1
3.1.1
Software-Features
Modularisierung
Beim Aufbau der Experimente aus dem IoT-Adventskalender ist aufgefallen, dass große Teile
des Codes unverändert in das neue Projekt übernommen werden mussten. Die beim IoTeaTimer genutzte Modularisierung vereinfacht das, da die gleichbleibenden Code-Teile in separate
Dateien ausgelagert sind, die einfach kopiert werden können. Im Idealfall muss dann lediglich die Hauptdatei des Projekts angepasst werden. Dazu wurde außerdem eine möglichst
universelle Belegung der I/O-Pins entworfen.
1
In spitzen Klammern notierte Namen innerhalb von Include-Direktiven beziehen sich auf Header-Dateien
in Systemverzeichnissen. Dagegen sucht der Präprozessor in Gänsefüßchen notierte Dateinamen im aktuellen
Verzeichnis, d.h. dort, wo auch die Hauptdatei <Projektname>.ino liegt.
7
8
KAPITEL 3. DIE SOFTWARE
3.1.2
Tests und Debugging
Folgende Features erleichtern beim IoTeaTimer das Testen und die Fehlersuche (Debugging).
• Debug-Meldungen können über Syslog-kompatible Level nach ihrem Wichtigkeitsgrad
gekennzeichnet und damit selektiv ein- und ausgeschaltet werden.
• Durch Definition des Makros NDEBUG können alle Debugausgaben komplett abgeschaltet werden.
• Die Funktion zur Ausgabe von Debug-Meldungen ersetzt Passwörter und andere sensitive Zeichenketten durch gleichlange Strings, die nur aus dem Buchstaben X“bestehen.
”
• Für Testzwecke kann über das Makro TEST ACTIONS eine reduzierte Minutenlänge
eingestellt werden.
Bei der Kodierung der Präprozessor-Direktiven wurde darauf geachtet, dass deaktivierter Code möglichst komplett aus dem kompilierten Quelltext verschwindet, um die knappen
Ressourcen des Pretzelboards nicht unnötig zu strapazieren.
1
i f (DEBUG) { . . . }
Das Makro DEBUG wird hier erst zur Laufzeit abgefragt, als jedesmal, wenn das Programm an der entsprechenden Stelle ausgeführt wird. Der Wert des Makros wird aber beim
Kompilieren festgelegt und ändert sich nit im lauffähigen Programm.
1
2
3
#i f DEBUG
...
#e n d i f
Bei dieser Notation alles zwischen dem #if DEBUG und dem #endif bereits vom Präprozessor, d.h. vor dem eigentlichen Kompilieren aus dem Quelltext entfernt, wenn DEBUG den
Wert false hat. Er benötigt daher weder Speicherplatz noch andere Ressourcen während des
Programmablaufs.
3.1.3
Kommentare im Quelltext
Um die Übersichtlichkeit des Quellcodes zu verbessern, sind Kommentare die der Dokumentation dienen im C-Stil notiert (/∗ Kommentartext ∗/). Der C++-Stil (// Kommentartext) wird
dagegen für das (vorübergehende) Auskommentieren, d.h. Deaktivieren von Code-Zeilen genutzt.
Kapitel 4
Geplante Weiterentwicklung
• Erweiterung auf vier vordefinierte Alarmzeiten (rot, gelb, grün, blau), die mit Taster 1
ausgewählt und mit Taster 2 aktiviert werden.
• Unterstützung für den unabhängigen Ablauf mehrerer, verschiedener Timer.
• Einbau des Bewegungsschalters aus dem Elektronik-Adventskalender, sodass ein laufender Alarm durch Bewegen des Geräts bestätigt und damit beendet werden kann.
9
10
KAPITEL 4. GEPLANTE WEITERENTWICKLUNG
Anhang A
Schaltpläne
Abbildung A.1: IoTeaTimer Breadboard Layout
11
12
ANHANG A. SCHALTPLÄNE
Anhang B
Quelltext-Listings
Listing B.1: Hauptquelltext IoTeaTimer.ino
1
2
3
4
5
6
7
8
9
/∗
∗ IoT Tea Timer − s e t an alarm on a nanoESP , r e c e i v e i t v i a i n e t ( WiFi ) .
∗
∗ (C) 2016 Gener a l O ver nig ht <g e n e r a l o v e r n i g h t . w o r d p r e s s . com>
∗
∗ This i s Fr ee S o f t w a r e a v a i l a b l e under t h e GNU Gener a l P u b l i c L i c e n s e (GPL ) .
∗
∗ $ Id : IoTeaTimer . ino , v 1 . 6 2016−01−31 0 8 : 5 5 : 3 0 manolo Exp $
∗/
10
11
12
13
14
/∗ I n c l u d e Arduino . h b e f o r e any l o c a l hea der f i l e s a s i s t p r o v i d e s t h e
∗ s t a n d a r d t y p e s used t h e r e i n ( l i k e b o o l e a n o r S t r i n g ) .
∗/
#i n c l u d e <Arduino . h>
15
16
17
18
19
#i n c l u d e
#i n c l u d e
#i n c l u d e
#i n c l u d e
” mytones . h”
” lo g debug . h”
” wla nsetup . h”
” ser ia lco mm . h”
20
21
22
23
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗∗ ∗∗ ∗∗∗ ∗ ∗/
/∗ ∗∗∗ Debug s e t t i n g s ∗∗∗ ∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗∗ ∗∗ ∗∗∗ ∗ ∗/
24
25
26
27
28
/∗ NOTE: uncomment t h e f o l l o w i n g l i n e f o r f u l l y s i l e n t o p e r a t i o n
∗ r e g a r d l e s s o f t h e DEBUG s e t t i n g below ( p r o d u c t i o n co de ) .
∗/
#d e f i n e NDEBUG
29
30
31
32
33
34
/∗ We use a s u b s e t o f t h e s t a n d a r d s y s l o g l e v e l s f o r c l a s s i f y i n g debug
∗ o utput h e r e . These a r e d e f i n e d i n ” lo g debug . h” and i n c l u d e can be
∗ s p e c i f i e d with t h e macros LVL EROR, LVL WARN, LVL NOTE, LVL INFO and
∗ LVL DBUG.
∗/
35
13
14
36
37
38
39
ANHANG B. QUELLTEXT-LISTINGS
/∗ S e t t h e minimum l e v e l o f debug messa g es t o be p r i n t e d ( d e f a u l t s t o
∗ LVL WARN i f u n d e f i n e d )
∗/
#d e f i n e DEBUG LVL INFO
40
41
42
43
44
45
46
47
48
#i f n d e f NDEBUG
/∗ This f l a g e n a b l e s s h o r t a c t i o n t i m e o u t s so you don ’ t have t o wa it a
∗ l o n g time when t e s t i n g t h e c o r r e s p o n d i n g f u n c t i o n s .
∗/
# d e f i n e TEST ACTIONS
/∗ NOTE: comment out t h e f o l l o w i n g l i n e t o e n a b l e TEST ACTIONS ∗/
# undef TEST ACTIONS
#e n d i f
49
50
51
52
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗/
/∗ ∗∗∗ End s e c t i o n : Debug s e t t i n g s ∗∗∗ ∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗/
53
54
55
56
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗/
/∗ ∗∗∗ Custom S e t t i n g s − E dit h e r e ! ∗∗∗ ∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗/
57
58
59
60
61
/∗ Read i n t h e SSID , PSK and IP s e t t i n g s from s e c r e t s . h ( t h a t f i l e has
∗ t o be c r e a t e d l o c a l l y , s e e example−s e c r e t s . h )
∗/
#i n c l u d e ” s e c r e t s . h”
62
63
64
/∗ D e f a u l t timeo ut f o r AT commands ∗/
#d e f i n e DEFTO 6000
65
66
67
68
69
70
71
72
73
#i f d e f TEST ACTIONS
/∗ Reduced l e n g t h o f a minute t o speed up t e s t i n g ( t h i s s h o u l d be
∗ g r e a t e r than ADJTIME + ALRMLEN)
∗/
# d e f i n e MINUTE LEN 12
#e l s e
# d e f i n e MINUTE LEN REAL MINUTE
#e n d i f
74
75
76
77
78
/∗ Adjust t h e timeo ut by t h i s many s e c o n d s t o a cco unt f o r t h e time s p e n t
∗ s e n d i n g t h e alarm o v e r t h e w i r e l e s s network .
∗/
#d e f i n e ADJTIME 18
79
80
81
82
83
84
/∗ The d u r a t i o n o f t h e alarm sound w i l l be s u b t r a c t e d from t h e timeo ut
∗ so t h a t t h e end o f t h e sound o utput marks t h e p r e c i s e end o f t h e
∗ timeo ut .
∗/
#d e f i n e ALRMLEN 20
85
86
87
88
/∗ B l i n k t h e onboard LED D3 ( p i n 1 3 ) t o i n d i c a t e a c t i v i t y i f t r u e , e l s e
∗ t h e RGB−LED.
∗/
15
89
90
//#d e f i n e USE ONBOARD LED t r u e
#d e f i n e USE ONBOARD LED f a l s e
91
92
93
94
95
/∗ Red t i m e r : 5 min ∗/
#d e f i n e TIME R 5
/∗ Green t i m e r 15 min ∗/
#d e f i n e TIME G 15
96
97
98
99
100
101
102
103
104
105
/∗ ∗∗ D e s t i n a t i o n UDP Port numbers , d e f i n e d a s s t r i n g s f o r c o n v e n i e n c e ∗∗ ∗/
/∗ Red alarm ∗/
#d e f i n e PORT R ” 1070”
/∗ Green alarm ∗/
#d e f i n e PORT Y ” 1071”
/∗ Blue alarm ∗/
#d e f i n e PORT G ” 1072”
/∗ Yellow alarm ∗/
#d e f i n e PORT B ” 1073”
106
107
108
109
110
111
112
113
114
/∗ D e f i n e ( a s t a n d a r d ) I /O p i n s e t u p ∗/
#d e f i n e BTN0 2 /∗ I n t e r r u p t ∗/
#d e f i n e BTN1 3 /∗ I n t e r r u p t (PWM a l s o , but to ne o utput may i n t e r f e r e ) ∗/
#d e f i n e LED COM 8
#d e f i n e LED R 5 /∗ PWM ∗/
#d e f i n e LED G 6 /∗ PWM ∗/
#d e f i n e LED B 9 /∗ PWM ∗/
#d e f i n e BUZZ 10 /∗ PWM ∗/
115
116
117
118
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗∗ ∗∗ ∗∗ ∗∗ ∗∗ ∗ ∗/
/∗ ∗∗∗ End custom S e t t i n g s ∗∗∗ ∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗∗ ∗∗ ∗∗ ∗∗ ∗∗ ∗ ∗/
119
120
121
/∗ number o f s e c o n d s i n a r e a l ( w a l l c l o c k ) minute ∗/
#d e f i n e REAL MINUTE 60
122
123
124
/∗ maximum v a l u e f o r PWM o u t p u t s ∗/
#d e f i n e MAXPWM 255
125
126
127
128
/∗ S e t up t h e s e r i a l c o n n c t i o n between Atmega MCU and ESP WLAN−Module ∗/
#i n c l u d e <S o f t w a r e S e r i a l . h>
S o f t w a r e S e r i a l esp8 2 6 6 ( 1 1 , 1 2 ) ;
129
130
131
132
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗/
/∗ ∗∗∗ Custom F u n c t i o n s : E dit h e r e ∗∗∗ ∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗/
133
134
/∗ ∗∗∗ Event h a n d l e r ∗∗∗ ∗/
135
136
137
138
139
140
141
i n t ha ndleButto n ( i n t btn )
{
int rc = 0;
i n t l e d = −1;
i n t timeo ut = 0 ;
S t r i n g p o r t = ”−” ;
16
142
ANHANG B. QUELLTEXT-LISTINGS
unsigned long s t a r t = m i l l i s ( ) ;
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
s w i t c h ( btn )
{
c a s e BTN0 :
l e d = LED R ;
p o r t = PORT R;
timeo ut = TIME R ∗ MINUTE LEN − ADJTIME − ALRMLEN;
br ea k ;
c a s e BTN1 :
l e d = LED G ;
p o r t = PORT G;
timeo ut = TIME G ∗ MINUTE LEN − ADJTIME − ALRMLEN;
br ea k ;
default :
/∗ s o f t w a r e e r r o r ( c f . s y s e x i t s . h ) ∗/
rc = 70;
dbg (LVL EROR, ” S o f t w a r e e r r o r : i n v a l i d butto n ID : ” + S t r i n g ( btn ) ) ;
}
161
162
163
164
i f ( 0 == r c )
{
dbg (LVL INFO , ” Button a c t i v a t e d , timeo ut = ” + S t r i n g ( timeo ut ) ) ;
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
d i g i t a l W r i t e ( l e d , HIGH ) ;
/∗ Who i s c o n n e c t e d ? ∗/
dbg (LVL INFO , runATcmd( ”+CWLIF” , 1 ) ) ;
/∗ Spend t h e time u n t i l t h e s c h e d u l e d timeo ut i n a l o o p b l i n k i n g an LED ∗/
f o r ( i n t i = timeo ut ; i −− > 0 ; )
{
#i f USE ONBOARD LED
d i g i t a l W r i t e (LED BUILTIN , i % 2 ) ;
#e l s e
r g bWr ite ( l e d , ( u n s i g n e d i n t ) ( ( f l o a t )MAXPWM ∗ ( f l o a t ) i / ( f l o a t ) timeo ut ) ) ;
#e n d i f
delay (999);
}
/∗ Timeout ! Send an alarm o v e r WiFi f i r s t . . . ∗/
i f ( configUDP ( p o r t ) )
{
to ne (BUZZ, TONE a2 , 2 0 0 ) ;
delay (200);
/∗ Someone c o n n e c t e d ? ∗/
dbg ( runATcmd ( ”+CWLIF” , 1 ) ) ;
// Alas , ESP c h o k e s on t h i s :
//sendUDP(DSTIP , po r t , ”ALRM” ) ;
sendUDP( ”ALRM” ) ;
to ne (BUZZ, TONE c1 , 2 0 0 ) ;
delay (200);
runATcmd( ”+CIPCLOSE” , ”OK” ) ;
to ne (BUZZ, TONE c1 , 2 0 0 ) ;
delay (200);
} else {
17
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
dbg ( ” E r r o r o pening UDP c o n n e c t i o n ” ) ;
to ne (BUZZ, TONE dis2 , 2 0 0 ) ;
delay (200);
}
dbg (LVL NOTE,
” Network alarm f i n i s h e d a f t e r ” + S t r i n g ( ( m i l l i s ( ) − s t a r t ) / 1 0 0 0 )
+ ” seconds . ” ) ;
/∗ sound an alarm ∗/
#i f USE ONBOARD LED
d i g i t a l W r i t e (LED BUILTIN , HIGH ) ;
#e n d i f
f o r ( i n t i = 5 ; i −− > 0 ; )
{
r g bWr ite ( l e d , LOW) ;
to ne (BUZZ, TONE c1 ) ;
/∗ to ne r e t u r n s immedia tely , use d e l a y t o d e t e r m i n e i t s d u r a t i o n ∗/
delay (1000);
r g bWr ite ( l e d , LOW) ;
to ne (BUZZ, TONE e1 ) ;
delay (1000);
r g bWr ite ( l e d , LOW) ;
to ne (BUZZ, TONE g1 ) ;
delay (1000);
r g bWr ite ( l e d , LOW) ;
to ne (BUZZ, TONE ais2 , 1 0 0 0 ) ;
delay (1000);
noTone (BUZZ ) ;
}
dbg (LVL NOTE,
” Timer f i n i s h e d a f t e r ” + S t r i n g ( ( m i l l i s ( ) − s t a r t ) / 1 0 0 0 )
+ ” seconds . ” ) ;
/∗ . . . f i n a l l y r e s e t t h e t i m e r LED ∗/
d i g i t a l W r i t e ( l e d , LOW) ;
}
}
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
/∗ L i g h t s up t h e RGB LED a l t e r n a t i n g between f u l l on and a dimmed mode
∗ s p e c i f i e d by t h e b r i g h t n e s s pa r a meter .
∗
∗ TODO: The c o l o u r pa r a meter c u r r e n t l y o n l y s u p p o r t s r ed and g r e e n
∗ b l u e . I t e x p e c t s t h e p i n number a s i t s v a l u e which i s t o be changed .
∗
∗/
v o i d r g bWr ite ( u n s i g n e d i n t c o l o u r , u n s i g n e d i n t b r i g h t n e s s )
{
/∗ A v a r i a b l e d e c l a r e d s t a t i c k e e p s i t s v a l u e a c r o s s m u l t i p l e
∗ i n v o c a t i o n s and i s i n i t i a l i z e d o n l y once , when t h e f u n c t i o n i s
∗ f i r s t run .
∗/
s t a t i c boolean t o g g l e = f a l s e ;
246
247
#i f n d e f NDEBUG
18
248
249
250
251
252
253
254
255
256
257
258
259
260
261
ANHANG B. QUELLTEXT-LISTINGS
/∗ Use a s t a n d a r d C p r i n f f u n c t i o n t o fo r ma t t h e s t r i n g t o be o utput
∗ with S e r i a l . p r i n t l n i n t o a C c h a r a c t e r a r r a y o f a p p r o p r i a t e l e n g t h
∗ (80 c h a r a c t e r s d e f a u l t terminal l i n e length ) .
∗/
cha r msg [ 8 2 ] = ” ” ;
/∗ One e x t r a byte a t t h e end f o r t h e ASCII−NUL t e r m i n a t i n g t h e
∗ C−s t r i n g and an a d d i t i o n a l one a s a s a f e t y n e t .
∗/
s n p r i n t f ( msg , s i z e o f ( msg) −2 ,
” r g bWr ite ( c o l o u r=%u , b r i g h t n e s s=%u ) ” , c o l o u r , b r i g h t n e s s ) ;
S e r i a l . p r i n t l n ( msg ) ;
#e n d i f
/∗ s a n i t y check t h e b r i g h t n e s s v a l u e t o guard a g a i n s t programming e r r o r s ∗/
i f ( b r i g h t n e s s > MAXPWM) { b r i g h t n e s s = MAXPWM; }
262
/∗ Reset a l l LED o u t p u t s f i r s t ∗/
d i g i t a l W r i t e (LED R , LOW) ;
d i g i t a l W r i t e (LED G, LOW) ;
d i g i t a l W r i t e (LED B , LOW) ;
i f ( toggle )
{
/∗ L i g h t up t h e LED with t h e s p e c i f i e d c o l o u r i n f u l l b r i g h t n e s s ∗/
switch ( colour ) {
c a s e LED R :
d i g i t a l W r i t e (LED R , HIGH ) ;
br ea k ;
c a s e LED G :
d i g i t a l W r i t e (LED G, HIGH ) ;
br ea k ;
}
}
else
{
/∗ L i g h t up t h e LED with t h e s p e c i f i e d c o l o u r i n r educed b r i g h t n e s s ∗/
switch ( colour ) {
c a s e LED R :
a n a l o g W r i t e (LED R , b r i g h t n e s s ) ;
br ea k ;
c a s e LED G :
a n a l o g W r i t e (LED G, b r i g h t n e s s ) ;
br ea k ;
}
}
/∗ t o g g l e t h e v a l u e o f t o g g l e f o r t h e next run ∗/
toggle = ! toggle ;
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
}
294
295
296
297
298
299
300
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗/
/∗ ∗∗∗ End custom f u n c t i o n s ∗∗∗ ∗/
/∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗∗ ∗∗ ∗∗ ∗ ∗/
19
301
/∗ === Main ============================================================= ∗/
302
303
304
305
306
void setup ( ) {
int rc = 0;
S e r i a l . begin (19200);
esp8 2 6 6 . b e g i n ( 1 9 2 0 0 ) ;
307
to ne (BUZZ, TONE h2 , 5 0 0 ) ;
308
309
i f ( 0 != ( r c = e s p C o n f i g ( ) ) ) {
to ne (BUZZ, TONE h2 , 1 5 0 0 ) ;
f o r ( i n t i = r c ; i > 0 ; i >>=1) {
/∗ to ne r e t u r n s i m m e d i a t e l y so a d e l a y i s n e c e s s a r y a s
∗ l o n g a s t h e beep d u r a t i o n a t l e a s t ( seco nd a r g t o to ne ) .
∗/
delay (1000);
to ne (BUZZ, TONE h, 5 0 0 ) ;
}
serialDebug ( ) ;
} else {
to ne (BUZZ, TONE c1 , 5 0 0 ) ;
}
310
311
312
313
314
315
316
317
318
319
320
321
322
323
/∗ c o n f i g u r e I /O ∗/
pinMode (LED R , OUTPUT) ;
pinMode (LED G, OUTPUT) ;
pinMode (LED B , OUTPUT) ;
pinMode (BTN0, INPUT PULLUP ) ;
pinMode (BTN1, INPUT PULLUP ) ;
324
325
326
327
328
329
330
/∗ Play a t r i a d ( D r e i k l a n g ) when r ea dy The to ne d u r a t i o n i s not
∗ s p e c i f i e d but l i m i t e d by t h e f o l l o w i n g commands .
∗/
to ne (BUZZ, TONE c1 ) ;
delay (500);
to ne (BUZZ, TONE dis1 ) ;
delay (500);
to ne (BUZZ, TONE gis1 , 5 0 0 ) ;
delay (500);
331
332
333
334
335
336
337
338
339
340
}
341
342
343
344
345
346
347
348
349
350
351
352
353
void loop ( ) {
b o o l e a n sw0 = ! d i g i t a l R e a d (BTN0) , sw1 = ! d i g i t a l R e a d (BTN1 ) ;
#i f DEBUG > 1
s t a t i c u n s i g n e d l o n g timestamp = m i l l i s ( ) ;
u n s i g n e d l o n g now = m i l l i s ( ) ;
u n s i g n e d l o n g r untime = now − timestamp ;
i f ( r untime ) {
dbg ( 7 , ” Program Uptime : ” + S t r i n g ( now / 1 0 0 0 . 0 )
+ ” s ; Main l o o p : p r e v i o u s run ”
+ S t r i n g ( r untime ) + ” ms ago ; Buttons : ”
+ S t r i n g ( sw0 ) + ” , ” + S t r i n g ( sw1 ) ) ;
20
354
355
356
357
358
359
360
ANHANG B. QUELLTEXT-LISTINGS
} else {
dbg ( 7 , ” Program Uptime : ” + S t r i n g ( now / 1 0 0 0 . 0 )
+ ” s . Main l o o p : f i r s t run ; Buttons : ”
+ S t r i n g ( sw0 ) + ” , ” + S t r i n g ( sw1 ) ) ;
}
timestamp = now ;
#e n d i f
361
i f ( sw0 | sw1 )
{
i f ( sw0 )
{
/∗ sw1 has been p r e s s e d ∗/
ha ndleButto n (BTN0 ) ;
}
e l s e /∗ sw1 must have been p r e s s e d , e l s e we had not e n t e r e d t h i s l o o p ∗/
{
ha ndleButto n (BTN1 ) ;
}
} else {
/∗ Check t h e s e r i a l Atmel−ESP l i n k f o r pending data , p r o c e s s i t , i f
∗ any o r wa it a q u a r t e r o f a seco nd b e f o r e t h e next l o o p run .
∗/
i f ( ! s e r i a l I O ()) { delay (250); }
}
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
}
380
381
382
/∗ ====== End Main ====================================================== ∗/
383
384
385
386
// L o c a l V a r i a b l e s :
// mode : c++
// End :
Listing B.2: Tondefinitionen in mytones.h
1
2
#i f n d e f MYTONES H
#d e f i n e MYTONES H
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// D e f i n e some named p i t c h e s
#d e f i n e TONE h
247
#d e f i n e TONE a1
440
#d e f i n e TONE h1
494
#d e f i n e TONE c1
523
#d e f i n e TONE cis1 554
#d e f i n e TONE d
587
#d e f i n e TONE dis1 622
#d e f i n e TONE e1
659
#d e f i n e TONE eis1 698
#d e f i n e TONE fis1 740
#d e f i n e TONE g1
784
#d e f i n e TONE gis1 830
#d e f i n e TONE dis2 1174
#d e f i n e TONE g2
1568
21
19
20
21
22
23
24
25
26
27
28
29
30
31
#d e f i n e TONE gis2
#d e f i n e TONE a2
#d e f i n e TONE ais2
//
#d e f i n e TONE h2
#d e f i n e TONE c3
//
#d e f i n e TONE cis3
#d e f i n e TONE Gis3
#d e f i n e TONE a3
#d e f i n e TONE h3
#d e f i n e TONE c3
//#d e f i n e TONE
1661
1760
1865
++
1975
2093
+
2217
3322
3520
3729
3951
32
33
34
#e n d i f
Listing B.3: Logging- und Debug-Funktionen in logdebug.ino
1
2
3
4
5
6
7
8
9
/∗
∗ Common l o g g i n g and debug g ing f u n c t i o n s .
∗
∗ (C) 2016 Gener a l O ver nig ht <g e n e r a l o v e r n i g h t . w o r d p r e s s . com>
∗
∗ This i s Fr ee S o f t w a r e a v a i l a b l e under t h e GNU Gener a l P u b l i c L i c e n s e (GPL ) .
∗
∗ $ Id : lo g debug . ino , v 1 . 1 2016−01−31 0 8 : 5 5 : 3 0 manolo Exp $
∗/
10
11
12
13
14
15
16
17
void serialDebug ( void ) {
while ( true )
{
i f ( esp8 2 6 6 . a v a i l a b l e ( ) ) { S e r i a l . w r i t e ( esp8 2 6 6 . r ea d ( ) ) ; }
i f ( S e r i a l . a v a i l a b l e ( ) ) { esp8 2 6 6 . w r i t e ( S e r i a l . r ea d ( ) ) ; }
}
}
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
v o i d dbg ( S t r i n g msg )
{
#i f d e f DEBUG
c o n s t S t r i n g s e c r e t s [ ] = { PSK, SSID , } ;
/∗ Repla ce any i n s t a n c e s o f t h e s e c r e t s d e f i n e d above i n t h e message
∗ with a e q u a l l e n g t h s t r i n g o f Xs .
∗
∗ s i z e o f ( s e c r e t s ) r e t u r n s t h e number o f b y t e s o c c u p i e d by t h e s e c r e t s a r r a y .
∗ This i s d i v i d e d by t h e s p a c e n e c e s s a r y t o ho ld a S t r i n g item t o g e t
∗ t h e number a c t u a l number o f i t e m s i n t h e a r r a y .
∗
∗ We s t a r t from t h e end o f t h e a r r a y f o r c o n v e n i e n c e .
∗/
f o r ( i n t i = s i z e o f ( s e c r e t s ) / s i z e o f ( S t r i n g ) ; i −− > 0 ; ) {
/∗ t r y t o f i n d t h e s t r i n g a t p o s i t i o n i i n s e c r e t s i n t h e msg
∗ String .
22
36
37
38
39
40
41
42
43
44
45
46
47
48
49
ANHANG B. QUELLTEXT-LISTINGS
∗/
i n t s t a r t = msg . indexO f ( s e c r e t s [ i ] ) ;
i f (−1 < s t a r t ) {
S t r i n g newmsg = msg . s u b s t r i n g ( 0 , s t a r t ) ;
f o r ( i n t k = s e c r e t s [ i ] . l e n g t h ( ) ; k−− > 0 ; ) {
newmsg += ”X” ;
}
msg = newmsg + msg . s u b s t r i n g ( s t a r t + s e c r e t s [ i ] . l e n g t h ( ) ) ;
}
}
/∗ F i n a l l y o utput t h e s a n i t i z e d message ∗/#
S e r i a l . p r i n t l n ( msg ) ;
#e n d i f
}
50
51
52
53
54
55
56
57
58
59
60
61
62
v o i d dbg ( i n t l e v e l , S t r i n g msg )
{
#i f n d e f NDEBUG
#i f d e f DEBUG
i f ( l e v e l <= DEBUG) {
#e l s e
i f ( l e v e l <= LVL WARN) {
#e n d i f
dbg ( msg ) ;
}
#e n d i f
}
63
64
65
66
67
// L o c a l V a r i a b l e s :
// mode : c++
// End :
Listing B.4: Headerdatei für logdebug.ino
1
2
3
4
5
6
7
8
9
/∗
∗ Common l o g g i n g and debug g ing f u n c t i o n s .
∗
∗ (C) 2016 Gener a l O ver nig ht <g e n e r a l o v e r n i g h t . w o r d p r e s s . com>
∗
∗ This i s Fr ee S o f t w a r e a v a i l a b l e under t h e GNU Gener a l P u b l i c L i c e n s e (GPL ) .
∗
∗ $ Id : lo g debug . h , v 1 . 1 2016−01−31 0 8 : 5 5 : 3 0 manolo Exp $
∗/
10
11
12
#i f n d e f LOGDEBUG H
#d e f i n e LOGDEBUG H
13
14
15
16
17
18
19
/∗ We use a s u b s e t
∗ o utput h e r e .
∗/
#d e f i n e LVL EROR 3
#d e f i n e LVL WARN 4
#d e f i n e LVL NOTE 5
o f t h e s t a n d a r d s y s l o g l e v e l s f o r c l a s s i f y i n g debug
/∗ e r r o r messa g es ∗/
/∗ wa r ning s ∗/
/∗ normal but n o t a b l e i n f o r m a t i o n ∗/
23
20
21
22
#d e f i n e LVL INFO 6 /∗ t h i n g s which may be i n t e r e s t i n g t o a u s e r but
don ’ t r e q u i r e a c t i o n ∗/
#d e f i n e LVL DBUG 7 /∗ debug g ing messa g es ∗/
23
24
25
v o i d dbg ( i n t l e v e l , S t r i n g msg ) ;
26
27
v o i d dbg ( S t r i n g msg ) ;
28
29
void serialDebug ( void ) ;
30
31
#e n d i f
Listing B.5: Setup-Funktionen für das ESP-Modul in wlansetup.ino
1
2
3
4
5
6
7
8
9
/∗
∗ F u n c t i o n s f o r s e t t i n g up t h e ESP8266 WLAN module .
∗
∗ (C) 2016 Gener a l O ver nig ht <g e n e r a l o v e r n i g h t . w o r d p r e s s . com>
∗
∗ This i s Fr ee S o f t w a r e a v a i l a b l e under t h e GNU Gener a l P u b l i c L i c e n s e (GPL ) .
∗
∗ $ Id : wla nsetup . ino , v 1 . 1 2016−01−31 0 8 : 5 5 : 3 1 manolo Exp $
∗/
10
11
12
13
int espConfig ()
{
int rc = 0;
14
15
16
17
18
/∗ i n c r e a s e t h e timeo ut f o r r e s e t t i n g t h e ESP ∗/
esp8 2 6 6 . setTimeo ut (DEFTO ∗ 3 ) ;
/∗ send a r e s e t command t o t h e ESP8266 and wa it f o r t h e s t r i n g ” r ea dy ” ∗/
r c |= runATcmd( ”+RST” , ” r ea dy ” ) ;
19
20
21
22
23
24
25
26
27
/∗ c o n f i g u r e a s a WLAN a c c e s s p o i n t ∗/
i f ( ! configAP ( SSID , PSK) ) {
esp8 2 6 6 . setTimeo ut (DEFTO) ;
dbg (LVL NOTE, ”WiFi A c c e s s p o i n t s u c c e s s f u l l y s e t up with c o n f i g : ” ) ;
dbg (LVL NOTE, runATcmd( ”+CIFSR” , 3 ) ) ;
} else {
r c |= 0 x2 ;
}
28
29
30
31
r c |= ( runATcmd ( ”+CIPMODE=0” , ”OK” ) ) << 3 ;
r c |= ( runATcmd ( ”+CIPMUX=0” , ”OK” ) ) << 2 ;
esp8 2 6 6 . setTimeo ut (DEFTO) ;
32
33
34
35
36
37
38
39
/∗ f i n a l l y l i g h t up t h e onboard LED i f e v e r y t h i n g went OK ∗/
i f ( 0 == r c ) {
d i g i t a l W r i t e (LED BUILTIN , HIGH ) ;
} else {
dbg ( ”ESP c o n f i g e r r o r : ” + S t r i n g ( r c ) ) ;
}
24
return rc ;
40
41
ANHANG B. QUELLTEXT-LISTINGS
}
42
43
44
45
46
i n t configAP ( S t r i n g s s i d , S t r i n g psk )
{
int rc = 0;
47
/∗ i n c r e a s e t h e timeout , AP s e t u p commands may t a k e s i g n i f i c a n t l y more
∗ time t o f i n i s h .
∗/
esp8 2 6 6 . setTimeo ut (DEFTO ∗ 2 ) ;
r c |= ( runATcmd ( ”+CWMODE=2” , ”OK” ) ) ;
/∗ S e t up WiFi AP with p a r a m e t e r s ( i n RAM o n l y ) :
∗
SSID , PSK, c h a n n e l number (1 −14) , e n c r y p t i o n i n d e x (0 −4)
∗/
r c |= ( runATcmd ( ”+CWSAP CUR=\””+S t r i n g ( s s i d )+” \ ” , \ ” ”+S t r i n g ( psk)+” \ ” , 1 , 3 ” ,
”OK” ) ) ;
/∗ S e t t h e IP a d d r e s s f o r t h e AP ( i n RAM o n l y ) ∗/
r c |= ( runATcmd ( ”+CIPAP CUR=\”” SRCIP ” \” ” , ”OK” ) ) ;
/∗ Reset t h e timeo ut v a l u e ∗/
esp8 2 6 6 . setTimeo ut (DEFTO) ;
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
return rc ;
63
64
}
65
66
67
68
i n t configUDP ( S t r i n g p o r t )
{
int rc = 0;
69
esp8 2 6 6 . setTimeo ut (DEFTO + DEFTO / 2 ) ;
r c |= ! runATcmd ( ”+CIPMODE=0” , ”OK” ) ;
r c |= ! runATcmd ( ”+CIPMUX=0” , ”OK” ) ;
/∗ S t a r t an UDP Br o a dca st s e r v e r ∗/
r c |= ! runATcmd ( ”+CIPSTART=\”UDP\ ” , \ ” ” DSTIP ” \ ” , ” + po r t , ”OK” ) ;
esp8 2 6 6 . setTimeo ut (DEFTO) ;
70
71
72
73
74
75
76
return rc ;
77
78
}
79
80
81
82
83
// L o c a l V a r i a b l e s :
// mode : c++
// End :
Listing B.6: Headerdatei für wlansetup.ino
1
2
3
4
5
6
7
/∗
∗ F u n c t i o n s f o r s e t t i n g up t h e ESP8266 WLAN module .
∗
∗ (C) 2016 Gener a l O ver nig ht <g e n e r a l o v e r n i g h t . w o r d p r e s s . com>
∗
∗ This i s Fr ee S o f t w a r e a v a i l a b l e under t h e GNU Gener a l P u b l i c L i c e n s e (GPL ) .
∗
25
∗ $ Id : wla nsetup . h , v 1 . 1 2016−01−31 0 8 : 5 5 : 3 1 manolo Exp $
∗/
8
9
10
11
12
#i f n d e f WLANSETUP H
#d e f i n e WLANSETUP H
13
14
int espConfig ( ) ;
15
16
i n t configAP ( S t r i n g s s i d , S t r i n g psk ) ;
17
18
i n t configUDP ( S t r i n g p o r t ) ;
19
20
#e n d i f
21
22
23
24
// L o c a l V a r i a b l e s :
// mode : c++
// End :
Listing B.7: Funktionen für serielle Kommunikation zwischen MCU und WLAN-Modul serialcomm.ino
1
2
3
4
5
6
7
8
9
/∗
∗ F u n c t i o n s p e r t a i n i n g t o s e r i a l I /O between t h e Atmega MCU and t h e ESP .
∗
∗ (C) 2016 Gener a l O ver nig ht <g e n e r a l o v e r n i g h t . w o r d p r e s s . com>
∗
∗ This i s Fr ee S o f t w a r e a v a i l a b l e under t h e GNU Gener a l P u b l i c L i c e n s e (GPL ) .
∗
∗ $ Id : ser ia lco mm . ino , v 1 . 1 2016−01−31 0 8 : 5 5 : 3 0 manolo Exp $
∗/
10
11
#i n c l u d e ” ser ia lco mm . h”
12
13
14
15
16
b o o l e a n sendUDP( S t r i n g addr , S t r i n g po r t , S t r i n g da ta )
{
boolean rc = 0 ;
17
esp8 2 6 6 . setTimeo ut (DEFTO) ;
r c = runATcmd( ”+CIPSEND=” + S t r i n g ( da ta . l e n g t h ( ) + 2 ) + ” , ” + addr + ” , ” + po r t ,
data , ”OK” ) ;
18
19
20
21
return rc ;
22
23
}
24
25
26
27
28
29
30
31
32
/∗
∗ Send t h e s p e c i f i e d da ta v i a UDP.
∗
∗ Retur ns t r u e ( 1 ) on e r r o r .
∗/
b o o l e a n sendUDP( S t r i n g da ta )
{
26
ANHANG B. QUELLTEXT-LISTINGS
boolean rc = 0 ;
33
34
esp8 2 6 6 . setTimeo ut (DEFTO) ;
r c = runATcmd( ”+CIPSEND=” + S t r i n g ( da ta . l e n g t h ( ) + 2 ) , data , ”OK” ) ;
35
36
37
return rc ;
38
39
}
40
41
42
43
44
45
46
47
48
/∗
∗ Run t h e s p e c i f i e d AT command , r e t u r n i n g t h e r e s p o n s e
∗/
S t r i n g runATcmd( S t r i n g command)
{
S t r i n g r e s p = ” ” , cmd = ”AT” + command ;
int start ;
49
esp8 2 6 6 . p r i n t l n (cmd ) ;
r e s p = esp8 2 6 6 . r e a d S t r i n g ( ) ;
dbg (LVL DBUG, ”# ” + cmd + ” = ” + r e s p ) ;
w h i l e (−1 < ( s t a r t = r e s p . indexO f ( command ) ) ) {
r e s p . remove ( s t a r t , 1 + command . l e n g t h ( ) ) ;
}
50
51
52
53
54
55
56
return ( resp ) ;
57
58
}
59
60
61
62
63
64
65
66
67
68
/∗
∗ Run t h e s p e c i f i e d AT command , r e t u r n i n g t h e r e s p o n s e but remove a t
∗ most s t r i p L e v e l i n s t a n c e s o f t h e command name b e f o r e h a n d .
∗/
S t r i n g runATcmd( S t r i n g command , i n t s t r i p L e v e l )
{
S t r i n g r e s p = ” ” , cmd = ”AT” + command ;
int start ;
69
esp8 2 6 6 . p r i n t l n (cmd ) ;
r e s p = esp8 2 6 6 . r e a d S t r i n g ( ) ;
dbg (LVL DBUG, ”# ” + cmd + ” = ” + r e s p ) ;
w h i l e ( s t r i p L e v e l −− > 0 && −1 < ( s t a r t = r e s p . indexO f ( command ) ) ) {
r e s p . remove ( s t a r t , 1 + command . l e n g t h ( ) ) ;
}
70
71
72
73
74
75
76
return ( resp ) ;
77
78
}
79
80
81
82
83
84
85
/∗
∗ Run s p e c i f i e d AT command , w a i t i n g f o r an e x p e c t e d r e s p o n s e s t r i n g .
∗
∗ Retur ns t r u e ( 1 ) on e r r o r
∗/
27
86
87
88
89
b o o l e a n runATcmd( S t r i n g command , cha r e x p e c t [ ] )
{
r e t u r n (runATcmd ( command , ” ” , e x p e c t ) ) ;
}
90
91
92
93
94
95
96
97
98
99
100
/∗
∗ Run s p e c i f i e d AT command with o p t i o n a l da ta t o send .
∗
∗ Retur ns t r u e ( 1 ) on e r r o r
∗/
b o o l e a n runATcmd( S t r i n g command , S t r i n g data , cha r e x p e c t [ ] )
{
b o o l e a n r c = f a l s e , found = f a l s e , withda ta = b o o l e a n ( da ta . l e n g t h ( ) ) ;
S t r i n g r e s p o n s e = ” ” , cmd = ”AT” + command ;
101
esp8 2 6 6 . p r i n t l n (cmd ) ;
102
103
w h i l e ( ! ( found | | r c ) ) {
r e s p o n s e = esp8 2 6 6 . r e a d S t r i n g U n t i l ( ’ \n ’ ) ;
i f ( 1 + r e s p o n s e . indexO f ( ”ERROR” ) ) {
rc = true ;
} e l s e i f ( 1 + r e s p o n s e . indexO f ( withda ta ? ”>” : e x p e c t ) ) {
found = t r u e ;
}
dbg ( ”>>> ” + r e s p o n s e ) ;
}
104
105
106
107
108
109
110
111
112
113
i f ( withda ta ) {
dbg ( ” . . . s e n d i n g da ta : ’ ” + da ta + ” ’ ” ) ;
esp8 2 6 6 . p r i n t l n ( da ta ) ;
r c |= ! esp8 2 6 6 . f i n d U n t i l ( expect , ”ERROR” ) ;
}
114
115
116
117
118
119
dbg (LVL DBUG, ”# AT+” + cmd + ” = ” + r e s p o n s e ) ;
120
121
i f ( rc )
{
dbg (LVL EROR, ” E r r o r s e n d i n g command : ” + cmd + ” : ” + r e s p o n s e ) ;
} else {
dbg (LVL INFO , ”Command s u c c e s s f u l : ” + cmd ) ;
}
return ( rc ) ;
122
123
124
125
126
127
128
129
}
130
131
132
133
134
135
136
137
138
/∗
∗ Retur ns :
∗
f a l s e : when no da ta were a v a i l a b l e ,
∗
t r u e : when da ta were exchanged
∗/
boolean s e r i a l I O ( )
{
28
ANHANG B. QUELLTEXT-LISTINGS
boolean rc = f a l s e ;
u n s i g n e d l o n g time ;
139
140
141
/∗ Read da ta from t h e ESP i f a v a i l a b l e , but don ’ t l o c k out o t h e r
∗ program p a r t s and s t o p o nce da ta were r ea d .
∗/
w h i l e ( ! r c && esp8 2 6 6 . a v a i l a b l e ( ) ) {
S e r i a l . w r i t e ( esp8 2 6 6 . r ea d ( ) ) ;
rc = true ;
}
142
143
144
145
146
147
148
149
w h i l e ( ! r c && S e r i a l . a v a i l a b l e ( ) ) {
esp8 2 6 6 . w r i t e ( S e r i a l . r ea d ( ) ) ;
rc = true ;
}
150
151
152
153
154
return ( rc ) ;
155
156
}
157
158
159
160
161
// L o c a l V a r i a b l e s :
// mode : c++
// End :
Listing B.8: Headerdatei für serialcomm.ino
1
2
3
4
5
6
7
8
9
/∗
∗ F u n c t i o n s p e r t a i n i n g t o s e r i a l I /O between t h e Atmega MCU and t h e ESP .
∗
∗ (C) 2016 Gener a l O ver nig ht <g e n e r a l o v e r n i g h t . w o r d p r e s s . com>
∗
∗ This i s Fr ee S o f t w a r e a v a i l a b l e under t h e GNU Gener a l P u b l i c L i c e n s e (GPL ) .
∗
∗ $ Id : ser ia lco mm . h , v 1 . 1 2016−01−31 0 8 : 5 5 : 3 0 manolo Exp $
∗/
10
11
12
#i f n d e f SERIALCOMM H
#d e f i n e SERIALCOMM H
13
14
b o o l e a n sendUDP( S t r i n g addr , S t r i n g po r t , S t r i n g da ta ) ;
15
16
b o o l e a n sendUDP( S t r i n g da ta ) ;
17
18
S t r i n g runATcmd( S t r i n g command ) ;
19
20
S t r i n g runATcmd( S t r i n g command , i n t s t r i p L e v e l ) ;
21
22
b o o l e a n runATcmd( S t r i n g command , cha r e x p e c t [ ] ) ;
23
24
b o o l e a n runATcmd( S t r i n g command , S t r i n g data , cha r e x p e c t [ ] ) ;
25
26
27
28
boolean s e r i a l I O ( void ) ;
29
29
#e n d i f
30
ANHANG B. QUELLTEXT-LISTINGS
Anhang C
Verwendete Bauteile
Der IoTeaTimer setzt sich aus folgenden Teilen zusammen, die im IoT- oder im ElektronikAdventskalender 2015 enthalten waren.
1. Breadboard Syb-46
2. nanoESP (Pretzelboard)
3. ca. 15 mm Kupferdraht (isoliert)
4. 3 Widerstände 1kΩ
5. 2 Taster
6. RGB-LED
7. Piezo-Summer
Um die Tonausgabe des Summers und die Handhabbarkeit des Aufbaus zu verbessern
wird außerdem eine aus Sperrholz (Länge 120 mm, Breite ca. 50–60 mm, Stärke ca. 10 mm)
benötigt, die durch weitere Brettchen zu einem geschlossenen Gehäuse ergänzt werden kann.
31
32
ANHANG C. VERWENDETE BAUTEILE