From 8da10956028ee968b82662da20ef877c6b161eff Mon Sep 17 00:00:00 2001 From: rudolfkoenig Date: Sun, 8 May 2016 13:58:47 +0000 Subject: [PATCH] 00_FBAHAHTTP.pm: new Module git-svn-id: https://svn.fhem.de/fhem/trunk@11408 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 1 + fhem/FHEM/00_FBAHAHTTP.pm | 257 ++++++++++++++++++++++++++++++++++++++ fhem/FHEM/10_FBDECT.pm | 186 ++++++++++++++++++++++----- fhem/MAINTAINER.txt | 1 + fhem/fhem.pl | 2 +- 5 files changed, 415 insertions(+), 32 deletions(-) create mode 100644 fhem/FHEM/00_FBAHAHTTP.pm diff --git a/fhem/CHANGED b/fhem/CHANGED index 8ae9e2500..ef32fd9e7 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,6 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - feature: FBAHAHTTP module as replacement for the deprecated FBAHA - feature: 50_TelegramBot reply set command / allowedCommands as restriction - change: 49_SSCam: get "snapfileinfo" will get back an Infomessage if Reading "LastSnapId" isn't available diff --git a/fhem/FHEM/00_FBAHAHTTP.pm b/fhem/FHEM/00_FBAHAHTTP.pm new file mode 100644 index 000000000..547383a35 --- /dev/null +++ b/fhem/FHEM/00_FBAHAHTTP.pm @@ -0,0 +1,257 @@ +############################################## +# $Id$ +package main; + +# Documentation: AHA-HTTP-Interface.pdf, AVM_Technical_Note_-_Session_ID.pdf + +use strict; +use warnings; +use Time::HiRes qw(gettimeofday); +use FritzBoxUtils; + +sub +FBAHAHTTP_Initialize($) +{ + my ($hash) = @_; + $hash->{WriteFn} = "FBAHAHTTP_Write"; + $hash->{DefFn} = "FBAHAHTTP_Define"; + $hash->{SetFn} = "FBAHAHTTP_Set"; + $hash->{AttrFn} = "FBAHAHTTP_Attr"; + $hash->{AttrList} = "dummy:1,0 fritzbox-user polltime"; +} + + +##################################### +sub +FBAHAHTTP_Define($$) +{ + my ($hash, $def) = @_; + my @a = split("[ \t][ \t]*", $def); + + return "wrong syntax: define FBAHAHTTP hostname" + if(@a != 3); + + $hash->{Clients} = ":FBDECT:"; + my %matchList = ( "1:FBDECT" => ".*" ); + $hash->{MatchList} = \%matchList; + + for my $d (devspec2array("TYPE=FBDECT")) { + if($defs{$d}{IODev} && $defs{$d}{IODev}{TYPE} eq "FBAHA") { + my $n = $defs{$d}{IODev}{NAME}; + CommandAttr(undef, "$d IODev $hash->{NAME}"); + CommandDelete(undef, $n) if($defs{$n}); + } + $defs{$d}{IODev} = $hash + } + + return undef if($hash->{DEF} eq "none"); # DEBUGGING + InternalTimer(1, "FBAHAHTTP_Poll", $hash); + $hash->{STATE} = "defined"; + return undef; +} + +##################################### +sub +FBAHAHTTP_Poll($) +{ + my ($hash) = @_; + my $name = $hash->{NAME}; + + my $dr = sub { + $hash->{STATE} = $_[0]; + Log 2, $hash->{STATE}; + return $hash->{STATE}; + }; + + if(!$hash->{".SID"}) { + my $fb_user = AttrVal($name, "fritzbox-user", ''); + return $dr->("MISSING: attr $name fritzbox-user") if(!$fb_user); + + my ($err, $fb_pw) = getKeyValue("FBAHAHTTP_PASSWORD_$name"); + return $dr->("ERROR: $err") if($err); + return $dr->("MISSING: set $name password") if(!$fb_pw); + + my $sid = FB_doCheckPW($hash->{DEF}, $fb_user, $fb_pw); + return $dr->("ERROR: cannot get SID, check hostname/fritzbox-user/password") + if(!$sid); + $hash->{".SID"} = $sid; + $hash->{STATE} = "connected"; + } + + my $sid = $hash->{".SID"}; + + HttpUtils_NonblockingGet({ + url=>"http://$hash->{DEF}/webservices/homeautoswitch.lua?sid=$sid". + "&switchcmd=getdevicelistinfos", + loglevel => AttrVal($name, "verbose", 4), + callback => sub { + if($_[1]) { + Log3 $name, 3, "$name: $_[1]"; + delete $hash->{".SID"}; + return; + } + + if($_[2] !~ m,^$,s) { + Log3 $name, 3, "$name: unexpected reply from device: $_[2]"; + delete $hash->{".SID"}; + return; + } + + $_[2] =~ s,,,; + + my @a = split("{".SID"}); + FBAHAHTTP_Poll($hash); + } + } + return undef; +} + +##################################### +sub +FBAHAHTTP_Set($@) +{ + my ($hash, @a) = @_; + my $name = shift @a; + my %sets = (password=>2, refreshstate=>1); + + return "set $name needs at least one parameter" if(@a < 1); + my $type = shift @a; + + return "Unknown argument $type, choose one of refreshstate:noArg password" + if(!defined($sets{$type})); + return "Missing argument for $type" if(int(@a) < $sets{$type}-1); + + if($type eq "password") { + setKeyValue("FBAHAHTTP_PASSWORD_$name", $a[0]); + delete($hash->{".SID"}); + FBAHAHTTP_Poll($hash); + return; + } + if($type eq "refreshstate") { + FBAHAHTTP_Poll($hash); + return; + } + + return undef; +} + + +##################################### +sub +FBAHAHTTP_Write($$$) +{ + my ($hash,$fn,$msg) = @_; + my $name = $hash->{NAME}; + my $sid = $hash->{".SID"}; + if(!$sid) { + Log 1, "$name: Not connected, wont execute $msg"; + return; + } + HttpUtils_NonblockingGet({ + url=>"http://$hash->{DEF}/webservices/homeautoswitch.lua?sid=$sid". + "&ain=$fn&switchcmd=$msg", + loglevel => AttrVal($name, "verbose", 4), + callback => sub { + if($_[1]) { + Log3 $name, 3, "$name: $_[1]"; + delete $hash->{".SID"}; + return; + } + Log 1, "FBAHAHTTP_Write reply for $name: $_[2]"; + } + }); +} + + +1; + +=pod +=begin html + + +

