home     Inhaltsverzeichnis
erste Version am 24.12.2017
letzte Änderung am 07.01.2018

LED-Streifen als Nachtlicht - Seite 4

Logging über WLAN

Der Taster ist verbaut und zieht, wenn betätigt, D12 auf Masse.
Das Neu-Einmessen funktioniert zwar, dessen Einleitung stellt sich jedoch äußert schwierig dar. Weil... Taster drücken und gleichzeitig die 12V anschließen grenzt an fortgeschrittene Akrobatik. Ein Schalter oder eine Jumper-Brücke wäre schlauer gewesen.

Und das Sensor-Gehäuse ist immer noch nicht an die Wand geschraubt, weil es neue Probleme gibt:
Der ESP-01-WLAN-Adapter läuft mit Standard-Firmware und muss somit über AT-Befehle gesteuert werden. Daher kommt es zu Änderungen des Laufzeitverhaltens. Schließlich muss der ATmega328 vor jeder Kommunikation sicherstellen, dass der ESP-01 im WLAN eingebucht ist und die Verbindung zum SocketServer steht. Das dauert normalerweise unter einer Sekunde (wenn die Einbuchung im WLAN noch steht). Manchmal aber auch deutlich länger.
Daher kommt es gelegentlich zu sehr sonderbaren Effekten und das wiederum macht quasi sämtliche Messwerte unbrauchbar.
Nicht tragisch, aber ganz speziell verwunderlich ist der Umstand, dass die LEDs jede Nacht pünktlich 36 bis 38 Sekunden nach 03:10 Uhr eingeschaltet werden. Nun ist 03:10 Uhr genau die Zeit, zu der der WLAN-Router seinen Reboot fährt. Folglich stirbt die WLAN-Verbindung. Eigentlich sollte das kein Grund für den ATmega328 sein, aufzuwachen. Aber wer weiß, was die AT-Firmware in so einem Fall macht..... 30 Sekunden lang viel Strom ziehen wahrscheinlich.... und der LF50CV war ja nicht dafür dimensioniert, zusätzlich einen 3,3V-Regler plus ESP-01 zu versorgen.

Für stabiles Laufzeitverhalten hilft eigentlich nur, sämtliche Funktionen mit variabler Laufzeit auf den ESP8266 auszulagern.
Aus diesem Grund starte ich bereits jetzt mit dem angedachten Folgeprojekt. Also dem "WLAN-Syslog-Adapter" alias Logging-Device.

So. Nun ist Feierabend mit den AT-Befehlen. Das Logging-Device hängt am Nachtlicht und erstmal sieht alles gut aus.

Die erste Nacht mit dem Logging-Device verlief ohne Auffälligkeiten. Auch wurden die LEDs um 03:10 Uhr nicht eingeschaltet.
Nun gibt es zwei mögliche Folge-Aufgaben.
Entweder baue ich das Logging-Device jetzt so um, dass der ATmega328 darüber auch Parameter beim SocketServer anfragen und empfangen kann. Damit ließe sich sowas wie "Helligkeitswert, ab dem die LEDs ausgeschaltet bleiben", "Nachleucht-Dauer" und die "Parameter für die Funktion <PWM-Wert zu Helligkeit>" anpassen, ohne den ATmega328 neu flashen zu müssen.
Oder ich überdenke nochmal den Algorithmus, mit dem die LED-Helligkeit an eine veränderte Gesamt-Helligkeit angepasst wird. Das läuft nämlich doch irgendwie nicht immer ganz so, wie ich mir das vorgestellt habe.


Helligkeits-Anpassung

Wenn Bewegung erkannt wurde und die Helligkeit(1) kleiner/gleich 45 ist, werden die LEDs eingeschaltet.
Die Berechnung ihres PWM-Wertes erfolgt mittels: min(255, map(helligkeit, 0, 45, 3, 255))
Nach Einschalten der LEDs kann nur noch die Gesamt-Helligkeit aus Fremdlicht- und LED-Helligkeit gemessen werden.
Es existiert ein Array, in dem jedem der 256 möglichen PWM-Werte ein Helligkeitswert(2) zugeordnet wird, der von den LEDs ohne Fremdlicht erreicht wird.
Damit ergeben sich folgende (exemplarisch herausgegriffene) Werte:
Helligkeit(1) PWM-Wert Helligkeit(2)
0 3 5
1 8 17
2 14 31
3 19 45
10 59 152
20 115 300
30 171 447
40 227 591
44 249 644
45 255 659
50 255 659
Bem.: Helligkeit(2) wurde zwischenzeitlich neu erfasst und passt nicht mehr ganz zur zweiten Messreihe in der dortigen Spalte "dunkel".

