DevelopmentIntroduction: Unterschied zwischen den Versionen
Yfhem (Diskussion | Beiträge) K (→Application Lifecycle: Improved list.) |
|||
Zeile 8: | Zeile 8: | ||
# Application variables are initialised | # Application variables are initialised | ||
# The valid application commands are loaded into a structure (%cmds) with the corresponding function name to call | # The valid application commands are loaded into a structure (%cmds) with the corresponding function name to call | ||
# If the application has been called as a FHEM client (eg perl fhem.pl 127.0.0.1:7072 commandToExecute) | # Do the job, either act as client or server. One of the following applies: | ||
## Connect to the FHEM server | ## If the application has been called as a FHEM client (eg perl fhem.pl 127.0.0.1:7072 commandToExecute) | ||
## Execute the command | ### Connect to the FHEM server | ||
## Exit the program | ### Execute the command | ||
### Exit the program | |||
# Execute each of the commands listed in the configuration file to initialise the server (see the CommandInclude and then the AnalyzeCommandChain methods) | ## Otherwise (the application has been started as a server) | ||
# Execute each of the commands in the state file if configured to restore the devices to the last state recorded when the server last ran | ### Execute each of the commands listed in the configuration file to initialise the server (see the CommandInclude and then the AnalyzeCommandChain methods) | ||
# Start the main application loop | ### Execute each of the commands in the state file if configured to restore the devices to the last state recorded when the server last ran | ||
### Start the main application loop | |||
== Main Application Loop == | == Main Application Loop == | ||
The following code is repeated until the application ends: | The following code is repeated until the application ends: |
Version vom 29. Oktober 2013, 12:42 Uhr
Developer's Introduction to FHEM
Introduction
This page is intended to give an introduction to the FHEM application from a developer's perspective. If you're interested in extending, modifying or reusing the FHEM code, then hopefully you will find this a useful document. Note that this document is a work in progress! I myself at the time of writing this have only a few hours of experience under my belt, but I'm documenting things I learn as I learn them.
Application Lifecycle
When you first launch the FHEM server, the following activities take place:
- Application variables are initialised
- The valid application commands are loaded into a structure (%cmds) with the corresponding function name to call
- Do the job, either act as client or server. One of the following applies:
- If the application has been called as a FHEM client (eg perl fhem.pl 127.0.0.1:7072 commandToExecute)
- Connect to the FHEM server
- Execute the command
- Exit the program
- Otherwise (the application has been started as a server)
- Execute each of the commands listed in the configuration file to initialise the server (see the CommandInclude and then the AnalyzeCommandChain methods)
- Execute each of the commands in the state file if configured to restore the devices to the last state recorded when the server last ran
- Start the main application loop
- If the application has been called as a FHEM client (eg perl fhem.pl 127.0.0.1:7072 commandToExecute)
Main Application Loop
The following code is repeated until the application ends:
- For each input device (eg FHZ1000 / FHZ1300 / CUL):
- Use that device module's Ready and Read functions to read data from the device
- For CUL devices, the data is read and parsed at this point
- For FHZ devices, the FHZ_CheckCRC method is used to validate the received data
- Call the Dispatch method in FHEM.pl to pass the message onto the correct device and corresponding module (Parse function)
- Read data from the client using sysread
- Pass the received input into the AnalyzeInput method to execute the command
Configuration and State Files
Note that these are just lists of commands to execute in a text file! So anything in these files will be interpreted by FHEM in the exact same way if a user keys the commands manually into a client application, eg a telnet connection.
Readings
The following mechanism is recommended for updating readings. It saves lines of codes and automatically makes your module honor the event-on-update-reading and event-on-change-reading attributes.
Before you start updating readings, write (in case $hash = $defs{<device>})
readingsBeginUpdate($hash);
For every reading you update, write
readingsBulkUpdate($hash,$reading,$value);
Terminate with
readingsEndUpdate($hash, $dotrigger);
The $dotrigger parameter should be 0 for updates initiated by fhem message dispatcher as the dispatcher already calls DoTrigger on its behalf. $dotrigger should be 1 for updates initiated by internal timers, e.g. for polling devices.
As a shorthand notation for updating just one reading write
readingsSingleUpdate($hash,$reading,$value,$dotrigger);
which is the same as
readingsBeginUpdate($hash); readingsBulkUpdate($hash,$reading,$value); readingsEndUpdate($hash, $dotrigger);
STATE
Vorschlag zur Umsetzung, diskutiert hier.
In den DevelopmentGuidelines, Kapselung, Standardisierung der Vorgehensweise.
Die Funktion readingsEndUpdateaktualisiert $hash->{STATE} grundsätzlich immer bei jedem Aufruf nach folgendem Algorithmus:
Falls $sr= $attr{$name}{stateReading} gesetzt ist:
Fall 1: wenn $sr =~ "^{.*}$" dann eval "\$hash->{STATE} = $sr"; Fall 2: sonst $hash->{STATE}= $hash->{READINGS}{$sr}{VAL}
sonst
Falls es $hash->{READINGS}{state} gibt, $hash->{STATE}= $hash->{READINGS}{state}{VAL}
sonst
Tue nichts (das Modul hat sich gekuemmert).
Ausserdem wird
ReplaceEventMap()
losgelassen, um die EventMaps des Anwenders auch im STATE zur Anwendung zu bringen.
Aus DoTriggerwerden
$defs{$dev}{STATE} = ReplaceEventMap($dev, $defs{$dev}{STATE}, 1);
und
# STATE && {READINGS}{state} should be the same my $r = $defs{$dev}{READINGS}; $r->{state}{VAL} = $defs{$dev}{STATE} if($r && $r->{state});
entfernt.
Global Attributes
In fhem.pl existiert ein
my $AttrList = "room comment alias ...";
Weiterhin kann jedes Modul im Initialize mit addToAttrList eigene Attribute zu global userattr hinzufuegen.