DevelopmentGuidelines: Unterschied zwischen den Versionen
Yfhem (Diskussion | Beiträge) K (→Bezeichnungen: Remove dot in source.) |
|||
Zeile 70: | Zeile 70: | ||
Beim Multiprocessing wird der fhem-Prozess geforkt, wenn ein Reading vom Geraet eingelesen werden soll. Der Vaterprozess wird sofort fortgesetzt und erledigt weitere Aufgaben. Der Kindprozess holt die Readings vom Geraet, liefert sie an den Vaterprozess und verendet. | Beim Multiprocessing wird der fhem-Prozess geforkt, wenn ein Reading vom Geraet eingelesen werden soll. Der Vaterprozess wird sofort fortgesetzt und erledigt weitere Aufgaben. Der Kindprozess holt die Readings vom Geraet, liefert sie an den Vaterprozess und verendet. | ||
Die Lieferung an den Vaterprozess erfolgt durch eine Verbindung zu fhem via | Die Lieferung des Resultats an den Vaterprozess erfolgt durch eine Loopback Verbindung zu fhem via localhost. | ||
Dieser Mechanismus wurde durch Rudolf König in ein entsprechendes Modul verpackt, so dass jedes andere FHEM-Modul diese Möglichkeiten direkt nutzen kann. Eine nähere Erklärung sowie eine Anleitung dazu findet man in dem Artikel → [[Blocking Call]] | |||
'''Fragen''': | '''Fragen''': | ||
* Soll es diesen Mechanismus nur passive Readings geben oder gibt es Anwendungsfaelle fuer aktive Readings? | * Soll es diesen Mechanismus nur passive Readings geben oder gibt es Anwendungsfaelle fuer aktive Readings? | ||
Zeile 135: | Zeile 84: | ||
* Wird praktisch auf keiner kleinen Plattform unterstuetzt. | * Wird praktisch auf keiner kleinen Plattform unterstuetzt. | ||
* Negative Erfahrungen (z.B. Probleme bei vielen 3rd-party-Komponenten) | * Negative Erfahrungen (z.B. Probleme bei vielen 3rd-party-Komponenten) | ||
* Kaum Programmiererfahrung mit Multithreading in Perl. | * Kaum Programmiererfahrung mit Multithreading in Perl. | ||
==Verabschiedete Richtlinien== | ==Verabschiedete Richtlinien== |
Version vom 31. Dezember 2013, 02:37 Uhr
Wichtiger Hinweis: Diese Seite enthält die Ideen der fhem-Entwickler, wie fhem in einer künftigen Version funktionieren soll. Es beschreibt nicht den Zustand der aktuellen Umsetzung in den Release- oder den SVN-Versionen.
Definitionen
TODO: Rudis kanonische Begriffe verwenden!
Allgemeines
Die Version von fhem, in der diese Guidelines umgesetzt werden sollen, wird mit fhem-NEU bezeichnet. Mit fhem 4.x wird die aktuelle Architektur bezeichnet, die auch fuer fhem 5.x zutrifft.
Readings
Ein Reading (Ablesewert) ist jeglicher Wert, Zustand, etc., der von einem Geraet ausgelesen werden kann. Beispiele dafuer sind Messtemperatur, Luftfeuchtigkeit, Schaltzustand (an/aus), Firmwareversion, Empfangsstaerke.
I/O-Devices und Clients
Um Readings durch fhem verarbeiten zu koennen, muessen die Daten erst ueber ein I/O-Device in den Rechner kommen. Beispiele: FHZ1300, CUL, CM11, M232.
Ein I/O-Device ist ueber einen Port (Beispiel fuer Unix: /dev/ttyS0) oder einen Socket ansprechbar.
Ein I/O-Device kann selbst ein Geraet sein, das Readings liefert (Beispiel: SCIVT, sowie die meisten anderen Schnittstellengeraete, wenn man die Geraeteversion oder die Uptime mit zu den Readings zaehlt), oder die Readings von anderen Geraeten (Clients) weiterleiten (Beispiel: FHZ1300).
Requests for Proposal
Aktualisierung der Readings
Aktive und passive Readings
Es sind zwei Arten von Readings zu unterscheiden:
- Readings, die vom Geraet aktiv mitgeteilt werden, entweder ad-hoc oder in regelmäßigen Zeitabständen (aktive Readings). Beispiele: measuredTemp bei FHT80B, wind bei KS300
- Readings, nach denen fhem die Geräte fragen muss (passive Readings). Beispiele: energyDay bei EM1010PC, counter bei M232, temperature bei OWTEMP
Dasselbe Geraet kann sowohl aktive als auch passive Readings beinhalten. Bei Geraeten mit aktiven Readings sind passive Readings meist Informationen wie Versionsnummer oder Uptime (CUL, CM11).
Geraete, die mehrere verschiedene Readings haben, senden diese haeufig im Batch an fhem (Beispiel: FHT80b, KS300).
Mechanismus fuer aktive Readings
TODO: Mechanismus mit ParseFn, GetFn, Match usw. beschreiben (wie in fhem 4.x)!
Mechanismus fuer passive Readings
Fuer passive Geräte gibt es eine Polling-Infrastruktur.
Status Quo in fhem 4.x:
In der Routine DEVICE_Define wird ein interner Timer gestartet, der die Updatefunktion aufruft. INTERVAL ist die Periode in Sekunden.
sub DEVICE_Define($$) { ... InternalTimer(gettimeofday()+$hash->{INTERVAL}, "DEVICE_GetUpdate", $hash, 0); ... }
In der Routine DEVICE_GetUpdate werden dann die Readings vom Gerät geholt und der Timer wird mit dem gleichen Befehl erneut gestartet.
sub DEVICE_GetUpdate($$) { ... # start internal timer; do it at the beginning to achieve equal intervals no matter how long it takes to gather data InternalTimer(gettimeofday()+$hash->{INTERVAL}, "DEVICE_GetUpdate", $hash, 1); # gather data ... }
Der letzte Paramater 0 oder 1 ist waitIfInitNotDone.
Fragen:
- Kann/soll dieses Verfahren in einem Modul gekapselt werden? Geraete melden sich dann an der Polling-Infrastruktur an. Wenn ja, wie?
- Wie wird waitIfInitNotDone korrekt eingesetzt?
Mechanismus fuer langsame Readings
Problemstellung: Laengere Verarbeitungsprozesse in einzelnen Modulen (z.B. aufgrund von Netzwerklatenzen oder toten Geraeten) halten fhem komplett an und verhindern die Verarbeitung von Events.
Loesung: Multiprocessing
Beim Multiprocessing wird der fhem-Prozess geforkt, wenn ein Reading vom Geraet eingelesen werden soll. Der Vaterprozess wird sofort fortgesetzt und erledigt weitere Aufgaben. Der Kindprozess holt die Readings vom Geraet, liefert sie an den Vaterprozess und verendet.
Die Lieferung des Resultats an den Vaterprozess erfolgt durch eine Loopback Verbindung zu fhem via localhost.
Dieser Mechanismus wurde durch Rudolf König in ein entsprechendes Modul verpackt, so dass jedes andere FHEM-Modul diese Möglichkeiten direkt nutzen kann. Eine nähere Erklärung sowie eine Anleitung dazu findet man in dem Artikel → Blocking Call
Fragen:
- Soll es diesen Mechanismus nur passive Readings geben oder gibt es Anwendungsfaelle fuer aktive Readings?
Verworfene Alternative: Multithreading
Argumente gegen Multithreading:
- Wird praktisch auf keiner kleinen Plattform unterstuetzt.
- Negative Erfahrungen (z.B. Probleme bei vielen 3rd-party-Komponenten)
- Kaum Programmiererfahrung mit Multithreading in Perl.
Verabschiedete Richtlinien
Zeichensatz
Alle nach aussen sichtbaren Werte sind in der Zeichenkodierung ASCII (Codes 32..127). Dies vermeidet Konvertierungsprobleme bei der Bearbeitung des Quellkodes, bei der Ausgabe durch Perl, beim Transport in Internet-Protokollen und bei der Darstellung im Frontend/GUI.
Klassifizierung der Attribute
Die Attribute eines Moduls werden in logische Klassen (Rubriken) eingeteilt.
Sinn und Zweck
Die Rubriken helfen...
- zu sortieren, welche Attribute bei (xml)list gezeigt werden und welche nicht,
- zu definieren, welche Werte per save in die Sicherung kommen und welche nicht,
- zu vereinbaren, welche Änderungen ein notify auslösen und welche nicht,
- zu definieren, wie ein Attribut im $hash->{} abgelegt wird (in $hash->{}, $hash->{READINGS}, $hash->{INTERNALS}, ...),
- zu gliedern, welche Namenskonventionen jeweils für Attribute verwendet werden (Kleinbuchstaben, Großbuchstaben, CamelCaps, ...),
- abzugrenzen, wo der Entwickler sich an Vorgaben halten muß (z.B. bei System Internals) und wo er frei ist, Attribute zu erfinden oder wegzulassen, und
- festzulegen, wo bzgl. der Inhalte Standards notwendig sind und wo nicht (z.B. bei "Logical Readings", wenn diese im GUI angezeigt werden sollten).
Logische Rubriken
Die folgenden Rubriken stellen eine sehr feine Einteilung dar:
- System Internals: werden vom Framework (fhem.pl) benoetigt/verwendet/erkannt, z.B. NAME, NR, CHANGED
- Device Readings: Rohdaten, die vom physischen Geraet ausgelesen werden (nicht interpretiert), z.B. rain_raw (Wippenschlaege des Regensensors) in KS300
- Hilfsvariablen: z.B. rain_raw_adj (rain_raw, jedoch bereinigt um die bei einigen KS300 auftretenden erratischen Spruenge) in KS300, Zwischenergebnisse von Daten/Werten, welche zur Mittelwertberechnung benoetigt werden
- Logical Readings: ausgewertete Messdaten und Zustaende, z.B. Temperatur, Niederschlag (nicht als Wippenschlaege sondern in l/qm)
- Derived Readings: aus den Messdaten abgeleitete Werte, z.B. durchschnittliche Temperatur der laufenden Woche, Niederschlagsmenge des Tages
- Physical Device Parameter: z.B. Modell oder Housecode und Unitcode bei X10 oder die Sensornummer beim BS (brightness sensor)
- Logical Device Parameter: statische Werte, die als Grundlage für Berechnungen genutzt werden, z.B. Korrekturfaktoren bei den Energiemessgeraeten, die Tankgeometrie beim USF1000
- Messages: alle Nachrichten, die das Gerät betreffen, z.B. "AVG_Month erfolgreich berechnet", "Script XYZ am xx.xx.xx gestartet", LastIODEV, LastRAWMSG
- Trigger: wenn Trigger direkt am Geraet hinterlegt werden, muessen nicht mehr alle Notifies durchsucht werden, sondern es kann das Modul direkt ermitteln, ob ein Notify ausgeloest wird.
Ablage im Programm
Programmtechnisch werden die Attribute eines Moduls so in Behaeltern abgelegt, dass folgende Kriterien erfuellt sind:
- Die Aufteilung ist moeglichst einfach/minimalistisch.
- Anhand des Behaelters laesst sich entscheiden,
- ob die Werte der darin enthaltene Attribute ueber das Programmende hinaus gespeichert oder nicht gespeichert werden,
- welchen Anzeigestandards oder Programmierstandards die darin enthaltenen Attribute entsprechen, und
- ob es sich um fhem-interne Attribute, Readings oder Hilfsvariablen handelt.
Es gibt folgende Behaelter:
readings
- Logische Rubrik: Device Reading, Logical Reading, Derived Reading
- Wird gespeichert
- Alle vom Geraet gelieferten bzw. berechneten Werte, die den Endanwender interessieren. Keine Rohdaten vom Geraet, die erst interpretiert werden muessen (Wippenschlaege beim Regensensor).
- Alle Daten haben einen Wert und ein Zeitstempel
- Beispiele:
$defs{Lampe}{readings}{switchedTo}{value} = "on"; $defs{Lampe}{readings}{switchedTo}{time} = "2010-03-29 23:32:26" $defs{FHToben}{readings}{measuredTemp}{value} = "23"; $defs{FHToben}{readings}{switchedTo}{time} = "2010-03-29 21:58:36"
helper
- Logische Rubrik: Hilfsvariable, Device Reading
- Wird gespeichert
- Alle Werte, die fuer den Endanwender nicht direkt Sinn machen, aber vom Modul fuer unterschiedliche Zwecke benoetigt werden. Kann auch rohe Readings enthalten.
- Beispiele:
$defs{ks300}{helper}{cumMonth} = "23 T: 131.4 H: 816 W: 775.1 R: -651.1" $defs{emwz}{helper}{basis} = "4776493"
fhem
- Logische Rubrik: System Internals, Physical Device Parameter, Logical Device Parameter
- Wird nicht gespeichert
- Alle Geraete-Werte, die nicht gespeichert werden muessen, weil entweder berechnet, oder aus der Definition hervorgehen.
- Beispiele
$defs{emwz}{fhem}{def} = "1 75 900" $defs{emwz}{fhem}{lastIODev} = "CUL"
Verworfener Behaelter STATE
- Logische Rubrik: Device Reading, Logical Reading, Derived Reading
- Wird gespeichert
- Kurze(!) Zusammenfassung der wichtigsten Information des Geraetes. Was man in einer Uebersicht ueber die Geraete sehen moechte, z.B. eine Warnung oder die aktuelle Temperatur beim FHT80 oder der Zeitpunkt der letzten Aktivierung beim PIRI. Falls es sowas nicht gibt, dann einheitlich "defined". GGf. ueber Attribute am Modul steuerbar. Eigentlich ist es kein Behaelter im ueblichen Sinne, da es keine Untereinheiten hat.
Der Behaelter wurde verworfen, weil er redundant ist, an sich gar kein Behaelter, und einfacher und flexibler ueber einen Verweis auf das Reading realisiert werden kann, der per Default angezeigt werden soll.
Status
Kurze Zusammenfassung der wichtigsten Information des Geraetes. Was man in einer Uebersicht ueber die Geraete sehen moechte, z.B. eine Warnung oder die aktuelle Temperatur beim FHT80 oder der Zeitpunkt der letzten Aktivierung beim PIRI. Falls es sowas nicht gibt, dann einheitlich "defined". Modulseitig gibt es einen Default, der auf das relevante Reading verweist. Dieser ist ueber das Attribut defaultReading am individuellen Geraet steuerbar.
Beispiel: Definition in der Konfigurationsdatei: attr myDevice defaultReading measuredTemp Verwendung im Code:
$defs{myDevice}{readings}{$attr{defaultReading}}
Die logischen Rubriken Messages und Trigger wurden noch nicht diskutiert.
Bezeichnungen
Verwendung von lowerCamelCaps fuer alle vom Modul nach aussen sichtbaren Bezeichner: a) die Bezeichnungen der Behaelter fuer Readings, Fhem und Helper und der Untereintraege, b) die Bezeichnungen der Readings, c) die Bezeichnungen der Attribute.
Beispiel:
$defs{myFHT}{readings}{measuredTemp}{time}
Readings
Standardisierung der Readings
Die Readings werden standardisiert, indem Geraeteklassen gebildet werden wie in DevelopmentInterfaces beschrieben. Die Definition der Interfaces ist explizit nicht Gegenstand dieser Entscheidungsvorlage und wird weiterentwickelt und angepasst, wie es sich bei der Entwicklung von fhem-NEU ergibt. Struktur im Code
Zu jedem Reading gibt es die folgenden Unterbehaelter:
- value: Wert der Messgroesse
- time: Zeitpunkt, zu dem der Wert ermittelt wurde
Beispiel:
$defs{myFHT}{readings}{measuredTemp}{time}= timestamp; $defs{myFHT}{readings}{measuredTemp}{value}= 23.5;
Readings enthalten grundsaetzlich genau einen Wert und diesen ohne Einheit.
Einheitendarstellung
Die verwendete Einheit fuer ein Reading ergibt sich aus der Interfacespezifikation.
Beispiel: Gerät ist ein Thermometer => es gibt ein Reading "temperature" und dessen Einheit ist immer °C oder Celsius
Verworfene Alternative:
- Einheit ergibt sich aus der Dokumentation
- Einheit ergibt sich aus einem expliziten Untereintrag $defs{deviceName}{readings}{theReading}{unit}="°C"
- Einheit ergibt sich aus Festlegung gemaess "FHEM-Standard", z.B. immer SI-Einheiten, Temperaturen in Celsius, etc.
Zeitdarstellung in fhem
Zeiten werden im Programm grundsaetzlich immer maschinenlesbar abgelegt, also sowohl in $defs{deviceName}{readings}{time} als auch z.B. bei der Speicherung des Zeitpunkts der Ausfuehrung des naechsten at-Kommandos.
Es gibt uebergreifende Hilfsfunktionen, die die maschinenlesbare in eine menschenlesbare Darstellung umwandeln.
Argumente fuer maschinenlesbar:
- vereinfacht Datumsarithmetik, z.B. die Berechnung der Zeitdauer zwischen zwei Ereignissen
- kann vom Frontend in die regionale Darstellung des Anwenders uebersetzt werden
- hat keine Probleme mit doppelt auftretenden Zeitpunkten bei der Umstellung von Sommer- auf Winterzeit
Folgende Zeitdarstellungen werden ausschliesslich verwendet:
A. Zahl der Sekunden seit der Unix-Epoche (was time liefert); auch wenn time eine Ganzzahl liefert, muss der Verwender damit rechnen, eine Gleitkommazahl vorzufinden. Das ist z.B. dann der Fall, wenn fuer die Zeibestimmung hoeheraufloesende Funktionen (z.B. Time::HiRes) zum Einsatz kamen und Sekundenbruchteile mitgespeichert wurden.
Hinweis zu potentiellen Problemen:
- Ab perl 5.12 ist das Jahr-2038-Problem in Perl beseitigt.
- Ab MacOS X liefert time auch auf Macs die Zahl der Sekunden seit der Unix-Epoche (statt seit Anfang 1904)
B. ISO8601 mit optionaler Zeitzonenangabe, wobei bei fehlender Zeitzone die lokale Zeitzone des fhem-Servers gilt
Die Zeitdarstellungen werden wie folgt verwendet:
- Zur Programmlaufzeit in Variablen immer A
- In Konfigurationsdateien (fhem.conf, fhem.save) immer B
- In Logs, die fuer den Menschen bestimmt sind, B
- In Logs, die fuer die Maschine bestimmt sind, also z.B. bei Weiterverarbeitung in einem GUI, A
- In Listen (list, xmllist friendly), die fuer den Menschen bestimmt sind, B
- In Listen (xmllist), die fuer die Maschine bestimmt sind, also z.B. bei Weiterverarbeitung in einem GUI, A
Die Unterscheidung bei den Logs ist noch zu diskutieren.
Hinweise zu gnuplot:
set timefmt '%Y-%m-%dT%H:%M:%S'
(ISO8601) funktioniert, und zwar unabhaengig davon, ob die optionale Zeitzonenangabe anhaengt oder nicht (getestet mit Gnuplot v4.2 pl3). Fuer die Sekunden seit der Unix-Epoche:
set timefmt '%s'
(nicht getestet).
Allgemeine Dokumentation
Events, Filter, Notify
Event
Ein Event tritt ein, wenn ein oder mehrere Readings eines Geraetes aktualisiert werden, weil z.B. ein Datagramm empfangen oder zeitgesteuert Werte eingelesen wurden. Es wird durch drei Angaben
(device, timestamp, { reading1, ..., readingN } )
beschrieben:
- das Geraet device
- der Zeitpunkt der Aktualisierung timestamp
- die Menge der N>= 1 geaenderten Readings reading1, .. readingN
Wenn N> 1, dann handelt es sich um ein Sammelevent, wie es z.B. von KS300 generiert wird.
Filter
Ein Filter filtert Events. Er hat die Form
deviceNamePattern
bzw.
deviceNamePattern:readingNamePattern
Ein Filter passt auf ein Event, wenn deviceNamePattern den Namen des device matcht und, sofern vorhanden, readingNamePattern mindestens irgendeinen Namen von reading1 bis readingN matcht.
Mechanismus
0. Fuer das Geraet device namens deviceName wird ein Datagramm empfangen oder es werden zeitgesteuert Werte eingelesen.
1. Die Readings werden aktualisiert. Fuer X= 1..N:
$defs{deviceName}{readings}{readingX}{value}= valueX; $defs{deviceName}{readings}{readingX}{time}= timestamp;
2. Das Event wird erstellt und an DoTrigger uebergeben.
3. DoTrigger informiert zunaechst alle Clients mit inform-Wunsch.
4. Das Event wird sodann von DoTrigger nacheinander an alle NotifyFn in der alphabetischen Reihenfolge der Geraetenamen gereicht. Darunter auch jene von Logs.
5. Wenn der Filter des Logs auf das Event passt, wird ein Log-Eintrag der Form
timestamp deviceName reading1: value1 reading2: value2 ... readingN: valueN
erzeugt.
Zurueckgestellte Entscheidungen
Attribute vs. Internals
Die Unterscheidung zwischen Attributen und Internals ist nicht eindeutig. Manche define-Parameter sind optional, und man kann define-Parameter mit "modify" aendern. Insofern koennte man theoretisch einen der beiden Verfahren (modify vs. attribute) abloesen.
1. Idee: define-Parameter duerfen nachtraeglich nicht geaendert werden, auch wenn es sich um optionale Parameter handelt => nicht-modifizierbare Internals
Pros:
- define-Parameter sind elementar fuer den Betrieb des Geraetes und koennen nicht sinnvoll zur Programmlaufzeit geaendert werden (z.B. Hauskode bei X10, FHTId bei FHT80b)
- Aus den define-Parametern werden bei der Initialisierung des Geraets weitere Helper und Internals abgeleitet und gespeichert. Eine nachtraegliche Aenderung zieht Aenderungen der Helper und Internals nach sich mit ggf. schwer durchschaubaren Nebeneffekten (z.B. corr1..corr4 bei EM, rainadjustment bei KS300). Auch die Logs aendern sich nicht nachtraeglich.
Contras:
- Man will nicht ein Geraet loeschen und neu anlegen, wenn es ausgetauscht wird.
- modify sollte bleiben, weil es nuetzlich ist.
2. Idee: Attribute enthalten Werte, die ohne Nebeneffekte zur Laufzeit geaendert werden koennen, weil sie z.B. ad-hoc ausgewertet werden.
- follow-on-for-timer
- retrycount
- lazy
3. Idee: Attribute beinhalten geraeteunabhaengige Meta-Informationen:
- room
- defaultReading
Contras:
- Nach 2. und 3. muesste
attr my_at disabled
doch zu Definition gehoeren. Und "skip_next" auch.
Spezialitaeten
- beim FS20 bleibt alles, wie es ist, also model als Attribut, was Auswirkung auf die moeglichen set Befehle hat.
- 1wire setzt nach define das model Attribut, laesst aber eine Aenderung nicht zu, oder wenn doch, dann muss sich dementsprechend verhalten, es macht ja evtl. Sinn es zu aendern. Was machbar ist, entscheidet der Modul-Author.
Damit ist "model" immer ein Attribut.
Fazit
Da es keine ueberzeugende Alternative zum Ist-Zustand in fhem 4.x gibt, wird b.a.w. nicht hierueber entschieden.
notify
Die Frage, ob der notify-Mechanismus, der weiter oben dokumentiert ist, aus Performancegruenden optimiert werden sollte, ist offen.
In fhem 4.x bekommt jedes Geraet mit NotifyFn jedes Event mit. Alternativ koennte sich ein Geraet als EventListener mit einem Filter bei fhem anmelden. Dann koennten die Events nur an die NotifyFn verteilt werden, fuer die es ein Match auf den Filter gaebe.
Der Punkt wurde zurueckgestellt, bis nachgewiesen ist, dass sich aus dieser Vorgehensweise relevante Auswirkungen auf die Systemlast ergeben.
Entscheidungen
- E1
- Es werden die Container fhem, readings und helper verwendet.
- E2
- Es wird ein Attribut defaultReading verwendet.
- E3
- Verwendung von lowerCamelCaps fuer a) die Bezeichnungen der Behaelter fuer Readings, Fhem und Helper und der Untereintraege, b) die Bezeichnungen der Readings, c) die Bezeichnungen der Attribute.
- E4
- Verwendung von value und time.
- E5
- Zeitdarstellung im Programm grundsaetzlich maschinenlesbar
- E6
- Zulaessige Zeitdarstellungen
- Sekunden seit der Unix-Epoche
- ISO8601 mit optionaler Zeitzonenangabe
ISO8601 mit _ statt T war nicht mehrheitsfaehig.
- E7
- Verwendung der Zeitdarstellungen
- E8
- Readings enthalten grundsaetzlich genau einen Wert und diesen ohne Einheit.
- E9
- Einheiten ergeben sich aus der Interfacespezifikation.
- E10
- Entscheidung fuer ASCII
- E11
- Die Readings werden standardisiert, indem Geraeteklassen gebildet werden wie in DevelopmentInterfaces beschrieben. Die Definition der Interfaces ist explizit nicht Gegenstand dieser Entscheidungsvorlage und wird weiterentwickelt und angepasst, wie es sich bei der Entwicklung von fhem-NEU ergibt.