Wenn nun nachträglich Fremdlicht hinzukommt, ändert sich Helligkeit(2).
Der derzeitige Algorithmus verwendet das Array Helligkeit(2) bzw. <Helligkeit zu PWM-Wert ohne Fremdlicht>, um eine Helligkeits-Differenz in die entsprechende PWM-Wert-Differenz umzuwandeln. Implementiert ist es folgendermaßen:
/* -------------------------------------------------------------------
* Liefert zum PWM-Wert "pwm" den PWM-Wert, bei dem die resultierende
* Helligkeit um den Wert von "lum_delta" verändert ist.
* "lum_delta" ist zu berechnen aus neuer_Wert - alter_Wert.
* Also etwa:
* neu(400) - alt(300) = 100 = positiv = heller geworden
* neu(300) - alt(400) = -100 = negativ = dunkler geworden
*/
int recalcPwm2(unsigned char pwm, int lum_delta) {
int fnd, idx=pwm;

fnd=led_lum_g[pwm]+lum_delta;
if(lum_delta<0) { // es ist dunkler geworden
while(idx>3 && led_lum_g[idx]>fnd) {
idx--;
}
} else { // es ist heller geworden
while(idx<255 && led_lum_g[idx]<fnd) {
idx++;
}
}
return(idx);
}

Die Funktion liefert immerhin schon mal neue PWM-Werte, die zu neuen Gesamt-Helligkeiten führen, die gemäß Helligkeits-Differenz in die richtige Richtung gehen.
Das Ergebnis ist allerdings weit davon entfernt, der Helligkeit zu entsprechen, die sich ergeben hätte, wenn die LEDs erst nach der Helligkeits-Änderung eingeschaltet worden wären.
Hier zwei entsprechende Blöcke aus dem Log:
2017.12.28 18:22:38 Info: last_lum_g=25
2017.12.28 18:22:39 Info: runWithLight()
2017.12.28 18:22:39 Info: cur_sec=0  led_val=143  last_lum_g=405  cur_lum=401
2017.12.28 18:22:39 Info: last_lum_g=405  cur_lum=398  led_val=143  led_val2=140
2017.12.28 18:22:39 Info: last_lum_g=396  cur_lum=390  led_val=140  led_val2=138
2017.12.28 18:22:40 Info: last_lum_g=391  cur_lum=385  led_val=138  led_val2=136
2017.12.28 18:22:44 Info: last_lum_g=383  cur_lum=368  led_val=136  led_val2=130
2017.12.28 18:22:44 Info: cur_sec=1  led_val=130  last_lum_g=340  cur_lum=342
2017.12.28 18:22:45 Info: cur_sec=2  led_val=130  last_lum_g=340  cur_lum=341
[...]
2017.12.28 18:23:29 Info: last_lum_g=2
2017.12.28 18:23:29 Info: runWithLight()
2017.12.28 18:23:29 Info: cur_sec=0  led_val=14  last_lum_g=33  cur_lum=34
2017.12.28 18:23:35 Info: cur_sec=1  led_val=14  last_lum_g=33  cur_lum=35
2017.12.28 18:23:36 Info: cur_sec=2  led_val=14  last_lum_g=33  cur_lum=35
Um 18:22:38 wurde Bewegung erkannt. Bevor die LEDs eingeschaltet wurden, betrug die Helligkeit 25 (Treppenlicht war an). Nach Einschalten der LEDs mit PWM-Wert 143 betrug die Gesamt-Helligkeit 405. Um 18:22:39 wurde das Treppenlicht ausgeschaltet. Die Gesamt-Helligkeit hat sich um 7 (von 405 auf 398) geändert. Dadurch wurden die LEDs auf den PWM-Wert 140 runtergedreht. Fünf Sekunden später war die Helligkeit bei 368 und dem PWM-Wert 130 angekommen. Wobei diese fünf Sekunden nicht bedeuten müssen, dass es tatsächlich erst fünf Sekunden später passiert ist. Die Zeitangabe stammt vom SocketServer und zeigt an, wann die Meldung dort angekommen ist. Vielleicht sollte ich noch den Wert von millis() in die Meldung aufnehmen.
Kurz danach um 18:23:29 wurde wieder Bewegung erkannt. Diesmal war das Treppenlicht nicht mehr an. Die Helligkeit betrug 2. Nach Einschalten der LEDs mit PWM-Wert 14 betrug die Gesamt-Helligkeit 33.
Also zwei sehr unterschiedliche Helligkeiten für den identischen Zustand (Treppenlicht ist aus). Helligkeit auf 398 statt 34 und PWM-Wert von 140 statt 14.

