LDR-Schwellen am realen Aufbau gemessen statt vom MSP430 uebernommen

Gemessen am XIAO ESP32-C3 mit dem LDR an GPIO2, je 200 Werte, Median
(Angaben nach raw_to_ldr, also in Zaehlrichtung "gross = hell"):

    abgedeckt      roh 4095 (ADC-Anschlag)  ->    0
    Raumlicht      roh 1642                 -> 2453
    angeleuchtet   roh  543                 -> 3552

Zwei Fehler in den alten Werten, die erst die Messung zeigt:

- Stufe 3 (100 %) war unerreichbar. Sie begann bei 3650, selbst eine Taschenlampe
  direkt auf dem Sensor kam nur auf 3552. Die Anzeige haette nie voll aufgedreht.
- Die Hysterese von 30 am untersten Uebergang lag unter dem Rauschen. Der Rohwert
  streut bei Raumlicht um +/-270, nach dem gleitenden Mittel bleiben rund +/-32
  (1 Sigma) -- die unterste Stufe haette geflattert.

Neu: Mitten 1200/2400/3200, Hysterese einheitlich 150. Die Aufteilung haelt den
5-%-Bereich bis 1200 (Nutzerwunsch "nachts laenger dunkel", schont die
Dunkeladaption der Beobachter). Die gestaffelten Hysteresen des alten Programms
entfallen -- die gemessene Streuung ist an allen Grenzen dieselbe.

Bekannte Grenzlage, in test_brightness festgehalten: Raumlicht (2453) liegt nur
53 Zaehler ueber HELL_HIGH und damit innerhalb der Hysterese, faellt also auf
Stufe 1 statt 2. Ob das so gewollt ist, entscheidet sich in der Sternwarte.

