diff --git a/fhem/CHANGED b/fhem/CHANGED index 407916a77..a21a2855f 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. + - new: 83_IOhomecontrol: control IOhomecontrol devices via REST API - feature: 31_PLAYBULB: add support for Candle S Firmware 1.4 - feature: 73_GardenaSmartBridge: add attribut disabledForInterval - new: 73_WaterCalculator.pm: New module for water consumption and cost diff --git a/fhem/FHEM/83_IOhomecontrol.pm b/fhem/FHEM/83_IOhomecontrol.pm new file mode 100644 index 000000000..fcc61dd55 --- /dev/null +++ b/fhem/FHEM/83_IOhomecontrol.pm @@ -0,0 +1,412 @@ +# $Id$ + +############################################################################## +# +# 83_IOhomecontrol.pm +# Copyright by Dr. Boris Neubert +# e-mail: omega at online dot de +# +# This file is part of fhem. +# +# Fhem is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# Fhem is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with fhem. If not, see . +# +############################################################################## + +package main; + + +use strict; +use warnings; +use HttpUtils; +use JSON; +#use Data::Dumper; + +##################################### +sub IOhomecontrol_Initialize($) { + my ($hash) = @_; + + $hash->{DefFn} = "IOhomecontrol_Define"; + $hash->{UndefFn} = "IOhomecontrol_Undef"; + $hash->{GetFn} = "IOhomecontrol_Get"; + $hash->{SetFn} = "IOhomecontrol_Set"; + $hash->{parseParams} = 1; + #$hash->{AttrFn} = "IOhomecontrol_Attr"; + #$hash->{AttrList}= ""; +} + +##################################### +sub IOhomecontrol_Define($$) { + + # define IOhomecontrol + my ($hash, $argref, undef) = @_; + + my @def= @{$argref}; + if($#def != 4) { + my $msg = "wrong syntax: define IOhomecontrol "; + Log 2, $msg; + return $msg; + } + + my $name = $def[0]; + my $unused = $def[2]; + my $host = $def[3]; + my $pwfile = $def[4]; + + $hash->{"host"}= $host; + $hash->{"pwfile"}= $pwfile; + $hash->{fhem}{".token"}= undef; + $hash->{fhem}{".scenes"}= undef; + + $hash->{STATE} = "Initialized"; + + return undef; +} + + +##################################### +sub IOhomecontrol_Undef($$) { + return undef; +} + +##################################### +# Internals +##################################### + +sub IOhomecontrol_Exec($$$$) { + + my ($hash, $api, $action, $params) = @_; + my $name = $hash->{NAME}; + my $host = $hash->{"host"}; + my $token = $hash->{fhem}{".token"}; + + # build header + my $header = { + "Accept" => "application/json", + "Content-Type" => "application/json;charset=utf-8", + }; + if(defined($token)) { + $header->{"Authorization"} = "Bearer $token"; + }; + + # build payload + my $payload = { + "action" => $action, + "params" => $params, + }; + my $json = encode_json $payload; + #Debug "IOhomecontrol $name: sending $json"; + + # build HTTP request + my $httpParams = { + url => "http://$host/api/v1/$api", + timeout => 2, + method => "POST", + noshutdown => 1, + keepalive => 0, + httpversion => "1.1", + header => $header, + data => $json, + }; + + my ($err, $data)= HttpUtils_BlockingGet($httpParams); + + if(defined($err) && $err) { + Log3 $hash, 2, "IOhomecontrol $name returned error: $err"; + return undef; + } else { + if(defined($data) && $data) { + # strip junk from the beginning + $data =~ s/^\)\]\}\',//; + #Debug "IOhomecontrol $name: data $data"; + my $result = decode_json $data; + #Debug Dumper $result; + my $errorsref= $result->{errors}; + my @errors= @{$errorsref}; + $err= ""; + if(@errors) { + $err= join(" ", @errors); + Log3 $hash, 2, "IOhomecontrol $name: API $api, action $action returned errors ($err)."; + }; + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "deviceStatus", $result->{deviceStatus}); + readingsBulkUpdate($hash, "errors", $err); + readingsEndUpdate($hash, 1); + return undef if(@errors); + return $result; # this is a hash reference + } else { + Log3 $hash, 2, "IOhomecontrol $name returned no data."; + return undef; + } + } + +} + +##################################### + +sub IOhomecontrol_getPassword($) { + my $hash = shift; + + my $pwfile= $hash->{"pwfile"}; + if(open(PWFILE, $pwfile)) { + my @contents= ; + close(PWFILE); + return undef unless @contents; + my $password = $contents[0]; + chomp $password; + return $password; + } else { + return undef; + } + +} + +sub IOhomecontrol_Login($) { + my $hash = shift; + my $name = $hash->{NAME}; + + Log3 $hash, 4, "IOhomecontrol $name: Logging in..."; + my $password = IOhomecontrol_getPassword($hash); + if(!defined($password)) { + Log3 $hash, 2, "IOhomecontrol $name: No password."; + return 0; + } + my $params = { "password" => $password }; + my $result= IOhomecontrol_Exec($hash, "auth", "login", $params); + if(defined($result)) { + my $token= $result->{token}; + Log3 $hash, 4, "IOhomecontrol $name got token: $token"; + $hash->{fhem}{".token"}= $token; + return 1; + } + return 0; +} + +sub IOhomecontrol_Logout($) { + my $hash = shift; + my $name = $hash->{NAME}; + + Log3 $hash, 4, "IOhomecontrol $name: Logging out..."; + my $params = { }; + my $result= IOhomecontrol_Exec($hash, "auth", "logout", $params); + if(defined($result)) { + Log3 $hash, 4, "IOhomecontrol $name logged out."; + $hash->{fhem}{".token"}= undef; + } + return undef; +} + +sub IOhomecontrol_Action($$$$) { + my ($hash, $api, $action, $params) = @_; + my $name = $hash->{NAME}; + + Log3 $hash, 4, "IOhomecontrol $name: API $api, action $action"; + if(IOhomecontrol_Login($hash)) { + my $result= IOhomecontrol_Exec($hash, $api, $action, $params); + IOhomecontrol_Logout($hash); + return $result; + } + return undef; +} + + +##################################### +sub IOhomecontrol_makeScenes($) { + my $hash= shift; + + my $scenes= $hash->{fhem}{".scenes"}; + if(!defined($scenes)) { + $scenes= IOhomecontrol_getScenes($hash); + $hash->{fhem}{".scenes"} = $scenes; + } + my $sc= {}; + if(defined($scenes)) { + my $data= $scenes->{data}; + #Debug "data: " . Dumper $data; + foreach my $item (@{$data}) { + #Debug "data item: " . Dumper $item; + my $name= $item->{name}; + my $id= $item->{id}; + #Debug "$id: $name"; + $sc->{$id}= $name; + } + my $sns= ""; + foreach my $id (sort keys %{$sc}) { + $sns.="," if($sns); + $sns.= sprintf("%d: %s", $id, $sc->{$id}); + } + readingsSingleUpdate($hash, "scenes", $sns, 1); + } + return $sc; # a hash id => name +} + +sub IOhomecontrol_getScenes($) { + my $hash= shift; + my $scenes= IOhomecontrol_Action($hash, "scenes", "get", {}); + #Debug Dumper $scenes; + return $scenes; +} + +sub IOhomecontrol_runSceneById($$$) { + my ($hash, $id, $name)= @_; + IOhomecontrol_Action($hash, "scenes", "run", { id => $id }); + readingsSingleUpdate($hash, "lastScene", $name, 1); +} + +##################################### +sub IOhomecontrol_Get($@) { + my ($hash, $argsref, undef) = @_; + + my @a= @{$argsref}; + return "get needs at least one parameter" if(@a < 2); + + my $name = $a[0]; + my $cmd= $a[1]; + my $arg = ($a[2] ? $a[2] : ""); + my @args= @a; shift @args; shift @args; + + my $answer= ""; + if($cmd eq "scenes") { + $hash->{fhem}{".scenes"}= undef; # forget scenes forces get from device + my $sc= IOhomecontrol_makeScenes($hash); + foreach my $id (sort keys %{$sc}) { + $answer.="\n" if($answer); + $answer.= sprintf("%2d: %s", $id, $sc->{$id}); + } + } else { + return "Unknown argument $cmd, choose one of scenes:noArg"; + } + + return $answer; +} + + +##################################### + +# sub IOhomecontrol_Attr($@) { +# +# my @a = @_; +# my $hash= $defs{$a[1]}; +# my $name= $hash->{NAME}; +# +# if($a[0] eq "set") { +# if($a[2] eq "") { +# } +# } +# +# return undef; +# } + + +##################################### +sub IOhomecontrol_Set($@) { + my ($hash, $argsref, undef) = @_; + + my @a= @{$argsref}; + return "set needs at least one parameter" if(@a < 2); + + my $name = shift @a; + my $cmd= shift @a; + + my $usage= "Unknown argument $cmd, choose one of scene"; + if($cmd eq "scene") { + if($#a) { + return "Command scene needs exactly one argument."; + } else { + my $sc= IOhomecontrol_makeScenes($hash); + my $id= $a[0]; + if($id !~ /^\d+$/) { + #Debug "IOhomecontrol $name: looking up scene $id by name..."; + my %cs= reverse %{$sc}; + $id= $cs{$id}; + } + my $sn= $sc->{$id}; + if(defined($sn)) { + Log3 $hash, 4, "IOhomecontrol $name: running scene id $id, name $sn"; + IOhomecontrol_runSceneById($hash, $id, $sn); + } else { + return "No such scene $id"; + } + } + } else { + return $usage + } + + return undef; + +} + +##################################### + +1; + +=pod +=item device +=item summary control IOhomecontrol devices via REST API +=item summary_DE IOhomecontrol-Geräte mittels REST-API steuern +=begin html + + +