Irgendwo in meinem Algorithmus fehlt mir auch die inverse Funktion zu dem min(255, map(helligkeit, 0, 45, 3, 255)).
Also sowas wie map(pwm_wert, 3, 255, 0, 45).
Für pwm_wert=143 liefert der invers_map()=25.
Laut Array gilt: pwm=155 val=406; der invers_map() liefert für 155: 27
Und: pwm=152 val=398; dafür liefert invers_map(): 26
Und für den Wert nach fünf Sekunden: pwm=141 val=369; invers_map()=24
Ich will da aber nicht 24 sondern 2 sehen!

Vielleicht ziehe ich das Delta ja an der falschen Seite ab.
Laut Array gilt: pwm=11 val=25
Also wäre bereits mit dem PWM-Wert 11 die Fremdlicht-Helligkeit von 25 erreicht.
405-368=37
Laut Array gilt: pwm=16 val=37
Der invers_map() liefert zu 16 die 2.

Leider muss der Test von diesem Algorithmus noch etwas warten....
Jetzt stehen erstmal die Weihnachts- und Sylvester-Besuche bei der Sippschaft an.

So...2018...nun gehts weiter...und gleich stellt sich die Frage, was denn passieren soll, wenn die Fremdlicht-Helligkeit zu- statt abnimmt.
Einfach den bisherigen PWM-Wert beizubehalten, wird nicht funktionieren. Bei obigen Daten wird das erste Helligkeits-Delta mit dem Wert 405-398=7 gemeldet, was zum PWM-Wert 3 führen würde. Und wenn dann kein Erhöhen des PWM-Wertes vorgesehen wäre, bliebe es dabei.

Jetzt habe ich spaßeshalber mal die Daten beider Messreihen in Libre Office Calc reingepasted und daraus jeweils ein Diagramm erstellen lassen.
Erste MessreiheZweite Messreihe
Diagramm für die erste Helligkeits-MessreiheDiagramm für die zweite Helligkeits-Messreihe

Dass die Helligkeits-Werte der zweiten Messung derart parallel zueinander verlaufen, hatte ich tatsächlich nicht erwartet. Hätte ich mir das mal früher auf diese Weise angesehen..... dann hätte ich mir den ganzen Heckmeck ab neuer Ansatz sparen können.
Jedenfalls ist diese Erkenntnis ja wohl nur so zu deuten, dass mein allererster Ansatz prinzipiell valide war und der Fehler durch was anderes entstanden sein muss.
Wie schön. Absolute Werte sind mir sowieso sehr viel lieber. Bei Delta-Werten würden sich die prinzip-bedingten Rundungsfehler nach ein paar Iterationen voraussichtlich in den merkbaren Bereich aufsummieren.


zurück auf Los

Nun berechne ich die Fremdlicht-Helligkeit bei eingeschalteten LEDs also wieder aus <aktuell gemessene Helligkeit> minus <gespeicherte LED-Helligkeit gemäß PWM-Wert>.

