0a893d0684
Die vier abgestuften Helligkeiten des alten MSP430-Programms (5/15/50/100 %)
entfallen. Fuer die Sternwarte genuegt der Wechsel Tag/Nacht: unterhalb der
Schwelle laeuft die Anzeige mit dunkel_prozent, oberhalb mit hell_prozent.
Die Werte stehen nicht mehr im Code, sondern in settings.json auf dem Geraet --
Vorbereitung fuer die spaetere MQTT-Anbindung:
settings.load() # mit Vorgaben aufgefuellt
settings.update({"hell_prozent": 60}) # aendern und speichern
Vorgaben: dunkel 5 %, hell 50 %, Schwelle 1800, Hysterese 150. Die Schwelle liegt
mit Abstand zwischen den gemessenen Lagen (abgedeckt 0, Raumlicht 2453).
Beibehalten, weil die Messung vom 27.07. sie verlangt: der gleitende Mittelwert
und eine Hysterese um die Schwelle. Der ADC rauscht mit +/-32 (nach Mittelung,
1 Sigma) -- ohne Hysterese wuerde die Anzeige am Umschaltpunkt springen.
settings.py prueft jeden Wert beim Laden UND beim Schreiben auf Typ und Bereich.
Das ist der eigentliche Zweck: Mit MQTT kommen die Werte von aussen, und ein
Helligkeitswert von 500 % oder eine Schwelle von -1 wuerde die Anzeige sonst
unbrauchbar machen. Eine fehlende oder beschaedigte Datei faellt auf die Vorgaben
zurueck, ein einzelner kaputter Wert verwirft nur diesen -- ein Geraet in der
Sternwarte soll sich nicht an seiner Konfigurationsdatei aufhaengen.
settings.json wird von deploy.sh bewusst NICHT mitkopiert und steht in
.gitignore: Es ist Laufzeitzustand, kein Quellcode. Sonst waeren die
eingestellten Werte nach jedem Deployen weg.
Am Geraet bestaetigt: schreiben, wiederlesen, Controller uebernimmt die Werte,
beide Helligkeiten auf der Anzeige sichtbar. 119 Tests gruen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
134 lines
4.8 KiB
Python
134 lines
4.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Tests fuer die zur Laufzeit aenderbaren Einstellungen (settings.json).
|
|
|
|
python3 -m unittest -v test_settings
|
|
|
|
Schwerpunkt ist die Pruefung der Werte: Sobald MQTT dazukommt, kommen sie von
|
|
aussen. Ein Helligkeitswert von 500 % oder eine kaputte Datei darf die Anzeige
|
|
nicht lahmlegen.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import unittest
|
|
|
|
import settings
|
|
|
|
|
|
class Tempdatei(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
self.pfad = "test_settings_tmp.json"
|
|
self._weg()
|
|
|
|
def tearDown(self):
|
|
self._weg()
|
|
|
|
def _weg(self):
|
|
try:
|
|
os.remove(self.pfad)
|
|
except OSError:
|
|
pass
|
|
|
|
def _schreibe_roh(self, inhalt):
|
|
with open(self.pfad, "w") as f:
|
|
f.write(inhalt)
|
|
|
|
|
|
class TestLaden(Tempdatei):
|
|
|
|
def test_ohne_datei_gelten_die_vorgaben(self):
|
|
self.assertEqual(settings.load(self.pfad), settings.DEFAULTS)
|
|
|
|
def test_fehlende_werte_werden_ergaenzt(self):
|
|
self._schreibe_roh(json.dumps({"schwelle": 1234}))
|
|
w = settings.load(self.pfad)
|
|
self.assertEqual(w["schwelle"], 1234)
|
|
self.assertEqual(w["hell_prozent"], settings.DEFAULTS["hell_prozent"])
|
|
|
|
def test_kaputtes_json_faellt_auf_die_vorgaben_zurueck(self):
|
|
"""Ein Geraet in der Sternwarte darf daran nicht haengenbleiben."""
|
|
self._schreibe_roh("{das ist kein json")
|
|
self.assertEqual(settings.load(self.pfad), settings.DEFAULTS)
|
|
|
|
def test_json_das_kein_objekt_ist(self):
|
|
self._schreibe_roh("[1, 2, 3]")
|
|
self.assertEqual(settings.load(self.pfad), settings.DEFAULTS)
|
|
|
|
def test_einzelner_unbrauchbarer_wert_verwirft_nur_diesen(self):
|
|
self._schreibe_roh(json.dumps({"schwelle": 99999, "hell_prozent": 42}))
|
|
meldungen = []
|
|
w = settings.load(self.pfad, log=meldungen.append)
|
|
self.assertEqual(w["schwelle"], settings.DEFAULTS["schwelle"]) # verworfen
|
|
self.assertEqual(w["hell_prozent"], 42) # uebernommen
|
|
self.assertTrue(any("schwelle" in m for m in meldungen))
|
|
|
|
def test_unbekannter_schluessel_wird_ignoriert(self):
|
|
self._schreibe_roh(json.dumps({"voellig_unbekannt": 1}))
|
|
w = settings.load(self.pfad)
|
|
self.assertEqual(w, settings.DEFAULTS)
|
|
self.assertNotIn("voellig_unbekannt", w)
|
|
|
|
|
|
class TestSpeichern(Tempdatei):
|
|
|
|
def test_speichern_und_wieder_lesen(self):
|
|
settings.save({"schwelle": 2000, "dunkel_prozent": 3}, self.pfad)
|
|
w = settings.load(self.pfad)
|
|
self.assertEqual(w["schwelle"], 2000)
|
|
self.assertEqual(w["dunkel_prozent"], 3)
|
|
|
|
def test_gespeichert_wird_immer_vollstaendig(self):
|
|
settings.save({"schwelle": 2000}, self.pfad)
|
|
with open(self.pfad) as f:
|
|
roh = json.load(f)
|
|
self.assertEqual(set(roh), set(settings.DEFAULTS))
|
|
|
|
def test_update_aendert_nur_das_angegebene(self):
|
|
settings.save({"schwelle": 1000, "hell_prozent": 30}, self.pfad)
|
|
settings.update({"hell_prozent": 70}, self.pfad)
|
|
w = settings.load(self.pfad)
|
|
self.assertEqual(w["hell_prozent"], 70)
|
|
self.assertEqual(w["schwelle"], 1000) # unveraendert
|
|
|
|
def test_ungueltiges_update_laesst_die_datei_unberuehrt(self):
|
|
settings.save({"schwelle": 1000}, self.pfad)
|
|
with self.assertRaises(settings.SettingsError):
|
|
settings.update({"hell_prozent": 500}, self.pfad)
|
|
self.assertEqual(settings.load(self.pfad)["schwelle"], 1000)
|
|
|
|
|
|
class TestPruefung(unittest.TestCase):
|
|
"""Die Grenzen, an denen spaeter MQTT-Eingaben haengenbleiben sollen."""
|
|
|
|
def test_prozent_ueber_100_wird_abgelehnt(self):
|
|
with self.assertRaises(settings.SettingsError):
|
|
settings.save({"hell_prozent": 101}, "/dev/null")
|
|
|
|
def test_negative_werte_werden_abgelehnt(self):
|
|
with self.assertRaises(settings.SettingsError):
|
|
settings.save({"schwelle": -1}, "/dev/null")
|
|
|
|
def test_schwelle_ueber_adc_bereich_wird_abgelehnt(self):
|
|
with self.assertRaises(settings.SettingsError):
|
|
settings.save({"schwelle": 4096}, "/dev/null")
|
|
|
|
def test_unbekannter_name_wird_abgelehnt(self):
|
|
with self.assertRaises(settings.SettingsError):
|
|
settings.save({"gibtsnicht": 1}, "/dev/null")
|
|
|
|
def test_nichtganzzahlige_werte_werden_abgelehnt(self):
|
|
for wert in (1.5, "50", None, True):
|
|
with self.assertRaises(settings.SettingsError):
|
|
settings.save({"hell_prozent": wert}, "/dev/null")
|
|
|
|
def test_die_raender_sind_erlaubt(self):
|
|
geprueft = settings._pruefe({"hell_prozent": 100, "dunkel_prozent": 0,
|
|
"schwelle": 4095, "hysterese": 0})
|
|
self.assertEqual(geprueft["hell_prozent"], 100)
|
|
self.assertEqual(geprueft["schwelle"], 4095)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(verbosity=2)
|