FBAHAHTTP

+
    + This module connects to the AHA server (AVM Home Automation) on a FRITZ!Box + via HTTP, it is a successor/drop-in replacement for the FBAHA module. It is + necessary, as the FBAHA interface is deprecated by AVM. Since the AHA HTTP + interface do not offer any notification mechanism, the module is regularly + polling the FRITZ!Box.
    + Important: For an existing installation with an FBAHA device, defining a + new FBAHAHTTP device will change the IODev of all FBDECT devices from the + old FBAHA to this FBAHAHTTP device, and it will delete the FBAHA device.
    + + This module serves as the "physical" counterpart to the FBDECT devices. Note: you have to enable the access to + Smart Home in the FRITZ!Box frontend for the fritzbox-user. +

    + + Define +
      + define <name> FBAHAHTTP <hostname>
      +
      + <hostnamedevice> is most probably fritz.box. + Example: +
        + define fb1 FBAHAHTTP fritz.box
        +
      +
    +
    + + + Set +
      +
    • password <password>
      + This is the only way to set the password +
    • +
    • refreshstate
      + The state of all devices is polled every <polltime> seconds (default + is 300). This command forces a state-refresh. +
    • +
    +
    + + + Get +
      N/A
    +
    + + + Attributes + +
    +
+ + +=end html + +=cut diff --git a/fhem/FHEM/10_FBDECT.pm b/fhem/FHEM/10_FBDECT.pm index c6be6a7ca..10c1a5ad9 100644 --- a/fhem/FHEM/10_FBDECT.pm +++ b/fhem/FHEM/10_FBDECT.pm @@ -2,8 +2,6 @@ # $Id$ package main; -# TODO: test multi-dev, test on the FB - use strict; use warnings; use SetExtensions; @@ -73,8 +71,6 @@ FBDECT_Define($$) if($ioNameAndId =~ m/^([^:]*):(.*)$/) { $ioName = $1; $id = $2; } - return "define $name: wrong id ($id): need a number" - if( $id !~ m/^\d+$/i ); $hash->{id} = $id; $hash->{props} = shift @a; @@ -84,14 +80,57 @@ FBDECT_Define($$) } ################################### -my %sets = ("on"=>1, "off"=>1, "msgInterval"=>1); +sub +FBDECT_SetHttp($@) +{ + my ($hash, @a) = @_; + my %cmd; + my $p = $hash->{props}; + + if($p =~ m/switch/) { + $cmd{off} = $cmd{on} = $cmd{toggle} = "noArg"; + } + if($p =~ m/actuator/) { + $cmd{"desired-temp"} = "slider,8,0.5,28,1"; + $cmd{open} = $cmd{closed} = "noArg"; + } + if(!$cmd{$a[1]}) { + my $cmdList = join(" ", map { "$_:$cmd{$_}" } sort keys %cmd); + return SetExtensions($hash, $cmdList, @a) + } + + my $cmd = $a[1]; + if($cmd =~ m/^(on|off|toggle)$/) { + IOWrite($hash, ReadingsVal($hash->{NAME},"AIN",0), "setswitch$cmd"); + my $state = ($cmd eq "toggle" ? ($hash->{state} eq "on" ? "off":"on"):$cmd); + readingsSingleUpdate($hash, "state", $state, 1); + return undef; + } + + if($cmd =~ m/^(open|closed|desired-temp)$/) { + if($cmd eq "desired-temp") { + return "Usage: set $hash->{NAME} desired-temp value" if(int(@a) != 3); + return "desired-temp must be between 8 and 28" + if($a[2] !~ m/^[\d.]+$/ || $a[2] < 8 || $a[2] > 28) + } + my $val = ($cmd eq "open" ? 254 : ($cmd eq "closed" ? 253: int(2*$a[2]))); + IOWrite($hash, ReadingsVal($hash->{NAME},"AIN",0),"sethkrtsoll¶m=$val"); + return undef; + } +} + +################################### sub FBDECT_Set($@) { my ($hash, @a) = @_; + my %sets = ("on"=>1, "off"=>1, "msgInterval"=>1); + + return FBDECT_SetHttp($hash, @a) + if($hash->{IODev} && $hash->{IODev}{TYPE} eq "FBAHAHTTP"); + my $ret = undef; my $cmd = $a[1]; - if(!$sets{$cmd}) { my $usage = join(" ", sort keys %sets); return SetExtensions($hash, $usage, @a); @@ -118,17 +157,17 @@ FBDECT_Set($@) return undef; } -my %gets = ("devInfo"=>1); sub FBDECT_Get($@) { my ($hash, @a) = @_; my $ret = undef; my $cmd = ($a[1] ? $a[1] : ""); + my %gets = ("devInfo"=>1); - if(!$gets{$cmd}) { - return "Unknown argument $cmd, choose one of ".join(" ", sort keys %gets); - } + my $cmdList = ($hash->{IODev} && $hash->{IODev}{TYPE} eq "FBAHA") ? + join(" ", sort keys %gets) : ""; + return "Unknown argument $cmd, choose one of $cmdList" if(!$gets{$cmd}); if($cmd eq "devInfo") { my @answ = FBAHA_getDevList($hash->{IODev}, $hash->{id}); @@ -159,14 +198,87 @@ FBDECT_Get($@) return undef; } +my %fbhttp_readings = ( + absenk => 'sprintf("night-temp:%.1f C", $val/2)', + celsius => 'sprintf("temperature:%.1f C (measured)", $val/10)', + energy => 'sprintf("energy:%d Wh", $val)', + functionbitmask => '"FBPROP:$fbprop"', + fwversion => '"fwversion:$val"', + id => '"ID:$val"', + identifier => '"AIN:$val"', + komfort => 'sprintf("day-temp:%.1f C", $val/2)', + lock => '"locked:".($val ? "yes":"no")', + mode => '"mode:$val"', + name => '"FBNAME:$val"', + offset => 'sprintf("tempadjust:%.1f C", $val/10)', # ?? + power => 'sprintf("power:%.2f W", $val/1000)', + present => '"present:".($val?"yes":"no")', + productname => '"FBTYPE:$val"', + state => '"state:".($val?"on":"off")', + tist => 'sprintf("temperature:%.1f C (measured)", $val/2)', + tsoll => 'sprintf("desired-temp:%.1f C", $val/2)', +); + +sub +FBDECT_ParseHttp($$) +{ + my ($iodev, $msg, $local) = @_; + my $ioName = $iodev->{NAME}; + my %h; + + $msg =~ s,<([^/>]+?)>([^<]+?)<,$h{$1}=$2,ge; # Quick & Dirty: Tags + $msg =~ s, ([a-z]+?)="([^"]+)",$h{$1}=$2,ge; # Quick & Dirty: Attributes + + my $ain = $h{identifier}; + $ain =~ s/[: ]/_/g; + + my %ll = (6=>"actuator", 7=>"powerMeter", 8=>"tempSensor", + 9=>"switch", 10=>"repeater"); + my $lsn = int($h{functionbitmask}); + my @fb; + map { push @fb, $ll{$_} if((1<<$_) & $lsn) } sort keys %ll; + my $fbprop = join(",", @fb); + + my $dp = $modules{FBDECT}{defptr}; + my $hash = $dp->{"$ioName:$ain"}; + $hash = $dp->{$ain} if(!$hash); + $hash = $dp->{"$ioName:$h{id}"} if(!$hash); + $hash = $dp->{$h{id}} if(!$hash); + + if(!$hash) { + my $ret = "UNDEFINED FBDECT_${ioName}_$ain FBDECT $ioName:$ain $fbprop"; + Log3 $ioName, 3, "$ret, please define it"; + DoTrigger("global", $ret); + return ""; + } + + $hash->{props} = $fbprop; # replace values from define + readingsBeginUpdate($hash); + Log3 $hash, 5, $hash->{NAME}; + foreach my $n (keys %h) { + Log3 $hash, 5, " $n = $h{$n}"; + next if(!$fbhttp_readings{$n}); + my $val = $h{$n}; + my ($ptyp,$pyld) = split(":", eval $fbhttp_readings{$n}, 2); + readingsBulkUpdate($hash, $ptyp, $pyld); + readingsBulkUpdate($hash, "state", "desired-temp: ".($val/2)) + if($n eq "tsoll"); # Exception + } + readingsEndUpdate($hash, 1); + + return $hash->{NAME}; +} + ################################### sub FBDECT_Parse($$@) { my ($iodev, $msg, $local) = @_; - my $ioName = $iodev->{NAME}; my $mt = substr($msg, 0, 2); + return FBDECT_ParseHttp($iodev, $msg) if($mt eq "{NAME}; if($mt ne "07" && $mt ne "04") { Log3 $ioName, 1, "FBDECT: unknown message type $mt"; return ""; # Nobody else is able to handle this @@ -361,16 +473,15 @@ FBDECT_Undef($$)