Der map(helligkeit, 0, 45, 3, 255) liefert folgende PWM-Werte:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 3 8 14 19 25 31 36 42 47 53 59 64 70 75 81 87
16 92 98 103 109 115 120 126 131 137 143 148 154 159 165 171 176
32 182 187 193 199 204 210 215 221 227 232 238 243 249 255

Dies ist der derzeitige Inhalt des Arrays, das die Helligkeits-Werte ohne Fremdlicht zu einem PWM-Wert angibt:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 1415
012 3 5 7 9 11 14 17 20 23 25 26 29 31 35
16 37 40 42 45 48 51 53 56 58 61 63 66 70 72 75 77
32 79 82 85 88 91 93 95 98 101 104 107 109 111 114 117 120
48 123 125 128 130 133 136 138 141 143 147 149 152 154 156 160 163
64 165 168 170 173 175 179 181 183 186 189 192 194 197 200 202 205
80 208 210 213 215 218 221 223 226 228 232 234 237 240 241 245 248
96 250 253 255 258 261 263 266 269 271 274 277 280 281 284 287 290
112 293 295 298 300 303 306 308 311 314 317 318 321 324 328 330 332
128 334 337 340 343 346 348 351 353 355 358 361 364 367 369 371 374
144 377 379 382 385 388 390 392 394 398 401 403 406 408 411 413 416
160 418 422 424 427 428 431 434 437 439 442 445 447 449 452 455 458
176 461 463 465 468 471 473 476 479 481 484 486 488 491 494 496 499
192 501 504 506 509 511 515 518 520 522 525 527 530 532 534 536 539
208 542 544 546 549 552 554 556 559 563 565 568 570 572 575 578 580
224 583 585 588 591 593 595 597 600 603 605 607 610 613 615 617 620
240 623 625 627 630 632 635 637 640 642 644 647 650 652 654 656 659

