Originally posted by: <email address deleted>
HMRPC - xmlrpc-basierte Homematic-Integration fuer fhem
=======================================================
Von Oliver Wagner
V0.1
Uebersicht
----------
HMRPC ist ein Modul zur Integration des Homematic-Systems der Firma EQ-3
mit fhem. Es verfolgt im Gegensatz zu den bereits vorhandenen CUL_HM/HMLAN-
Modulen einen anderen Ansatz: Statt direkt mit der Funk-Hardware zu
kommunizieren, verwendet es die offizielle bereitgestellte xmlrpc-basierte
API der EQ-3-Software (siehe [1]). Daraus ergeben sich Vorteile und
Nachteile: So sind implizit alle derzeitigen und auch zukuenftigen Geraete
vollumfaenglich unterstuetzt, auch die RS485 Wired-Module.
Der wesentliche Nachteil, oder zumindestens eine Vorraussetzung, ist, dass
man eine Instanz der xmlrpc-Server benoetigt. Dazu gibt es aktuell zwei
Moeglichkeiten:
1) auf der CCU1 selbst laufen "rfd" fuer die Funkkommunikation und
"hs485d" fuer die Wired-Kommunikaiton.
Eine Uebersicht der Softwarearchitektur der CCU1 findet sich unter [2]
2) als Teil der Verwaltungssoftware fuer den HM-LAN-Aadapter (siehe [3])
gibt
es einen xmlrpc-Dienst fuer Funkkommunikation als Windows-Service. Dieser
entspricht dem "rfd" auf der CCU1.
Es ist aber nicht auszuschliessen, das EQ-3 in Zukunft z.B. einen rfd fuer
Linux veroeffentlicht.
Geschichte und Status
---------------------
Diese Module sind aus der Middleware "HMCompanion" [4] entstanden, die
ich mir
fuer die HM-Integration in meinen Haussteuerungswildwuchs geschrieben habe.
HMRPC hat aktuell eher experimentellen Charakter. Ohne genaue Kenntnisse
von fhem, perl und HM-Internas haben die Module nur eingeschraenkten
Nutzwert,
die Veroeffentlichung dient erstmal nur dazu, fruehes Feedback zur
Implementierung zu bekommen.
Das ist im übrigen mein erstes nicht komplett triviales Stück perl-code
-- über
Hinweise diesbezüglich würde ich mich ebenso freuen wie über allgemeines
Feedback zu HMRPC.
Benutzung
---------
Es gibt zwei Module:
00_HMRPC.pm ist der Provider fuer die Kommunikation mit eineml
xmlrpc-Service
01_HMDEV.pm ist jeweils die Abstraktion eines einzelnen Devices
Beispielkonfiguration fuer fhem:
# Wired-Schnittstelle auf einer CCU1 mit IP 192.168.5.2)
define hmw HMRPC 192.168.5.2 2000
# Ein Kanal eines Wired-Aktors
define light_buero_olli HMDEV GEQ0009019:3
Nutzung dann z.B. mit
set light_buero_olli STATE false
Ein putParamset (Konfigurationsupdate) wird dann durch zusätzliche Angabe
der Paramset-ID generiert:
set light_buero_olli MASTER LOGGING 0
Die Attribute eines Geraetes entsprechen den in dem Dokument unter [1]
"HomeMatic-Script Dokumentation: Teil 4 - Datenpunkte" beschriebenen.
Die Inhalte der Paramsets sind aktuell nicht dokumentiert, man muss diese
anhand des xmlrpc-Requests getParamsetDescription oder durch Browsen der
XML-Beschreibungen im /firmware-Verzeichnis der CCU-Software
ermitteln.
Weitergehende Funktionen wie synchrones Abfragen von Werten oder Paramsets
oder Statii des jeweiligen Service (Meldungen etc.) sind geplant, aber noch
nicht implementiert.
Design
------
Ich habe überlegt, ob HMRPC als Provider für CUL_HM dienen könnte, habe aber
keine praktikable Lösung dafür gefunden -- HMDEV ist aktuell im Vergleich zu
CUL_HM sehr dumm und dient mehr oder weniger nur als Cache für Adresse und
Readings.
HMRPC meldet sich beim jeweiligen Service per "init" an und erhält dann per
xmlrpc-Callback Mitteilungen über Zustandsänderungen. Wird der Service neu
gestartet (CCU Reboot o.ä.), ist diese Anmeldung hinfällig. Es gibt aktuell
keine gute Methode, dies festzustelle -- als Workaround meldet sich HMRPC
15 Minuten nach dem letzten empfangenen Callback neu an. Je nach Art der
verwendeten Aktoren in einer Installation kann diese Zeit sehr kurz sein
und daher unnötige re-inits verursachen. Diese scheinen aber
grundsätzlich kein
Problem auf der Service-Seite darzustellen.
Anhang
------
[1] http://www.homematic.com/index.php?id=156
[2] http://www.homematic-wiki.info/mw/index.php/HomeMatic_Software
[3] http://www.homematic.com/index.php?id=644
[4] http://www.fhz-forum.de/viewtopic.php?f=26&t=4639
--
To unsubscribe from this group, send email to
fhem-users+unsubscribe@googlegroups.com
##############################################
# HMRPC Device Handler
# Written by Oliver Wagner
#
# V0.1
#
##############################################
#
# This module handles individual devices via the
# HMRPC provider.
#
package main;
use strict;
use warnings;
sub
HMDEV_Initialize($)
{
my ($hash) = @_;
$hash->{Match} = "^HMDEV .* .* .*";
$hash->{DefFn} = "HMDEV_Define";
$hash->{ParseFn} = "HMDEV_Parse";
$hash->{SetFn} = "HMDEV_Set";
$hash->{AttrList} = "IODev do_not_notify:0,1";
}
#############################
sub
HMDEV_Define($$)
{
my ($hash, $def) = @_;
my @a = split("[ \t][ \t]*", $def);
my $name = $hash->{NAME};
return "wrong syntax: define HMDEV deviceaddress" if int(@a)!=3;
my $addr=uc($a[2]);
$hash->{hmaddr}=$addr;
$modules{HMDEV}{defptr}{$addr} = $hash;
AssignIoPort($hash);
Log 5,"Assigned $name to $hash->{IODev}->{NAME}";
return undef;
}
#############################
sub
HMDEV_Parse($$)
{
my ($hash, $msg) = @_;
my @mp=split(" ",$msg);
my $addr=$mp[1];
$hash=$modules{HMDEV}{defptr}{$addr};
if(!$hash)
{
Log(2,"Received callback for unknown device $msg");
return "UNDEFINED HMDEV_$addr HMDEV $addr";
}
#
# Ok update the relevant reading
#
my @changed;
$hash->{READINGS}{$mp[2]}{TIME}=TimeNow();
if($hash->{READINGS}{$mp[2]}{VAL} && ($hash->{READINGS}{$mp[2]}{VAL} ne $mp[3]))
{
push @changed, "$mp[2]: $mp[3]";
$hash->{READINGS}{$mp[2]}{VAL}=$mp[3];
}
$hash->{CHANGED}=\@changed;
return $hash->{NAME};
}
################################
sub
HMDEV_Set($@)
{
my ($hash, @a) = @_;
return "invalid set call @a" if(@a != 3 && @a != 4);
# We delegate this call to the IODev, after having added the device address
if(@a==4)
{
return HMRPC_Set($hash->{IODev},$hash->{IODev}->{NAME},$hash->{hmaddr},$a[1],$a[2],$a[3]);
}
else
{
return HMRPC_Set($hash->{IODev},$hash->{IODev}->{NAME},$hash->{hmaddr},$a[1],$a[2]);
}
}
1;
##############################################
#
# HomeMatic XMLRPC API Device Provider
# Written by Oliver Wagner
#
# V0.1
#
##############################################
#
# This module implements the documented XML-RPC based API
# of the Homematic system software (currently offered as
# part of the CCU1 and of the LAN config adapter software)
#
# This module operates a http server to receive incoming
# xmlrpc event notifications from the HM software.
#
# Individual devices are then handled by 01_HMDEV.pm
#
package main;
use strict;
use warnings;
use Time::HiRes qw(gettimeofday);
use RPC::XML::Server;
use RPC::XML::Client;
use Dumpvalue;
my $dumper=new Dumpvalue;
$dumper->veryCompact(1);
sub HMRPC_Initialize($)
{
my ($hash) = @_;
$hash->{DefFn} = "HMRPC_Define";
$hash->{ShutdownFn} = "HMRPC_Shutdown";
$hash->{ReadFn} = "HMRPC_Read";
$hash->{SetFn} = "HMRPC_Set";
$hash->{Clients} = ":HMDEV:";
}
#####################################
sub
HMRPC_Shutdown($)
{
my ($hash) = @_;
# Uninitialize again
$hash->{client}->send_request("init",$hash->{callbackurl},"");
return undef;
}
#####################################
sub
HMRPC_Define($$)
{
my ($hash, $def) = @_;
my @a = split("[ \t][ \t]*", $def);
if(@a != 4) {
my $msg = "wrong syntax: define HMRPC remote_host remote_port";
Log 2, $msg;
return $msg;
}
$hash->{serveraddr}=$a[2];
$hash->{serverport}=$a[3];
$hash->{client}=RPC::XML::Client->new("http://$a[2]:$a[3]/");
$hash->{server}=RPC::XML::Server->new(port=>5400+$hash->{serverport});
$hash->{server}->{fhemdef}=$hash;
# Add the XMLRPC methods we do expose
$hash->{server}->add_method(
{name=>"event",signature=> ["string string string string int","string string string string double","string string string string boolean"],code=>\&HMRPC_EventCB}
);
#
# Dummy implementation, always return an empty array
#
$hash->{server}->add_method(
{name=>"listDevices",signature=>["array string"],code=>sub{return RPC::XML::array->new()} }
);
#
# TOFIX! We can use this to store device types, autocreate devices and other niceties
#
$hash->{server}->add_method(
{name=>"newDevices",signature=>["array string array"],code=>sub{return RPC::XML::array->new()} }
);
$hash->{STATE} = "Initialized";
$hash->{SERVERSOCKET}=$hash->{server}->{__daemon};
$hash->{FD}=$hash->{SERVERSOCKET}->fileno();
$hash->{PORT}=$hash->{server}->{__daemon}->sockport();
# This will also register the callback
HMRPC_CheckCallback($hash);
$selectlist{"$hash->{serveraddr}.$hash->{serverport}"} = $hash;
#
# All is well
#
return 0;
}
sub
HMRPC_CheckCallback($)
{
my ($hash) = @_;
# We recheck the callback every 15 minutes. If we didn't receive anything
# inbetween, we re-init just to make sure (CCU reboots etc.)
InternalTimer(gettimeofday()+(15*60), "HMRPC_CheckCallback", $hash, 0);
if(!$hash->{lastcallbackts})
{
HMRPC_RegisterCallback($hash);
return;
}
my $age=int(gettimeofday()-$hash->{lastcallbackts});
if($age>(15*60))
{
Log 5,"HMRPC Last callback received more than $age seconds ago, re-init-ing";
HMRPC_RegisterCallback($hash);
}
}
sub
HMRPC_RegisterCallback($)
{
my ($hash) = @_;
#
# We need to find out our local address. In order to do so,
# we establish a dummy connection to the remote xmlrpc server
# and then look at the local socket address assigned to us.
#
my $dummysock=IO::Socket::INET->new(PeerAddr=>$hash->{serveraddr},PeerPort=>$hash->{serverport});
$hash->{callbackurl}="http://".$dummysock->sockhost().":".$hash->{PORT}."/fhemhmrpc";
$dummysock->close();
Log(2, "HMRPC callback listening on $hash->{callbackurl}");
# We need to fork here, as the xmlrpc server will synchronously call us
if(!fork())
{
$hash->{client}->send_request("init",$hash->{callbackurl},"cb");
exit(0);
}
Log(2, "HMRPC callback initialized");
}
#####################################
sub
HMRPC_EventCB($$$$$)
{
my ($server,$cb,$devid,$attr,$val)=@_;
Log(5, "Processing event setting $devid->$attr=$val" );
Dispatch($server->{fhemdef},"HMDEV $devid $attr $val",undef);
$server->{fhemdef}->{lastcallbackts}=gettimeofday();
}
sub
HMRPC_Read($)
{
my ($hash) = @_;
#
# Handle an incoming callback
#
my $conn=$hash->{server}->{__daemon}->accept();
$conn->timeout(3);
$hash->{server}->process_request($conn);
$conn->close;
undef $conn;
}
################################
#
#
sub
HMRPC_Set($@)
{
my ($hash, @a) = @_;
return "invalid set specification @a" if(@a != 4 && @a != 5);
my $ret;
if(@a==5)
{
my $paramset={$a[3]=>$a[4]};
$ret=$hash->{client}->simple_request("putParamset",$a[1],$a[2],$paramset);
}
else
{
$ret=$hash->{client}->simple_request("setValue",$a[1],$a[2],$a[3]);
}
if($ret)
{
return $ret->{faultCode}.": ".$ret->{faultString};
}
else
{
return undef;
}
}
1;
Hallo Oliver,
> HMRPC - xmlrpc-basierte Homematic-Integration fuer fhem
Klasse, dein Modul eroeffnet neue Moeglichkeiten :)
> Der wesentliche Nachteil, oder zumindestens eine Vorraussetzung, ist, dass
> man eine Instanz der xmlrpc-Server benoetigt. Dazu gibt es aktuell zwei
> Moeglichkeiten:
Die Dritte: mit qemu-arm das rfd der CCU aus dem Firmware update starten, siehe
auch die "HM Neuigkeiten" Diskussion in diese Gruppe.
> Das ist im übrigen mein erstes nicht komplett triviales Stück perl-code
Dafuer ist es aber erstaunlich schoen und sauber gelungen! Ich wuerde mich
freuen, wenn Du das Programm direkt nach fhem/contrib oder nach fhem/FHEM
einchecken wuerdest (letzteres nur mit Doku im commandref.html :).
Was mir auf die schnelle aufgefallen ist.
- das set Befehl unterstuetzt kein "?", damit wird FHEMWEB seine
Schwierigkeiten haben.
- HMRPC_read koennte fhem blockieren, wenn rfd.exe die Daten nur zoegerlich
liefert. Aber wenn rfd.exe immer nur vorgedaute Daten sendet, dann sollte das
nie ein Problem sein.
- FritzBox User duerfen sich erstmal nicht freuen: es werden zusaetzliche
Module (RPC::XML::.*) benoetigt.
Gruss,
Rudi
--
To unsubscribe from this group, send email to
fhem-users+unsubscribe@googlegroups.com
Originally posted by: <email address deleted>
Hallo Rudi,
> Ich wuerde mich freuen, wenn Du das Programm direkt nach fhem/contrib
oder nach fhem/FHEM einchecken wuerdest
Nun eingecheckt in contrib/HMRPC (wegen des noch experimentellen Charakters)
> - das set Befehl unterstuetzt kein "?", damit wird FHEMWEB seine
Schwierigkeiten haben.
Ich habe gerade mal in anderen Modulen geschaut, was es damit auf sich
hat, aber ad-hoc nichts gefunden, was sowas wie "set ?" implementiert --
Pointer welcome...
> - HMRPC_read koennte fhem blockieren, wenn rfd.exe die Daten nur
zoegerlich liefert. Aber wenn rfd.exe immer nur vorgedaute Daten sendet,
dann sollte das nie ein Problem sein.
Ich denke auch, dass das nur in besonders komischen Fällen von
Netzwerkproblemen eine Rolle spielen könnte. Auf jeden Fall ist das
Timeout des httpd sehr niedrig (3 Sekunden) gesetzt.
> - FritzBox User duerfen sich erstmal nicht freuen: es werden
zusaetzliche Module (RPC::XML::.*) benoetigt.
Hmja. Die EQ-3-Server unterstützen auch einen nicht wirklich
dokumentierten Binärmodus für die Datenübertragung, der sich relativ
einfach in Handarbeit parsen läßt; das hatte ich für HMCompanion mal
implementiert. Eventuell wäre es eine Option, diesen zu benutzen und auf
RPC::XML:: zu verzichten, das würde ich dann aber gerne in einem
späteren Stadium angehen.
Viele Grüße,
Olli
--
To unsubscribe from this group, send email to
fhem-users+unsubscribe@googlegroups.com
> Ich habe gerade mal in anderen Modulen geschaut, was es damit auf sich
> hat, aber ad-hoc nichts gefunden, was sowas wie "set ?" implementiert --
> Pointer welcome...
Sowas wie:
return "Unknown argument $a[1], choose one of " . join(" ", sort keys %sets)
if(!defined($sets{$a[1]}));
aus 00_CUL.pm. Im 10_FS20.pm/10_CUL_HM.pm usw. ist das natuerlich auch drin,
aber komplexer, da unterschiedliche Modelle unterschiedliche Set-Parameter
unterstuetzen.
--
To unsubscribe from this group, send email to
fhem-users+unsubscribe@googlegroups.com
Originally posted by: <email address deleted>
Hi,
es gibt nun zusätzlich ein Script "contrib/HMRPC/import_from_webui.bsh",
welches per TCL-API aus dem WebUI (ReGaHSS) einer laufenden CCU die
zugewiesenen Device- und Channelnamen abfragt und auf dieser Basis ein
Config-Fragment für fhem generiert.
Es werden automatisch die IODev "hmw" für Wired-Geräte und "hmrf" für
RF-Geräte zugewiesen. Desweiteren wird auch das "room"-Attribut
automatisch anhand der ReGaHSS-Namen gesetzt.
Zur Namensumwandlung werden alle Umlaute und einige Sonderzeichen
umgesetzt und der ReGaHSS-Name in Kleinbuchstaben gewandelt. Da im
ReGaHSS-Namensraum ein Device und ein Channel denselben Namen haben
können, generiert das Script bei Namensgleichheit den Device-Namen mit
dem Suffix "_dev".
Bei den Room-Namen werden nur Leerzeichen entfernt.
Viele Grüße,
Olli
--
To unsubscribe from this group, send email to
fhem-users+unsubscribe@googlegroups.com
Originally posted by: <email address deleted>
Hallo Olli,
da packst du ja ein sehr interessantes Thema an! Ich hatte die gleiche Idee
nur andersrum ;)
Wenn wir eine Serversoftware hätten, welche eben diese XMLRPC Schnittstelle
der CCU implementiert - also so tut als sei sie ein CCU - und "unter der
Haube" aber FHEM steuert und dessen Werte ausliest, wird's spannend:
Damit hätten wir auf einen Schlag viele weitere Frontends für FHEM, die
eigentlich für die Homematic CCU gedacht waren! Mich interessieren da vor
allem die Android Apps für die Homematic CCU. Es gibt aber auch weitere
interessante PC basierte Frontends (z.B. ip-symcon).
Bei mir ist es aus Zeitgründen leider nur bei der Idee geblieben.
Was denkst du/ihr?
Gruß
Eyk
Am 11. Oktober 2011 01:07 schrieb Oliver Wagner :
> Hi,
>
> es gibt nun zusätzlich ein Script "contrib/HMRPC/import_from_webui.bsh",
> welches per TCL-API aus dem WebUI (ReGaHSS) einer laufenden CCU die
> zugewiesenen Device- und Channelnamen abfragt und auf dieser Basis ein
> Config-Fragment für fhem generiert.
>
> Es werden automatisch die IODev "hmw" für Wired-Geräte und "hmrf" für
> RF-Geräte zugewiesen. Desweiteren wird auch das "room"-Attribut
> automatisch anhand der ReGaHSS-Namen gesetzt.
>
> Zur Namensumwandlung werden alle Umlaute und einige Sonderzeichen
> umgesetzt und der ReGaHSS-Name in Kleinbuchstaben gewandelt. Da im
> ReGaHSS-Namensraum ein Device und ein Channel denselben Namen haben
> können, generiert das Script bei Namensgleichheit den Device-Namen mit
> dem Suffix "_dev".
> Bei den Room-Namen werden nur Leerzeichen entfernt.
>
> Viele Grüße,
> Olli
>
> --
> To unsubscribe from this group, send email to
> fhem-users+unsubscribe@googlegroups.com
>
--
To unsubscribe from this group, send email to
fhem-users+unsubscribe@googlegroups.com
Originally posted by: <email address deleted>
gibt es hier was neues?
--
To unsubscribe from this group, send email to
fhem-users+unsubscribe@googlegroups.com