DevelopmentIntroduction: Unterschied zwischen den Versionen

Aus FHEMWiki
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
</li><li> Otherwise (the application has been started as a server)
### 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
</li></ol>
### 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, 13: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:

  1. Application variables are initialised
  2. The valid application commands are loaded into a structure (%cmds) with the corresponding function name to call
  3. Do the job, either act as client or server. One of the following applies:
    1. If the application has been called as a FHEM client (eg perl fhem.pl 127.0.0.1:7072 commandToExecute)
      1. Connect to the FHEM server
      2. Execute the command
      3. Exit the program
    2. Otherwise (the application has been started as a server)
      1. Execute each of the commands listed in the configuration file to initialise the server (see the CommandInclude and then the AnalyzeCommandChain methods)
      2. 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
      3. Start the main application loop

Main Application Loop

The following code is repeated until the application ends:

  1. For each input device (eg FHZ1000 / FHZ1300 / CUL):
    1. Use that device module's Ready and Read functions to read data from the device
    2. For CUL devices, the data is read and parsed at this point
    3. For FHZ devices, the FHZ_CheckCRC method is used to validate the received data
    4. Call the Dispatch method in FHEM.pl to pass the message onto the correct device and corresponding module (Parse function)
  • $server->fileno() is used to check for and accept new connections to the server
  • For each connected client:
    1. Read data from the client using sysread
    2. 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.