IOhomecontrol

+
    + + + Define

    +
      + define <name> IOhomecontrol <model> <host> <pwfile>

      + + Defines a IOhomecontrol device. <model> is a placeholder for future amendments. <host> is the IP address or hostname of the IOhomecontrol device. <pwfile> is a file that contains the password to log into the device.

      + + Example: +
        + define velux IOhomecontrol KLF200 192.168.0.91 /opt/fhem/etc/veluxpw.txt
        +
      +

      +
    + + + Set

    +
      + set <name> scene <id> +

      + Runs the scene identified by <id> which can be either the numeric id of the scene or the scene's name. +

      + Examples: +
        + set velux scene 1
        + set velux scene "all shutters down"
        +
      +
      + Scene names with blanks must be enclosed in double quotes. +

      +
    + + + + Get

    +
      + get <name> scenes +

      + Retrieves the ids and names of the scenes from the device. +

      + Example: +
        + get velux scenes
        +
      +
    +

    + +
+ +=end html +=cut diff --git a/fhem/MAINTAINER.txt b/fhem/MAINTAINER.txt index f263d5486..186c11f01 100644 --- a/fhem/MAINTAINER.txt +++ b/fhem/MAINTAINER.txt @@ -341,6 +341,7 @@ FHEM/82_LGTV.pm markusbloch Multimedia FHEM/82_LGTV_IP12.pm markusbloch Multimedia FHEM/82_LGTV_WebOS.pm CoolTux Multimedia FHEM/82_M232Voltage.pm neubert Sonstige Systeme +FHEM/83_IOhomecontrol.pm neubert Sonstige Systeme FHEM/87_WS2000.pm tdressler Sonstiges FHEM/86_Robonect.pm andi291 Sonstige Systeme FHEM/88_ALL4000T.pm sachag Sonstiges