Nun habe ich folgende Einträge im Log:
2018.01.04 18:26:52 Info: millis=609309  last_lum_g=21
2018.01.04 18:26:53 Info: runWithLight()
2018.01.04 18:26:53 Info: millis=609396  cur_sec=0  led_val=120  last_lum_g=318  cur_lum=323
2018.01.04 18:26:56 Info: millis=609680  last_lum_g=318  cur_lum=325  cur_lum_noLED=11  led_val=120  led_val2=64  (unmotiviert)
2018.01.04 18:26:58 Info: millis=610096  last_lum_g=185  cur_lum=179  cur_lum_noLED=14  led_val=64  led_val2=81   (unmotiviert)
2018.01.04 18:26:59 Info: millis=615954  cur_sec=1  led_val=81  last_lum_g=223  cur_lum=223
[...]
2018.01.04 18:27:09 Info: millis=625924  cur_sec=11  led_val=81  last_lum_g=223  cur_lum=222
2018.01.04 18:27:10 Info: millis=626933  cur_sec=0  led_val=81  last_lum_g=223  cur_lum=224
2018.01.04 18:27:19 Info: millis=636168  last_lum_g=223  cur_lum=200  cur_lum_noLED=0  led_val=81  led_val2=3     (Treppenlicht ausgeschaltet)
2018.01.04 18:27:20 Info: millis=636461  cur_sec=1  led_val=3  last_lum_g=6  cur_lum=6
[...]
2018.01.04 18:27:38 Info: millis=654425  cur_sec=3  led_val=3  last_lum_g=6  cur_lum=6
2018.01.04 18:27:38 Info: millis=654826  last_lum_g=6  cur_lum=32  cur_lum_noLED=27  led_val=3  led_val2=154      (Treppenlicht eingeschaltet)
2018.01.04 18:27:38 Info: millis=655361  cur_sec=4  led_val=154  last_lum_g=410  cur_lum=413
[...]
2018.01.04 18:27:42 Info: millis=658551  cur_sec=0  led_val=154  last_lum_g=410  cur_lum=405
2018.01.04 18:27:44 Info: millis=660771  last_lum_g=410  cur_lum=404  cur_lum_noLED=1  led_val=154  led_val2=8    (unmotiviert)
2018.01.04 18:27:52 Info: millis=668443  cur_sec=1  led_val=8  last_lum_g=44  cur_lum=42
[...]
2018.01.04 18:28:20 Info: millis=696419  cur_sec=29  led_val=8  last_lum_g=44  cur_lum=41
2018.01.04 18:28:21 Info: deepSleep()
Vor der ersten Bewegungserkennung war das Treppenlicht eingeschaltet.
Bei last_lum_g=21 liefert der map() led_val=120. Das Einschalten der LEDs mit 120 führt zu einer neuen Helligkeit last_lum_g=318. Es gilt array[120]=314. Somit hätte es zu 314+21=335 führen sollen.
Dann (0,284 Sekunden später) stieg die Helligkeit auf 325, wodurch ein removeLedLum(120, 325) ausgeführt wurde und das Ergebnis 11 (325-array[120] = 325-314 = 11) geliefert hat. Die Helligkeit 11 führt zum PWM-Wert 64. Und das wiederum zur Helligkeit 185.
Ohne Fremdlicht gilt array[64]=165. Also ein Delta von 20 (185-165=20). Das passt somit zur Treppenlicht-Helligkeit, auch wenn die 11 deutlich von 21 abweicht...
Um 18:26:58 sank die Helligkeit von 185 auf 179. Daher removeLedLum(64, 179) = 14 (179-array[64] = 179-165 = 14).
14 ergibt laut map() 81.
81 führt zur Helligkeit 223. Ohne Fremdlicht gilt array[81]=210. 223-210=13. Passt eher nicht zu 21.
Soweit....so unschön.
Um 18:27:19 habe ich das Treppenlicht ausgeschaltet. Dadurch sank die Helligkeit auf 200. removeLedLum(81, 200) = 0 (200-array[81] = 200-210 = -10).
Zur Helligkeit 0 liefert der map() den PWM-Wert 3, was zur Helligkeit 6 führt.
Um 18:27:38 habe ich das Treppenlicht wieder eingeschaltet. Die Helligkeit stieg von 6 auf 32. removeLedLum(3, 32) = 27 (32-array[3] = 32-5 = 27).
Zu 27 liefert der map() 154. 154 führt zur Helligkeit 410.
Um 18:27:44 wurde stattdessen (unmotiviert) 404 gemeldet. removeLedLum(154, 404) = 1 (404-array[154] = 404-403 = 1).
Zu 1 liefert der map() 8. 8 führt zur Helligkeit 44. Ohne Fremdlicht ergibt array[8]=17. 44-17=27 ... und das passt nicht ganz zur 21 des Treppenlichts.
Fazit: durchaus schlüssig....aber trotzdem verfluchter Mist.

Vielleicht sollte ich den Wert des Mindest-Deltas von derzeit 5 auf 15 ändern. Damit würde auf das Ein- oder Ausschalten des Treppenlichts noch sicher reagiert werden, nicht aber auf kleine Messfehler. Zumindest wären damit die obigen drei unmotivierten Helligkeits-Änderungen nicht verarbeitet worden.
Wahrscheinlich wäre es jedoch effektiver, wenn zwischen PWM-Wert-Änderung und Helligkeits-Messung etwas länger gewartet würde. Derzeit sind es nur zehn Millisekunden.

Beide Änderungen haben nicht zum gewünschten Ergebnis geführt. Irgendwie scheint sich mir die Gesamt-Helligkeit nach einer PWM-Wert-Änderung erst nach mehreren Sekunden stabilisiert zu haben...!?
Deshalb bin ich nun schon zum zweiten mal auf die Idee der schrittweisen Annäherung zurückgekommen. Und zwar diesmal so:
Dieser Algorithmus liefert das bisher beste Ergebnis. Nachdem ich den delay() zwischen den einzelnen Nachregel-Schritten von 100 auf 10 Millisekunden geändert hatte, passt sich die LED-Helligkeit nun auch hinreichend schnell an eine veränderte Fremdlicht-Helligkeit an.
Ich werde das mal ein oder zwei Tage mit dieser Firmware-Version laufen lassen und beobachten.
Derweil fange ich schon mal an, das Nachtlicht für die Treppe in den Keller zu bauen....bzw. da erstmal Strom hinzubringen.
Die Fortsetzung bekommt eine eigene Seite.