Am Geraet bestaetigt: Regelung laeuft stabil ohne Flattern, Abdecken schaltet
herunter, Freigeben wieder hoch, Helligkeitstelegramm wird quittiert. Die
Schwellen sind aber am Schreibtisch gemessen -- with_ldr bleibt deshalb auf
False, bis sie vor Ort bestaetigt sind. 101 Tests gruen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-27 16:21:08 +02:00
parent 4f7375add3
commit e8a5b5d5e3
4 changed files with 161 additions and 52 deletions
+66 -18
View File
@@ -3,8 +3,13 @@
python3 -m unittest -v test_brightness
Grenzen: Mitten (300, 2500, 3500) mit Hysterese (30, 150, 150)
-> hoch bei 330 / 2650 / 3650, runter bei 270 / 2350 / 3350.
Grenzen am Geraet gemessen (2026-07-27): Mitten (1200, 2400, 3200) mit
einheitlicher Hysterese 150 -> hoch bei 1350 / 2550 / 3350,
runter bei 1050 / 2250 / 3050.
Die Zahlen stehen bewusst ausgeschrieben statt aus brightness.* gerechnet:
So faellt eine versehentliche Aenderung der Schwellen im Test auf, statt
stillschweigend mitzuwandern.
"""
import unittest
@@ -19,32 +24,75 @@ class TestStufen(unittest.TestCase):
self.c = BrightnessController()
def test_erststart_schaltet_von_0_hoch(self):
self.assertEqual(self.c._next_level(329, None), 0)
self.assertEqual(self.c._next_level(330, None), 1)
self.assertEqual(self.c._next_level(2649, None), 1)
self.assertEqual(self.c._next_level(2650, None), 2)
self.assertEqual(self.c._next_level(3649, None), 2)
self.assertEqual(self.c._next_level(3650, None), 3) # 100 % erreichbar
self.assertEqual(self.c._next_level(1349, None), 0)
self.assertEqual(self.c._next_level(1350, None), 1)
self.assertEqual(self.c._next_level(2549, None), 1)
self.assertEqual(self.c._next_level(2550, None), 2)
self.assertEqual(self.c._next_level(3349, None), 2)
self.assertEqual(self.c._next_level(3350, None), 3) # 100 % erreichbar
def test_hysterese_von_stufe_1(self):
self.assertEqual(self.c._next_level(270, 1), 1)
self.assertEqual(self.c._next_level(269, 1), 0)
self.assertEqual(self.c._next_level(2649, 1), 1)
self.assertEqual(self.c._next_level(2650, 1), 2)
self.assertEqual(self.c._next_level(1050, 1), 1)
self.assertEqual(self.c._next_level(1049, 1), 0)
self.assertEqual(self.c._next_level(2549, 1), 1)
self.assertEqual(self.c._next_level(2550, 1), 2)
def test_hysterese_von_stufe_2(self):
self.assertEqual(self.c._next_level(2350, 2), 2)
self.assertEqual(self.c._next_level(2349, 2), 1)
self.assertEqual(self.c._next_level(3649, 2), 2)
self.assertEqual(self.c._next_level(3650, 2), 3)
self.assertEqual(self.c._next_level(2250, 2), 2)
self.assertEqual(self.c._next_level(2249, 2), 1)
self.assertEqual(self.c._next_level(3349, 2), 2)
self.assertEqual(self.c._next_level(3350, 2), 3)
def test_hysterese_von_stufe_3(self):
self.assertEqual(self.c._next_level(3350, 3), 3)
self.assertEqual(self.c._next_level(3349, 3), 2)
self.assertEqual(self.c._next_level(3050, 3), 3)
self.assertEqual(self.c._next_level(3049, 3), 2)
def test_prozente(self):
self.assertEqual(brightness.PERCENTS, (5, 15, 50, 100))
def test_gemessene_lagen_ergeben_die_gewollten_stufen(self):
"""Die am Geraet gemessenen Lichtlagen, in Stufen uebersetzt.
Das ist der eigentliche Zweck der Kalibrierung: abgedeckt muss auf die
dunkelste Stufe fallen, angeleuchtet auf die hellste. Beides ging mit
den alten MSP430-Schwellen daneben (100 % war unerreichbar).
"""
self.assertEqual(self.c._next_level(0, None), 0) # abgedeckt -> 5 %
self.assertEqual(self.c._next_level(3552, None), 3) # Lampe -> 100 %
def test_raumlicht_liegt_dicht_an_der_grenze(self):
"""Bekannte Grenzlage, absichtlich festgehalten.
Der gemessene Raumlichtwert 2453 liegt nur 53 Zaehler ueber HELL_HIGH
(2400) und damit unter der Hysterese: Hochgeschaltet wird erst ab 2550,
also bleibt Raumlicht auf Stufe 1 (15 %). Eine Stufengrenze so dicht an
einem realen Betriebspunkt ist keine gute Stelle -- welche Stufe dort
gewollt ist, entscheidet sich erst an den Lichtverhaeltnissen in der
Sternwarte. Bis dahin haelt dieser Test das Verhalten schriftlich fest,
damit es niemanden ueberrascht.
"""
self.assertEqual(self.c._next_level(2453, None), 1)
self.assertLess(abs(2453 - brightness.HELL_HIGH), brightness.HELL_HYST)
def test_hysterese_ueberdeckt_das_gemessene_rauschen(self):
"""Nach dem gleitenden Mittel bleiben rund 32 Zaehler Streuung (1 Sigma).
Die Hysterese muss deutlich darueber liegen, sonst springt die Stufe an
einer Grenze hin und her -- genau das waere mit den alten 30 passiert.
"""
self.assertGreaterEqual(brightness.HELL_HYST, 100)
def test_kein_stufensprung_bei_rauschen_um_eine_grenze(self):
"""Werte, die um eine Stufengrenze streuen, duerfen die Stufe halten."""
c = BrightnessController()
for _ in range(brightness.AVERAGE_WINDOW):
c.update(1200) # genau auf der Grenze einschwingen
stufe_vorher = c.level
for delta in (+60, -60, +55, -50, +45, -60, +60, -55):
stufe, _, changed = c.update(1200 + delta)
self.assertFalse(changed, "Rauschen um die Grenze hat umgeschaltet")
self.assertEqual(stufe, stufe_vorher)
class TestUpdate(unittest.TestCase):