Hallo zusammen,
auf Basis von Rudis Websocket-Erweiterung für DevIO und seinem Beispiel unter https://forum.fhem.de/index.php/topic,109910.msg1057407.html#msg1057407 versuche ich testweise ein zweistufiges Modulkonzept umzusetzen. Ich scheitere aber seit Tagen kläglich an der Weitergabe von Nachrichten vom physischen zum logischen Modul. Meine Kenntnisse und mein Verständnis reichen derzeit dafür wohl noch nicht aus.
Grundsätzlich steht die Websocket-Verbindung und ich erhalte Nachrichten im physischen Modul (JSON).
Ich habe gedacht, dass im physischen Modul unter ReadFn ein Dispatch ausgelöst werden muss. Aber egal wie ich es anstelle, ich erhalte bevor FHEM komplett abschmiert folgende Meldung im Log:
Can't use an undefined value as a subroutine reference at fhem.pl line 4013
Mein physisches Modul 30_fahBridge.pm hat folgenden Inhalt:
# This module connects to freeathome-api via websocket.
# https://github.com/henry-spanka/freeathome-api
#
# $Id$
package main;
use strict;
use warnings;
use DevIo;
use JSON;
sub fahBridge_Initialize {
my $hash = shift // return;
$hash->{DefFn} = 'fahBridge_Define';
$hash->{ReadFn} = 'fahBridge_ReadFn';
$hash->{SetFn} = 'fahBridge_SetFn';
$hash->{WriteFn} = "fahBridge_Write";
$hash->{Clients} = ':fahDevice:';
$hash->{MatchList} = { "1:fahDevice" => "^.*" };
return;
}
sub fahBridge_Define {
my $hash = shift;
my $def = shift // return;
my @arr = split m{\s+}xms, $def;
return "Usage: define <name> $hash->{TYPE} <host> <port>"
if(@arr < 4);
my $name = shift @arr;
my $type = shift @arr;
my $host = shift @arr;
my $port = shift @arr;
$hash->{Host} = $host;
$hash->{NAME} = $name;
$hash->{Port} = $port;
# websocket adapted from Rudi: https://forum.fhem.de/index.php/topic,109910.msg1057407.html#msg1057407
$hash->{DeviceName} = qq(ws:$hash->{Host}:$hash->{Port});
$hash->{SSL} = 0;
DevIo_OpenDev ($hash, 0, undef, sub() {
DevIo_SimpleWrite($hash, "list", 2);
});
}
sub fahBridge_ReadFn($) {
my ($hash) = @_;
my $buf = DevIo_SimpleRead($hash);
if(!defined($buf)) {
DevIo_CloseDev($hash);
return;
}
Log 1, "GOT via websocket: >$buf<";
Dispatch($hash,"fahDevice_".$buf);
return undef;
}
sub fahBridge_SetFn($@) {
my ( $hash, $name, $cmd, @args ) = @_;
if($cmd eq "status") {
DevIo_SimpleWrite($hash, "info/ABB700000000", 2);
}
}
sub fahBridge_Write ($$) {
my ( $hash, $message) = @_;
DevIo_SimpleWrite($hash, $message, 2);
return undef;
}
1;
Hier das logische Modul 31_fahDevice.pm:
# $Id$
package main;
use strict;
use warnings;
my %fahDevices = (
B002 => {
allowedCmds => 'on:noArg off:noArg statusRequest',
regxCmds => '^on$|^off$',
idpOnOff => 'idp0000',
},
1024 => {
allowedCmds => 'desired-temp:noArg eco:noArg on:noArg off:noArg statusRequest',
regxCmds => '^on$|^off$|^eco$|^desired-temp$',
idpOnOff => 'idp0012',
idpDesTemp => 'idp0016',
idpEco => 'idp0011',
},
);
sub fahDevice_Initialize {
my $hash = shift // return;
$hash->{DefFn} = 'fahDevice_Define';
$hash->{UndefFn} = 'fahDevice_Undef';
$hash->{ParseFN} = 'fahDevice_Parse';
$hash->{SetFn} = 'fahDevice_SetFn';
$hash->{Match} = "^fahDevice.*";
$hash->{Clients} = ':fahDevice:';
$hash->{MatchList} = { "1:fahDevice" => "^.*" };
}
sub fahDevice_Define {
my $hash = shift;
my $def = shift // return;
my @arr = split m{\s+}xms, $def;
return "Usage: define <name> $hash->{TYPE} <serialNumber> <channel>"
if(@arr != 4);
my $name = shift @arr;
my $type = shift @arr;
my $serialNr = shift @arr;
my $channel = shift @arr;
$hash->{NAME} = $name;
$hash->{deviceId} = 'B002'; # Vorerst statisch. Muss beim define noch abgefragt werden!
$hash->{serialNr} = $serialNr;
$hash->{channel} = $channel;
$hash->{IODev} = 'wsTest';
# Adresse rückwärts dem Hash zuordnen (für ParseFn)
$modules{fahDevice}{defptr}{$name} = $hash;
AssignIoPort($hash);
return undef;
}
sub fahDevice_Parse($$) {
my ($io_hash, $message) = @_;
my $name = $io_hash->{NAME};
my $address = 'fahTest'; # just static for testing
# wenn bereits eine Gerätedefinition existiert (via Definition Pointer aus Define-Funktion)
if(my $hash = $modules{fahDevice}{defptr}{$address}) {
Log 1, "PARSE LAUTET $message";
# Rückgabe des Gerätenamens, für welches die Nachricht bestimmt ist.
return $hash->{NAME};
}
else {
# Keine Gerätedefinition verfügbar
# Daher Vorschlag define-Befehl: <NAME> <MODULNAME> <ADDRESSE>
Log 1, 'kein Geraet gefunden';
return "UNDEFINED fahDevice_".$address." fahDevice $address";
}
}
sub fahDevice_SetFn($@) {
my $hash = shift;
my $name = shift;
my $cmd = shift;
my @args = shift;
my $deviceId = $hash->{deviceId};
my $usage = "unknown argument $cmd, choose one of $fahDevices{$deviceId}{allowedCmds}";
if ($cmd eq 'statusRequest') {
IOWrite($hash, "info/$hash->{serialNr}");
return;
}
my $value = $cmd =~ m/on$/xms ? 1
: $cmd =~ m/off$/xms ? 0
: 0;
if ($cmd !~ m/$fahDevices{$deviceId}{regxCmds}/xms) {
return $usage;
}
else {
if ($cmd =~ m/^on$|^off$/xms) {
IOWrite($hash, "raw/$hash->{serialNr}/$hash->{channel}/$fahDevices{$deviceId}{idpOnOff}/$value");
Log 1, "raw/$hash->{serialNr}/$hash->{channel}/$fahDevices{$deviceId}{idpOnOff}/$value";
}
}
}
1;
Ich würde mich freuen, wenn mich jemand in die richtige Richtung schubsen könnte. Ich bin lernwillig und kritikfähig. :)
Gruß
Fabian
$hash->{ParseFN} = 'fahDevice_Parse';
solte wohl
$hash->{ParseFn} = 'fahDevice_Parse';
sein - großes vs. kleines n.
Oh Gott! Wie peinlich! Danke xenos1984. ;D
Kleines n und schon kommen die Nachrichten auch an.