DevelopmentIntroduction: Unterschied zwischen den Versionen

Aus FHEMWiki
(Die Seite wurde neu angelegt: „= Developer's Introduction to FHEM = == Introduction == This page is intended to give an introduction to the FHEM application from a developer's perspective. I…“)
 
 
(4 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt)
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:
Zeile 25: Zeile 26:
## For FHZ devices, the FHZ_CheckCRC method is used to validate the received data
## 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)
## Call the Dispatch method in FHEM.pl to pass the message onto the correct device and corresponding module (Parse function)
</li><li> $server-&gt;fileno() is used to check for and accept new connections to the server
$server-&gt;fileno() is used to check for and accept new connections to the server
</li><li> For each connected client:
For each connected client:
# Read data from the client using sysread
# Read data from the client using sysread
# Pass the received input into the AnalyzeInput method to execute the command
# Pass the received input into the AnalyzeInput method to execute the command
</li></ol>
 
== Configuration and State Files ==
== 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.
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.
Zeile 61: Zeile 62:




Die Funktion '''readingsEndUpdate'''aktualisiert $hash-&gt;{STATE} grundsätzlich immer bei jedem Aufruf nach folgendem Algorithmus:
Die Funktion '''readingsEndUpdate''' aktualisiert $hash-&gt;{STATE} grundsätzlich immer bei jedem Aufruf nach folgendem Algorithmus:


Falls $sr= $attr{$name}{stateReading} gesetzt ist:
Falls $sr= $attr{$name}{stateReading} gesetzt ist:
Zeile 79: Zeile 80:




Aus '''DoTrigger'''werden
Aus '''DoTrigger''' werden


  <nowiki>$defs{$dev}{STATE} = ReplaceEventMap($dev, $defs{$dev}{STATE}, 1);</nowiki>
  <nowiki>$defs{$dev}{STATE} = ReplaceEventMap($dev, $defs{$dev}{STATE}, 1);</nowiki>
Zeile 88: Zeile 89:
   $r-&gt;{state}{VAL} = $defs{$dev}{STATE} if($r &amp;&amp; $r-&gt;{state});</nowiki>
   $r-&gt;{state}{VAL} = $defs{$dev}{STATE} if($r &amp;&amp; $r-&gt;{state});</nowiki>
entfernt.
entfernt.


== Global Attributes ==
== Global Attributes ==
Zeile 99: Zeile 96:
Weiterhin kann jedes Modul im Initialize mit addToAttrList eigene Attribute zu
Weiterhin kann jedes Modul im Initialize mit addToAttrList eigene Attribute zu
global userattr hinzufuegen.
global userattr hinzufuegen.
[[Kategorie:Development (Archive)]]

Aktuelle Version vom 19. Oktober 2016, 13:14 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 readingsEndUpdate aktualisiert $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 DoTrigger werden

$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.