FBDECT

    This module is used to control AVM FRITZ!DECT devices via FHEM, see also the - FBAHA module for the base. + FBAHA or FBAHAHTTP module for + the base.

    Define
      - define <name> FBDECT [<FBAHAname>:]<homeId> <id> [classes] + define <name> FBDECT [<FBAHAname>:]<id> props

      - <id> is the id of the device, the classes argument ist ignored for now. -
      Example:
        define lamp FBDECT 16 switch,powerMeter
        @@ -387,11 +498,18 @@ FBDECT_Undef($$) Set
        • on/off
          - set the device on or off.
        • -
        • - set extensions are supported.
        • + set the device on or off. + + +
        • desired-temp <value>
          + set the desired temp on a Comet DECT (FBAHAHTTP IOdev only) +
        • + +
        • set extensions are supported. +
        • +
        • msgInterval <sec>
          - Number of seconds between the sensor messages. + Number of seconds between the sensor messages (FBAHA IODev only).

        @@ -400,7 +518,8 @@ FBDECT_Undef($$) Get
        • devInfo
          - report device information
        • + report device information (FBAHA IODev only) +

        @@ -448,24 +567,23 @@ FBDECT_Undef($$)

        FBDECT

          Dieses Modul wird verwendet, um AVM FRITZ!DECT Geräte via FHEM zu - steuern, siehe auch das FBAHA Modul für die - Anbindung an das FRITZ!Box. + steuern, siehe auch das FBAHA oder FBAHAHTTP Modul für die Anbindung an das FRITZ!Box.

          Define
            - define <name> FBDECT [<FBAHAname>:]<homeId> <id> [classes] + define <name> FBDECT [<FBAHAname>:]<id> props

            - <id> ist das Geräte-ID, das Argument wird z.Zt ignoriert. -
            Beispiel:
              define lampe FBDECT 16 switch,powerMeter
            - Achtung:FBDECT Einträge werden noralerweise per - autocreate angelegt. Falls sie die zugeordnete FBAHA - Instanz umbenennen, dann muss die FBDECT Definition manuell angepasst werden. + Achtung:FBDECT Einträge werden normalerweise per + autocreate angelegt. Falls sie die zugeordnete + FBAHA oder FBAHAHTTP Instanz umbenennen, dann muss die FBDECT Definition + manuell angepasst werden.


        • on/off
          Gerät einschalten bzw. ausschalten.
        • +
        • desired-temp <value&/gt;
          + Gewünschte Temperatur beim Comet DECT setzen (nur mit FBAHAHTTP als + IODev). +
        • Die set extensions werden - unterstützt.
        • + unterstützt. +
        • msgInterval <sec>
          - Anzahl der Sekunden zwischen den Sensornachrichten. + Anzahl der Sekunden zwischen den Sensornachrichten (nur mit FBAHA als + IODev).

        @@ -488,7 +612,7 @@ FBDECT_Undef($$) Get
        • devInfo
          - meldet Geräte-Informationen.
        • + meldet Geräte-Informationen (nur mit FBAHA als IODev)

        diff --git a/fhem/MAINTAINER.txt b/fhem/MAINTAINER.txt index 01dfff128..3aa8abd4a 100644 --- a/fhem/MAINTAINER.txt +++ b/fhem/MAINTAINER.txt @@ -18,6 +18,7 @@ configDB.pm betateilchen http://forum.fhem.de Sonstiges FHEM/00_CM11.pm borisneubert http://forum.fhem.de SlowRF FHEM/00_CUL.pm rudolfkoenig http://forum.fhem.de SlowRF FHEM/00_FBAHA.pm rudolfkoenig http://forum.fhem.de FRITZ!Box +FHEM/00_FBAHAHTTP.pm rudolfkoenig http://forum.fhem.de FRITZ!Box FHEM/00_FHZ.pm rudolfkoenig http://forum.fhem.de SlowRF FHEM/00_HMLAN.pm martinp876 http://forum.fhem.de HomeMatic FHEM/00_HXB.pm borisneubert http://forum.fhem.de Sonstige Systeme diff --git a/fhem/fhem.pl b/fhem/fhem.pl index c59264381..b02b5b57e 100755 --- a/fhem/fhem.pl +++ b/fhem/fhem.pl @@ -2518,7 +2518,7 @@ CommandAttr($$) } if($attrName eq "IODev" && (!$a[2] || !defined($defs{$a[2]}))) { - push @rets,"$sdev: unknown IODev specified"; + push @rets,"$sdev: unknown IODev $a[2] specified"; next; }