| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855 |
- # $Id: 26_tahoma.pm 16851 2018-06-11 21:30:34Z mike3436 $
- ################################################################
- #
- # Copyright notice
- #
- # (c) 2015 mike3436 (mike3436@online.de)
- #
- # This script 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.
- #
- # The GNU General Public License can be found at
- # http://www.gnu.org/copyleft/gpl.html.
- # A copy is found in the textfile GPL.txt and important notices to the license
- # from the author is found in LICENSE.txt distributed with these scripts.
- #
- # This script 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.
- #
- # This copyright notice MUST APPEAR in all copies of the script!
- #
- ################################################################
- # $Id: 26_tahoma.pm
- #
- # 2014-08-01 V 0100 first Version using XML Interface
- # 2015-08-16 V 0200 communication to server changes from xml to json
- # 2015-08-16 V 0201 some standard requests after login which are not neccessary disabled (so the actual requests are not equal to flow of iphone app)
- # 2016-02-14 V 0202 bugs forcing some startup warning messages fixed
- # 2016-02-20 V 0203 perl exception while parsing json string captured
- # 2016-02-24 V 0204 commands open,close,my,stop and setClosure added
- # 2016-04-24 V 0205 commands taken from setup
- # 2016-06-16 V 0206 updateDevices called for devices created before setup has been read
- # 2016-11-15 V 0207 BLOCKING=0 can be used, all calls asynchron, attribut levelInvert inverts RollerShutter position
- # 2016-11-29 V 0208 HttpUtils used instead of LWP::UserAgent, BLOCKING=0 set as default, umlaut can be used in Tahoma names
- # 2016-12-15 V 0209 perl warnings during startup and login eliminated
- # 2017-01-08 V 0210 tahoma_cancelExecutions: cancel command added
- # 2017-01-10 V 0211 tahoma_getStates: read all states based on table {setup}{devices}[n]{definition}{states}
- # 2017-01-24 V 0212 tahoma_getStates: read all states recovered
- # 2017-01-24 V 0212 start scene with launchActionGroup so cancel is working on scenes now
- # 2017-01-24 V 0212 Attribut interval used to disable or enable refreshAllstates
- # 2017-01-24 V 0212 Setup changes recognized for reading places
- # 2017-03-23 V 0213 username and password stored encrypted
- # 2017-05-07 V 0214 encryption can be disabled by new attribut cryptLoginData
- # 2017-05-07 V 0214 correct parameters of setClosureAndLinearSpeed caused syntax error
- # 2017-07-01 V 0215 creation of fid and device names for first autocreate extended
- # 2017-07-08 V 0215 login delay increased automatically up to 160s if login failed
- # 2017-07-08 V 0215 default set commands on devices without commands deleted
- # 2017-10-08 V 0216 group definition added
- # 2018-05-10 V 0217 disable activated on devices
- # 2018-05-25 V 0218 keepalive of http connection corrected
- # 2018-06-01 V 0219 new Attributes for time interval of getEvents, getStates and refreshAllStates
- # 2018-06-11 V 0220 HttpUtils_Close before login, some newer Debug outputs deleted, Apply command separated, command responds verified
- package main;
- use strict;
- use warnings;
- use utf8;
- use Encode qw(decode_utf8);
- use JSON;
- #use Data::Dumper;
- use Time::HiRes qw(time);
- use HttpUtils;
- sub tahoma_parseGetSetupPlaces($$);
- sub tahoma_UserAgent_NonblockingGet($);
- sub tahoma_encode_utf8($);
- my $hash_;
- sub tahoma_Initialize($)
- {
- my ($hash) = @_;
- $hash->{DefFn} = "tahoma_Define";
- $hash->{NOTIFYDEV} = "global";
- $hash->{NotifyFn} = "tahoma_Notify";
- $hash->{UndefFn} = "tahoma_Undefine";
- $hash->{SetFn} = "tahoma_Set";
- $hash->{GetFn} = "tahoma_Get";
- $hash->{AttrFn} = "tahoma_Attr";
- $hash->{AttrList} = "IODev ".
- "blocking ".
- "debug:1 ".
- "disable:1 ".
- "interval ".
- "intervalRefresh ".
- "intervalEvents ".
- "intervalStates ".
- "logfile ".
- "url ".
- "placeClasses ".
- "levelInvert ".
- "cryptLoginData ".
- "userAgent ";
- $hash->{AttrList} .= $readingFnAttributes;
- }
- #####################################
- sub tahoma_fhemIdFromDevice($)
- {
- my @device = split "/", shift;
- $device[-1] =~ s/\W/_/g;
- return $device[-1] if (@device <= 4);
- $device[-2] =~ s/\W/_/g;
- return $device[-2].'_'.$device[-1] if (@device <= 5);;
- $device[-3] =~ s/\W/_/g;
- return $device[-3].'_'.$device[-2].'_'.$device[-1];
- }
- sub tahoma_fhemIdFromOid($)
- {
- my @oid = split "-", shift;
- $oid[0] =~ s/\W/_/g;
- return $oid[0];
- }
- my $groupId = 123001;
- sub tahoma_Define($$)
- {
- my ($hash, $def) = @_;
- my @a = split("[ \t][ \t]*", $def);
- my $ModuleVersion = "0220";
-
- my $subtype;
- my $name = $a[0];
- if( $a[2] eq "DEVICE" && @a == 4 ) {
- $subtype = "DEVICE";
- my $device = $a[3];
- my $fid = tahoma_fhemIdFromDevice($device);
- $hash->{device} = $device;
- $hash->{fid} = $fid;
- #$hash->{INTERVAL} = 0;
- my $d = $modules{$hash->{TYPE}}{defptr}{"$fid"};
- return "device $device already defined as $d->{NAME}" if( defined($d) && $d->{NAME} ne $name );
- $modules{$hash->{TYPE}}{defptr}{"$fid"} = $hash;
- } elsif( $a[2] eq "PLACE" && @a == 4 ) {
- $subtype = "PLACE";
- my $oid = $a[@a-1];
- my $fid = tahoma_fhemIdFromOid($oid);
- $hash->{oid} = $oid;
- $hash->{fid} = $fid;
- #$hash->{INTERVAL} = 0;
- my $d = $modules{$hash->{TYPE}}{defptr}{"$fid"};
- return "place oid $oid already defined as $d->{NAME}" if( defined($d) && $d->{NAME} ne $name );
- $modules{$hash->{TYPE}}{defptr}{"$fid"} = $hash;
-
- } elsif( $a[2] eq "GROUP" && @a == 4 ) {
- $subtype = "GROUP";
- my $oid = $a[@a-1];
- my $fid = 'group' . "$groupId";
- $groupId++;
- $hash->{oid} = $oid;
- $hash->{fid} = $fid;
- #$hash->{INTERVAL} = 0;
- my $d = $modules{$hash->{TYPE}}{defptr}{"$fid"};
- return "group oid $oid already defined as $d->{NAME}" if( defined($d) && $d->{NAME} ne $name );
- $modules{$hash->{TYPE}}{defptr}{"$fid"} = $hash;
- } elsif( $a[2] eq "SCENE" && @a == 4 ) {
- $subtype = "SCENE";
- my $oid = $a[@a-1];
- my $fid = tahoma_fhemIdFromOid($oid);
- $hash->{oid} = $oid;
- $hash->{fid} = $fid;
- #$hash->{INTERVAL} = 0;
- my $d = $modules{$hash->{TYPE}}{defptr}{"$fid"};
- return "scene oid $oid already defined as $d->{NAME}" if( defined($d) && $d->{NAME} ne $name );
- $modules{$hash->{TYPE}}{defptr}{"$fid"} = $hash;
- } elsif( $a[2] eq "ACCOUNT" && @a == 5 ) {
- $subtype = "ACCOUNT";
- my $username = $a[@a-2];
- my $password = $a[@a-1];
-
- $hash->{Clients} = ":tahoma:";
- $hash->{helper}{username} = $username;
- $hash->{helper}{password} = $password;
- $hash->{BLOCKING} = 0;
- $hash->{VERSION} = $ModuleVersion;
- $hash->{getEventsInterval} = 2;
- $hash->{refreshStatesInterval} = 120;
- $hash->{getStatesInterval} = 0;
- } else {
- return "Usage: define <name> tahoma device\
- define <name> tahoma ACCOUNT username password\
- define <name> tahoma DEVICE id\
- define <name> tahoma SCENE oid username password\
- define <name> tahoma PLACE oid" if(@a < 4 || @a > 5);
- }
- $hash->{NAME} = $name;
- $hash->{SUBTYPE} = $subtype;
- $hash->{STATE} = "Initialized";
- if( $init_done ) {
- tahoma_connect($hash) if( $hash->{SUBTYPE} eq "ACCOUNT" );
- tahoma_initDevice($hash) if( $hash->{SUBTYPE} eq "DEVICE" );
- tahoma_initDevice($hash) if( $hash->{SUBTYPE} eq "PLACE" );
- tahoma_initDevice($hash) if( $hash->{SUBTYPE} eq "GROUP" );
- tahoma_initDevice($hash) if( $hash->{SUBTYPE} eq "SCENE" );
- }
- return undef;
- }
- sub tahoma_Notify($$)
- {
- my ($hash,$dev) = @_;
- return if($dev->{NAME} ne "global");
- return if(!grep(m/^INITIALIZED|REREADCFG$/, @{$dev->{CHANGED}}));
- if( $hash->{SUBTYPE} eq "ACCOUNT" )
- {
- my $name = $hash->{NAME};
- my $username = $hash->{helper}{username};
- my $password = $hash->{helper}{password};
- if ((defined $attr{$name}{cryptLoginData}) && (not $attr{$name}{cryptLoginData}))
- {
- $username = tahoma_decrypt($username);
- $password = tahoma_decrypt($password);
- }
- else
- {
- $username = tahoma_encrypt($username);
- $password = tahoma_encrypt($password);
- }
- $hash->{DEF} = "$hash->{SUBTYPE} $username $password";
- }
-
- tahoma_connect($hash) if( $hash->{SUBTYPE} eq "ACCOUNT" );
- tahoma_initDevice($hash) if( $hash->{SUBTYPE} eq "DEVICE" );
- tahoma_initDevice($hash) if( $hash->{SUBTYPE} eq "PLACE" );
- tahoma_initDevice($hash) if( $hash->{SUBTYPE} eq "GROUP" );
- tahoma_initDevice($hash) if( $hash->{SUBTYPE} eq "SCENE" );
- }
- sub tahoma_Undefine($$)
- {
- my ($hash, $arg) = @_;
- delete( $modules{$hash->{TYPE}}{defptr}{"$hash->{fid}"} ) if( $hash->{SUBTYPE} eq "DEVICE" );
- delete( $modules{$hash->{TYPE}}{defptr}{"$hash->{fid}"} ) if( $hash->{SUBTYPE} eq "PLACE" );
- delete( $modules{$hash->{TYPE}}{defptr}{"$hash->{fid}"} ) if( $hash->{SUBTYPE} eq "GROUP" );
- delete( $modules{$hash->{TYPE}}{defptr}{"$hash->{fid}"} ) if( $hash->{SUBTYPE} eq "SCENE" );
- return undef;
- }
- sub tahoma_login($)
- {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 3, "$name: tahoma_login";
- HttpUtils_Close($hash);
- $hash->{logged_in} = undef;
- $hash->{startup_run} = undef;
- $hash->{startup_done} = undef;
- $hash->{url} = "https://www.tahomalink.com/enduser-mobile-web/externalAPI/json/";
- $hash->{url} = $attr{$name}{url} if (defined $attr{$name}{url});
- $hash->{userAgent} = "TaHoma/7980 CFNetwork/758.5.3 Darwin/15.6.0";
- $hash->{userAgent} = $attr{$name}{userAgent} if (defined $attr{$name}{userAgent});
- $hash->{timeout} = 10;
- $hash->{HTTPCookies} = undef;
- $hash->{loginRetryTimer} = 5 if (!defined $hash->{loginRetryTimer});
- $hash->{loginRetryTimer} *= 2 if ($hash->{loginRetryTimer} < 160);
-
- Log3 $name, 2, "$name: login start";
- tahoma_UserAgent_NonblockingGet({
- timeout => 10,
- noshutdown => 1,
- hash => $hash,
- page => 'login',
- data => {'userId' => tahoma_decrypt($hash->{helper}{username}) , 'userPassword' => tahoma_decrypt($hash->{helper}{password})},
- callback => \&tahoma_dispatch,
- nonblocking => 1,
- });
- }
-
- my @startup_pages = ( 'getEndUser',
- 'getSetup',
- 'getActionGroups',
- #'/../../enduserAPI/setup/interactiveNotifications',
- #'/../../enduserAPI/setup/interactiveNotifications/history',
- #'getCalendarDayList',
- #'getCalendarRuleList',
- #'/../../enduserAPI/conditionGroups',
- #'getScheduledExecutions',
- #'getHistory',
- #'getSetupTriggers',
- #'getUserPreferences',
- #'getSetupOptions',
- #'getAvailableProtocolsType',
- #'getActiveProtocolsType',
- #'getSetupQuota?quotaId=smsCredit',
- #'getSetupDawnAndDuskTimes',
- '../../enduserAPI/setup/gateways',
- #'../../enduserAPI/setup/gateways',
- #'../../enduserAPI/setup/subscribe/notification/apple/com.somfy.iPhoneTaHoma',
- #'../../enduserAPI/setup/subscribe/notification/devices/tahoma',
- #'/../../enduserAPI/setup/subscribe/notification/apple/com.somfy.iPhoneTaHoma',
- #'../../enduserAPI/setup/subscribe/notification/devices/tahoma',
- 'getCurrentExecutions',
- 'refreshAllStates' );
- sub tahoma_startup($)
- {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_startup";
- return if (!$hash->{logged_in});
- return if ($hash->{startup_done});
-
- if (!defined($hash->{startup_run}))
- {
- $hash->{startup_run} = 0;
- }
- else
- {
- $hash->{startup_run}++;
- if ($hash->{startup_run} >= scalar @startup_pages)
- {
- $hash->{startup_done} = 1;
- return;
- }
- }
- my $page = $startup_pages[$hash->{startup_run}];
- my $subpage = "";
- $subpage = '?gatewayId='.$hash->{gatewayId} if (substr($page, -13) eq 'ProtocolsType');
- $subpage = '?quotaId=smsCredit' if ($page eq 'getSetupQuota');
- $subpage = '/'.$hash->{gatewayId}.'/version' if (substr($page, -8) eq 'gateways');
- tahoma_UserAgent_NonblockingGet({
- timeout => 10,
- noshutdown => 1,
- hash => $hash,
- page => $page,
- subpage => $subpage,
- callback => \&tahoma_dispatch,
- nonblocking => 1,
- });
- }
- sub tahoma_refreshAllStates($)
- {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_refreshAllStates";
- tahoma_UserAgent_NonblockingGet({
- timeout => 10,
- noshutdown => 1,
- hash => $hash,
- page => 'refreshAllStates',
- callback => \&tahoma_dispatch,
- nonblocking => 1,
- });
- }
- sub tahoma_getEvents($)
- {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_getEvents";
- return if(!$hash->{logged_in} && !$hash->{startup_done});
- tahoma_UserAgent_NonblockingGet({
- timeout => 10,
- noshutdown => 1,
- hash => $hash,
- page => 'getEvents',
- method => 'PUSH',
- callback => \&tahoma_dispatch,
- nonblocking => 1,
- });
- }
- sub tahoma_readStatusTimer($)
- {
- my $timestart = time;
- my $timeinfo = "tahoma_readStatusTimer";
- my ($hash) = @_;
- my $name = $hash->{NAME};
- RemoveInternalTimer($hash);
-
- my ($seconds) = gettimeofday();
- $hash->{refreshStatesTimer} = $seconds + 10 if ( (!defined($hash->{refreshStatesTimer})) || (!$hash->{logged_in}) );
-
- if( $hash->{request_active} ) {
- Log3 $name, 3, "$name: request active";
- if( ($timestart - $hash->{request_time}) > 10)
- {
- Log3 $name, 2, "$name: timeout, close ua";
- $hash->{socket} = undef;
- $hash->{request_active} = 0;
- $hash->{logged_in} = 0;
- $hash->{startup_done} = 0;
- }
- }
- elsif( !$hash->{logged_in} ) {
- tahoma_login($hash) if (!(defined $hash->{loginRetryTimer}) || !(defined $hash->{request_time}) || (($timestart - $hash->{request_time}) >= $hash->{loginRetryTimer}));
- $timeinfo = "tahoma_login";
- }
- elsif( !$hash->{startup_done} ) {
- tahoma_startup($hash);
- $timeinfo = "tahoma_startup";
- if ( $hash->{startup_done} ) {
- tahoma_getStates($hash) ;
- $hash->{refreshStatesTimer} = $seconds + $hash->{refreshStatesInterval};
- $hash->{getStatesTimer} = $seconds + $hash->{getStatesInterval};
- $hash->{getEventsTimer} = $seconds + $hash->{getEventsInterval};
- $timeinfo = "tahoma_getStates";
- }
- }
- elsif( ($seconds >= $hash->{refreshStatesTimer}) && ($hash->{refreshStatesInterval} > 0) )
- {
- Log3 $name, 4, "$name: refreshing all states";
- tahoma_refreshAllStates($hash);
- $hash->{refreshStatesTimer} = $seconds + $hash->{refreshStatesInterval};
- $timeinfo = "tahoma_refreshAllStates";
- }
- elsif( ($seconds >= $hash->{getStatesTimer}) && ($hash->{getStatesInterval} > 0) )
- {
- Log3 $name, 4, "$name: get all states";
- tahoma_getStates($hash);
- $hash->{getStatesTimer} = $seconds + $hash->{getStatesInterval};
- $timeinfo = "tahoma_getStates";
- }
- elsif( ($seconds >= $hash->{getEventsTimer}) || ($hash->{getEventsInterval} <= 0) )
- {
- Log3 $name, 4, "$name: refreshing event";
- tahoma_getEvents($hash);
- $hash->{getEventsTimer} = $seconds + $hash->{getEventsInterval};
- $timeinfo = "tahoma_getEvents";
- }
- my $timedelta = time -$timestart;
- if ($timedelta > 0.5)
- {
- $timedelta *= 1000;
- Log3 $name, 3, "$name: $timeinfo took $timedelta ms"
- }
- InternalTimer(gettimeofday()+2, "tahoma_readStatusTimer", $hash, 0);
- }
- sub tahoma_connect($)
- {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 3, "$name: tahoma_connect";
- RemoveInternalTimer($hash);
- tahoma_login($hash);
- my ($seconds) = gettimeofday();
- $hash->{refreshStatesTimer} = $seconds + 10;
- tahoma_readStatusTimer($hash);
- }
- sub tahoma_initDevice($)
- {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- my $subtype = $hash->{SUBTYPE};
- AssignIoPort($hash);
- if(defined($hash->{IODev}->{NAME})) {
- Log3 $name, 3, "$name: I/O device is " . $hash->{IODev}->{NAME};
- } else {
- Log3 $name, 1, "$name: no I/O device";
- }
- my $device;
- if( defined($hash->{device}) ) {
- $device = tahoma_getDeviceDetail( $hash, $hash->{device} );
- #Log3 $name, 4, Dumper($device);
- } elsif( defined($hash->{oid}) ) {
- $device = tahoma_getDeviceDetail( $hash, $hash->{oid} );
- #Log3 $name, 4, Dumper($device);
- }
- if( defined($device) && ($subtype eq 'DEVICE') ) {
- Log3 $name, 4, "$name: I/O device is label=".$device->{label};
- $hash->{inType} = $device->{type};
- $hash->{inLabel} = $device->{label};
- $hash->{inControllable} = $device->{controllableName};
- $hash->{inPlaceOID} = $device->{placeOID};
- $hash->{inClass} = $device->{uiClass};
- $device->{levelInvert} = $attr{$hash->{NAME}}{levelInvert} if (defined $attr{$hash->{NAME}}{levelInvert});
- }
- elsif( defined($device) && ($subtype eq 'PLACE') ) {
- Log3 $name, 4, "$name: I/O device is label=".$device->{label};
- $hash->{inType} = $device->{type};
- $hash->{inLabel} = $device->{label};
- $hash->{inOID} = $device->{oid};
- $hash->{inClass} = 'RollerShutter';
- $hash->{inClass} = $attr{$hash->{NAME}}{placeClasses} if (defined $attr{$hash->{NAME}}{placeClasses});
- }
- elsif( defined($device) && ($subtype eq 'SCENE') ) {
- Log3 $name, 4, "$name: I/O device is label=".$device->{label};
- $hash->{inLabel} = $device->{label};
- $hash->{inOID} = $device->{oid};
- }
- elsif($subtype eq 'GROUP' ) {
- $hash->{inType} = '';
- $hash->{inLabel} = '';
- $hash->{inLabel} = $attr{$hash->{NAME}}{alias} if (defined $attr{$hash->{NAME}}{alias});
- $hash->{inOID} = '';
- $hash->{inClass} = '';
- }
- else
- {
- my $device=$hash->{device};
- $device ||= 'undefined';
- $subtype ||= 'undefined';
- Log3 $name, 3, "$name: unknown device=$device, subtype=$subtype";
- }
- }
- sub tahoma_updateDevices($)
- {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 3, "$name: tahoma_updateDevices";
- return undef if( !$hash->{helper}{devices} ) ;
-
- $hash = $hash->{IODev} if( defined($hash->{IODev}) );
- foreach my $module (keys %{$modules{$hash->{TYPE}}{defptr}}) {
- my $def = $modules{$hash->{TYPE}}{defptr}{"$module"};
- my $subtype = $def->{SUBTYPE};
- if (defined($def->{oid}) && !defined($def->{inType}))
- {
- Log3 $name, 3, "$name: updateDevices oid=$def->{oid}";
- my $device = tahoma_getDeviceDetail( $hash, $def->{oid} );
- if( defined($device) && ($subtype eq 'PLACE') ) {
- Log3 $name, 4, "$name: I/O device is label=".$device->{label};
- $def->{inType} = $device->{type};
- $def->{inLabel} = $device->{label};
- $def->{inOID} = $device->{oid};
- $def->{inClass} = 'RollerShutter';
- $def->{inClass} = $attr{$def->{NAME}}{placeClasses} if (defined $attr{$def->{NAME}}{placeClasses});
- $device->{NAME} = $def->{NAME};
- }
- elsif( defined($device) && ($subtype eq 'SCENE') ) {
- Log3 $name, 4, "$name: I/O device is label=".$device->{label};
- $def->{inLabel} = $device->{label};
- $def->{inOID} = $device->{oid};
- $device->{NAME} = $def->{NAME};
- }
- }
- elsif (defined($def->{device}) && !defined($def->{inType}))
- {
- Log3 $name, 3, "$name: updateDevices device=$def->{device}";
- my $device = tahoma_getDeviceDetail( $hash, $def->{device} );
- if( defined($device) && ($subtype eq 'DEVICE') ) {
- Log3 $name, 4, "$name: I/O device is label=".$device->{label};
- $def->{inType} = $device->{type};
- $def->{inLabel} = $device->{label};
- $def->{inControllable} = $device->{controllableName};
- $def->{inPlaceOID} = $device->{placeOID};
- $def->{inClass} = $device->{uiClass};
- $device->{levelInvert} = $attr{$def->{NAME}}{levelInvert} if (defined $attr{$def->{NAME}}{levelInvert});
- $device->{NAME} = $def->{NAME};
- }
- }
- }
- return undef;
- }
- sub tahoma_getDevices($$)
- {
- my ($hash,$nonblocking) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_getDevices";
- tahoma_UserAgent_NonblockingGet({
- timeout => 10,
- noshutdown => 1,
- hash => $hash,
- page => 'getSetup',
- callback => \&tahoma_dispatch,
- nonblocking => $nonblocking,
- });
- return $hash->{helper}{devices};
- }
- sub tahoma_getDeviceDetail($$)
- {
- my ($hash,$id) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_getDeviceDetails $id";
- $hash = $hash->{IODev} if( defined($hash->{IODev}) );
- foreach my $device (@{$hash->{helper}{devices}}) {
- return $device if( defined($device->{deviceURL}) && ($device->{deviceURL} eq $id) );
- return $device if( defined($device->{oid}) && ($device->{oid} eq $id) );
- }
- Log3 $name, 4, "$name: getDeviceDetails $id not found";
-
- return undef;
- }
- sub tahoma_getStates($)
- {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_getStates";
- my $data = '[';
-
- foreach my $device (@{$hash->{helper}{devices}}) {
- if( defined($device->{deviceURL}) && defined($device->{states}) )
- {
- $data .= ',' if (substr($data, -1) eq '}');
- $data .= '{"deviceURL":"'.$device->{deviceURL}.'","states":[';
- foreach my $state (@{$device->{states}}) {
- $data .= ',' if (substr($data, -1) eq '}');
- $data .= '{"name":"' . $state->{name} . '"}';
- }
- $data .= ']}';
- }
- }
-
- $data .= ']';
- Log3 $name, 5, "$name: tahoma_getStates data=".$data;
-
- tahoma_UserAgent_NonblockingGet({
- timeout => 10,
- noshutdown => 1,
- hash => $hash,
- page => 'getStates',
- data => tahoma_encode_utf8($data),
- callback => \&tahoma_dispatch,
- nonblocking => 1,
- });
-
- }
- sub tahoma_getDeviceList($$$$);
- sub tahoma_getDeviceList($$$$)
- {
- my ($hash,$oid,$placeClasses,$deviceList) = @_;
- #print "tahoma_getDeviceList oid=$oid devices=".scalar @{$deviceList}."\n";
-
- my @classes = split(' ',$placeClasses);
- my $devices = $hash->{helper}{devices};
- foreach my $device (@{$devices}) {
- if ( defined($device->{deviceURL}) && defined($device->{placeOID}) && defined($device->{uiClass}) ) {
- if (( grep { $_ eq $device->{uiClass}} @classes ) && ($device->{placeOID} eq $oid)) {
- push ( @{$deviceList}, { device => $device->{deviceURL}, class => $device->{uiClass}, levelInvert => $device->{levelInvert} } ) if !($attr{$device->{NAME}}{disable});
- #print "tahoma_getDeviceList url=$device->{deviceURL} devices=".scalar @{$deviceList}."\n";
- }
- } elsif ( defined($device->{oid}) && defined($device->{subPlaces}) ) {
- if ($device->{oid} eq $oid)
- {
- foreach my $place (@{$device->{subPlaces}}) {
- tahoma_getDeviceList($hash,$place->{oid},$placeClasses,$deviceList);
- }
- }
- }
- }
- }
- sub tahoma_getGroupList($$$)
- {
- my ($hash,$oid,$deviceList) = @_;
- #print "tahoma_getGroupList oid=$oid devices=".scalar @{$deviceList}."\n";
- my @groupDevices = split(',',$oid);
- foreach my $module (@groupDevices) {
- if (defined($defs{$module}) && defined($defs{$module}{device}) && defined($defs{$module}{inClass})) {
- push ( @{$deviceList}, { device => $defs{$module}{device}, class => $defs{$module}{inClass}, levelInvert => $attr{$module}{levelInvert} } ) if !($attr{$module}{disable});
- }
- }
- }
- sub tahoma_checkCommand($$$$)
- {
- my ($hash,$device,$command,$value) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_checkCommand";
- if (($command eq 'setClosure') && (defined ($device->{levelInvert})))
- {
- $value = 100 - $value if ($device->{levelInvert} && ($value >= 0) && ($value <= 100));
- }
- if (($command eq 'setClosure') && ($value == 100) && (index($hash->{COMMANDS}," close:") > 0))
- {
- $command = 'close';
- $value = '';
- }
- if (($command eq 'setClosure') && ($value == 0) && (index($hash->{COMMANDS}," open:") > 0))
- {
- $command = 'open';
- $value = '';
- }
- return ($command,$value);
- }
- sub tahoma_applyRequest($$$)
- {
- my ($hash,$command,$value) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_applyRequest";
- if ( !defined($hash->{IODev}) || !(defined($hash->{device}) || defined($hash->{oid})) || !defined($hash->{inLabel}) || !defined($hash->{inClass}) ) {
- Log3 $name, 3, "$name: tahoma_applyRequest failed - define error";
- return;
- }
-
- my @devices = ();
- if ( defined($hash->{device}) ) {
- push ( @devices, { device => $hash->{device}, class => $hash->{inClass}, commands => $hash->{COMMANDS}, levelInvert => $attr{$hash->{NAME}}{levelInvert} } );
- } elsif ($hash->{SUBTYPE} eq 'GROUP') {
- tahoma_getGroupList($hash->{IODev},$hash->{oid},\@devices);
- } else {
- tahoma_getDeviceList($hash->{IODev},$hash->{oid},$hash->{inClass},\@devices);
- }
- Log3 $name, 4, "$name: tahoma_applyRequest devices=".scalar @devices;
- foreach my $dev (@devices) {
- Log3 $name, 4, "$name: tahoma_applyRequest devices=$dev->{device} class=$dev->{class}";
- }
-
- return if (scalar @devices < 1);
- my $data = '';
- $value = '' if (!defined($value));
- my $commandChecked = $command;
- my $valueChecked = $value;
- foreach my $device (@devices) {
- ($commandChecked, $valueChecked) = tahoma_checkCommand($hash,$device,$command,$value);
- if (defined($commandChecked) && defined($valueChecked))
- {
- $data .= ',' if substr($data, -1) eq '}';
- $data .= '{"deviceURL":"'.$device->{device}.'",';
- $data .= '"commands":[{"name":"'.$commandChecked.'","parameters":['.$valueChecked.']}]}';
- }
- }
- return if (length $data < 20);
-
- my $dataHead = '{"label":"' . $hash->{inLabel};
- if ($commandChecked eq 'setClosure') {
- $dataHead .= ' - Positionieren auf '.$valueChecked.' % - iPhone","actions":[';
- } elsif ($commandChecked eq 'close') {
- $dataHead .= ' - Schliessen - iPhone","actions":[';
- } elsif ($commandChecked eq 'open') {
- $dataHead .= ' - Oeffnen - iPhone","actions":[';
- } elsif ($commandChecked eq 'setClosureAndLinearSpeed') { #neu fuer setClosureAndLinearSpeed
- $dataHead .= ' - Positionieren auf '.(split(',',$valueChecked))[0].' % - iPhone","actions":['; #neu fuer setClosureAndLinearSpeed
- } else {
- $dataHead .= " - $commandChecked $valueChecked".' - iPhone","actions":[';
- }
- $data = $dataHead . $data . ']}';
- Log3 $name, 3, "$name: tahoma_applyRequest data=".$data;
-
- tahoma_UserAgent_NonblockingGet({
- timeout => 10,
- noshutdown => 1,
- hash => $hash,
- page => 'apply',
- data => tahoma_encode_utf8($data),
- callback => \&tahoma_dispatch,
- nonblocking => 1,
- });
- }
- sub tahoma_scheduleActionGroup($$)
- {
- my ($hash,$delay) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_scheduleActionGroup";
- if ( !defined($hash->{IODev}) || !defined($hash->{oid}) ) {
- Log3 $name, 3, "$name: tahoma_scheduleActionGroup failed - define error";
- return;
- }
- $delay = 0 if(!defined($delay));
-
- tahoma_UserAgent_NonblockingGet({
- timeout => 10,
- noshutdown => 1,
- hash => $hash,
- page => 'scheduleActionGroup',
- subpage => '?oid='.$hash->{oid}.'&delay='.$delay,
- callback => \&tahoma_dispatch,
- nonblocking => 1,
- });
- }
- sub tahoma_launchActionGroup($)
- {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_launchActionGroup";
- if ( !defined($hash->{IODev}) || !defined($hash->{oid}) ) {
- Log3 $name, 3, "$name: tahoma_launchActionGroup failed - define error";
- return;
- }
- tahoma_UserAgent_NonblockingGet({
- timeout => 10,
- noshutdown => 1,
- hash => $hash,
- page => 'launchActionGroup',
- subpage => '?oid='.$hash->{oid},
- callback => \&tahoma_dispatch,
- nonblocking => 1,
- });
- }
- sub tahoma_cancelExecutions($)
- {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_cancelExecutions";
- my $subpage = '';
- if (defined($hash->{IODev}))
- {
- if (defined($hash->{inExecId}) && (length $hash->{inExecId} > 20))
- {
- $subpage = '?execId='.$hash->{inExecId};
- }
- elsif (defined($hash->{inTriggerId}) && (length $hash->{inTriggerId} > 20))
- {
- $subpage = '?triggerId='.$hash->{inTriggerId};
- }
- else
- {
- Log3 $name, 3, "$name: tahoma_cancelExecutions failed - no valid execId or triggerId found";
- return;
- }
- }
- Log3 $name, 3, "$name: tahoma_cancelExecutions subpage=$subpage";
- tahoma_UserAgent_NonblockingGet({
- timeout => 10,
- noshutdown => 1,
- hash => $hash,
- page => 'cancelExecutions',
- subpage => $subpage,
- callback => \&tahoma_dispatch,
- nonblocking => 1,
- });
- }
- sub tahoma_dispatch($$$)
- {
- my ($param, $err, $data) = @_;
- my $hash = $param->{hash};
- my $name = $hash->{NAME};
- my $hashIn = $hash;
-
- $hash = $hash->{IODev} if (defined($hash->{IODev}));
-
- $hash->{request_active} = 0;
-
- if( $err ) {
- Log3 $name, 2, "$name: tahoma_dispatch http request failed: $err";
- $hash->{logged_in} = 0;
- return;
- }
-
- if( $data ) {
- tahoma_GetCookies($hash,$param->{httpheader}) if (!$hash->{logged_in});
-
- $data =~ tr/\r\n//d;
- $data =~ s/\h+/ /g;
- $data =~ s/\\\//\//g;
- Log3 $name, (length $data > 120)?4:5, "$name: tahoma_dispatch data=".decode_utf8($data);
- # perl exception while parsing json string captured
- my $json = {};
- eval { $json = JSON->new->utf8(0)->decode($data); };
- if ($@ || ((ref $json ne 'HASH') && (ref $json ne 'ARRAY')) ) {
- Log3 $name, 3, "$name: tahoma_dispatch json string is faulty" . substr($data,0,40) . ' ...';
- $hash->{lastError} = 'json string is faulty: ' . substr($data,0,40) . ' ...';
- $hash->{logged_in} = 0;
- return;
- }
-
- if( (ref $json eq 'HASH') && ($json->{errorResponse}) ) {
- $hash->{lastError} = $json->{errorResponse}{message};
- $hash->{logged_in} = 0;
- Log3 $name, 3, "$name: tahoma_dispatch error: $hash->{lastError}";
- return;
- }
- if( (ref $json eq 'HASH') && ($json->{error}) ) {
- $hash->{lastError} = $json->{error};
- $hash->{logged_in} = 0;
- Log3 $name, 3, "$name: tahoma_dispatch error: $hash->{lastError}";
- return;
- }
- if( $param->{page} eq 'getEvents' ) {
- tahoma_parseGetEvents($hash,$json);
- } elsif( $param->{page} eq 'apply' ) {
- tahoma_parseApplyRequest($hashIn,$json);
- } elsif( $param->{page} eq 'getSetup' ) {
- tahoma_parseGetSetup($hash,$json);
- } elsif( $param->{page} eq 'refreshAllStates' ) {
- tahoma_parseRefreshAllStates($hash,$json);
- } elsif( $param->{page} eq 'getStates' ) {
- tahoma_parseGetStates($hash,$json);
- } elsif( $param->{page} eq 'login' ) {
- tahoma_parseLogin($hash,$json);
- } elsif( $param->{page} eq 'getActionGroups' ) {
- tahoma_parseGetActionGroups($hash,$json);
- } elsif( $param->{page} eq '../../enduserAPI/setup/gateways' ) {
- tahoma_parseEnduserAPISetupGateways($hash,$json);
- } elsif( $param->{page} eq 'getCurrentExecutions' ) {
- tahoma_parseGetCurrentExecutions($hash,$json);
- } elsif( $param->{page} eq 'scheduleActionGroup' ) {
- tahoma_parseScheduleActionGroup($hashIn,$json);
- } elsif( $param->{page} eq 'launchActionGroup' ) {
- tahoma_parseLaunchActionGroup($hashIn,$json);
- } elsif( $param->{page} eq 'cancelExecutions' ) {
- tahoma_parseCancelExecutions($hash,$json);
- }
- }
- }
- sub tahoma_autocreate($)
- {
- my($hash) = @_;
- my $name = $hash->{NAME};
- if( !$hash->{helper}{devices} ) {
- tahoma_getDevices($hash,1);
- return undef;
- }
- foreach my $d (keys %defs) {
- next if($defs{$d}{TYPE} ne "autocreate");
- return undef if(AttrVal($defs{$d}{NAME},"disable",undef));
- }
-
- Log3 $name, 2, "$name: tahoma_autocreate begin";
- my $autocreated = 0;
- my $devices = $hash->{helper}{devices};
- foreach my $device (@{$devices}) {
- my ($id, $fid, $devname, $define);
- if ($device->{deviceURL}) {
- $id = $device->{deviceURL};
- $fid = tahoma_fhemIdFromDevice($id);
- $devname = "tahoma_". $fid;
- $define = "$devname tahoma DEVICE $id";
- if( defined($modules{$hash->{TYPE}}{defptr}{"$fid"}) ) {
- Log3 $name, 4, "$name: device '$fid' already defined";
- next;
- }
- } elsif ( $device->{oid} ) {
- $id = $device->{oid};
- my $fid = tahoma_fhemIdFromOid($id);
- $devname = "tahoma_". $fid;
- $define = "$devname tahoma PLACE $id" if (!defined $device->{actions});
- $define = "$devname tahoma SCENE $id" if (defined $device->{actions});
- if( defined($modules{$hash->{TYPE}}{defptr}{"$fid"}) ) {
- Log3 $name, 4, "$name: device '$fid' already defined";
- next;
- }
- }
- Log3 $name, 3, "$name: create new device '$devname' for device '$id'";
- my $cmdret= CommandDefine(undef,$define);
- if($cmdret) {
- Log3 $name, 1, "$name: Autocreate: An error occurred while creating device for id '$id': $cmdret";
- } else {
- $cmdret= CommandAttr(undef,"$devname alias room ".$device->{label}) if( defined($device->{label}) && defined($device->{oid}) && !defined($device->{actions}) );
- $cmdret= CommandAttr(undef,"$devname alias scene ".$device->{label}) if( defined($device->{label}) && defined($device->{oid}) && defined($device->{actions}) );
- $cmdret= CommandAttr(undef,"$devname alias $device->{uiClass} ".$device->{label}) if( defined($device->{label}) && defined($device->{states}) );
- $cmdret= CommandAttr(undef,"$devname room tahoma");
- $cmdret= CommandAttr(undef,"$devname IODev $name");
- $cmdret= CommandAttr(undef,"$devname webCmd dim") if( defined($device->{uiClass}) && ($device->{uiClass} eq "RollerShutter") );
- $autocreated++;
- }
- }
- CommandSave(undef,undef) if( $autocreated && AttrVal( "autocreate", "autosave", 1 ) );
- Log3 $name, 2, "$name: tahoma_autocreate end, new=$autocreated";
- }
- sub tahoma_defineCommands($)
- {
- my($hash) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_defineCommands";
-
- my $devices = $hash->{helper}{devices};
- foreach my $device (@{$devices}) {
- my ($id, $fid, $devname, $define);
- if ($device->{deviceURL}) {
- $id = $device->{deviceURL};
- $fid = tahoma_fhemIdFromDevice($id);
- $devname = "tahoma_". $fid;
- $define = "$devname tahoma DEVICE $id";
- my $commandlist = "";
- if( defined $device->{definition}{commands}[0]{commandName} ) {
- $commandlist = "dim:slider,0,1,100 cancel:noArg";
- foreach my $command (@{$device->{definition}{commands}}) {
- $commandlist .= " " . $command->{commandName};
- $commandlist .= ":noArg" if ($command->{nparams} == 0);
- }
- }
- if( defined($modules{$hash->{TYPE}}{defptr}{"$fid"}) ) {
- $modules{$hash->{TYPE}}{defptr}{"$fid"}{COMMANDS} = $commandlist;
- Log3 $name, 4, "$name: tahoma_defineCommands fid=$fid commandlist=$commandlist";
- }
- }
- }
- }
- sub tahoma_parseLogin($$)
- {
- my($hash, $json) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_parseLogin";
- if (ref($json) ne 'HASH')
- {
- Log3 $name, 3, "$name: tahoma_parseLogin response is not a valid hash";
- return;
- }
- if (defined $json->{errorResponse}) {
- $hash->{logged_in} = 0;
- $hash->{STATE} = $json->{errorResponse}{message};
- } else {
- $hash->{inVersion} = $json->{version};
- $hash->{logged_in} = 1;
- $hash->{loginRetryTimer} = 5;
- }
- Log3 $name, 2, "$name: login end, logged_in=".$hash->{logged_in};
- }
- sub tahoma_parseGetEvents($$)
- {
- my($hash, $json) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 5, "$name: tahoma_parseGetEvents";
- $hash->{refresh_event} = $json;
- if( $hash->{logged_in} ) {
- $hash->{STATE} = "Connected";
- } else {
- $hash->{STATE} = "Disconnected";
- }
- if( ref $json eq 'ARRAY' ) {
- #print Dumper($json);
- foreach my $devices ( @{$json} ) {
- if( defined($devices->{deviceURL}) ) {
- #print "\nDevice=$devices->{deviceURL} found\n";
- my $id = $devices->{deviceURL};
- my $fid = tahoma_fhemIdFromDevice($id);
- my $devname = "tahoma_". $fid;
- my $d = $modules{$hash->{TYPE}}{defptr}{"$fid"};
- if( defined($d) )# && $d->{NAME} eq $devname )
- {
- #print "\nDevice=$devices->{deviceURL} updated\n";
- readingsBeginUpdate($d);
- foreach my $state (@{$devices->{deviceStates}}) {
- #print "$devname $state->{name} = $state->{value}\n";
- next if (!defined($state->{name}) || !defined($state->{value}));
- if ($state->{name} eq "core:ClosureState") {
- $state->{value} = 100 - $state->{value} if ($attr{$d->{NAME}}{levelInvert});
- readingsBulkUpdate($d, "state", "dim".$state->{value});
- } elsif ($state->{name} eq "core:OpenClosedState") {
- readingsBulkUpdate($d, "devicestate", $state->{value});
- }
- readingsBulkUpdate($d, (split(":",$state->{name}))[-1], $state->{value});
- }
- my ($seconds) = gettimeofday();
- readingsBulkUpdate( $d, ".lastupdate", $seconds, 0 );
- readingsEndUpdate($d,1);
- }
- }
- elsif( defined($devices->{name}) && (defined($devices->{execId}) || defined($devices->{triggerId})) )
- {
- foreach my $module (keys %{$modules{$hash->{TYPE}}{defptr}})
- {
- my $def = $modules{$hash->{TYPE}}{defptr}{"$module"};
- if (defined($def->{inExecId}) && ($def->{inExecId} eq $devices->{execId}))
- {
- if ($devices->{name} eq 'ExecutionStateChangedEvent')
- {
- $def->{inExecState} = $devices->{newState};
- $def->{inExecId} = 'finished' if ($devices->{newState} == 4);
- $def->{inExecId} = 'canceled' if ($devices->{newState} == 5);
- }
- }
- elsif (defined($def->{inTriggerId}) && ($def->{inTriggerId} eq $devices->{triggerId}))
- {
- $def->{inTriggerState} = $devices->{name};
- $def->{inTriggerId} = 'finished' if ($devices->{name} eq '4');
- $def->{inTriggerId} = 'canceled' if ($devices->{name} eq '5');
- }
- }
- }
- }
- }
-
- }
- sub tahoma_parseApplyRequest($$)
- {
- my($hash, $json) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_parseApplyRequest";
- $hash->{inExecState} = 0;
- if (ref($json) ne 'HASH') {
- Log3 $name, 3, "$name: tahoma_parseApplyRequest response is not a valid hash";
- return;
- }
- if (defined($json->{execId})) {
- $hash->{inExecId} = $json->{execId};
- } else {
- $hash->{inExecId} = "undefined";
- }
- if (defined($json->{events}) && defined($hash->{IODev}))
- {
- tahoma_parseGetEvents($hash->{IODev},$json->{events})
- }
- }
- sub tahoma_parseGetSetup($$)
- {
- my($hash, $json) = @_;
- my $name = $hash->{NAME};
- if (ref($json) ne 'HASH') {
- Log3 $name, 3, "$name: tahoma_parseGetSetup response is not a valid hash";
- return;
- }
- $hash->{gatewayId} = $json->{setup}{gateways}[0]{gatewayId};
- my @devices = ();
- foreach my $device (@{$json->{setup}{devices}}) {
- Log3 $name, 4, "$name: tahoma_parseGetSetup device = $device->{label}";
- push( @devices, $device );
- }
-
- $hash->{helper}{devices} = \@devices;
- if ($json->{setup}{rootPlace}) {
- my $places = $json->{setup}{rootPlace};
- #Log3 $name, 4, "$name: tahoma_parseGetSetup places= " . Dumper($places);
- tahoma_parseGetSetupPlaces($hash, $places);
- }
- tahoma_autocreate($hash);
- tahoma_updateDevices($hash);
- tahoma_defineCommands($hash);
- }
- sub tahoma_parseGetSetupPlaces($$)
- {
- my($hash, $places) = @_;
- my $name = $hash->{NAME};
- #Log3 $name, 4, "$name: tahoma_parseGetSetupPlaces " . Dumper($places);
- my $devices = $hash->{helper}{devices};
-
- if (ref $places eq 'ARRAY') {
- #Log3 $name, 4, "$name: tahoma_parseGetSetupPlaces isArray";
- foreach my $place (@{$places}) {
- push( @{$devices}, $place );
- my $placesNext = $place->{subPlaces};
- tahoma_parseGetSetupPlaces($hash, $placesNext ) if ($placesNext);
- }
- }
- else {
- #Log3 $name, 4, "$name: tahoma_parseGetSetupPlaces isScalar";
- push( @{$devices}, $places );
- my $placesNext = $places->{subPlaces};
- tahoma_parseGetSetupPlaces($hash, $placesNext) if ($placesNext);
- }
- }
- sub tahoma_parseGetActionGroups($$)
- {
- my($hash, $json) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_parseGetActionGroups";
- if (ref($json) ne 'HASH') {
- Log3 $name, 3, "$name: tahoma_parseGetActionGroups response is not a valid hash";
- return;
- }
-
- my $devices = $hash->{helper}{devices};
- foreach my $action (@{$json->{actionGroups}}) {
- push( @{$devices}, $action );
- }
- tahoma_autocreate($hash);
- tahoma_updateDevices($hash);
- tahoma_defineCommands($hash);
- }
- sub tahoma_parseRefreshAllStates($$)
- {
- my($hash, $json) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_parseRefreshAllStates";
- }
- sub tahoma_parseGetStates($$)
- {
- my($hash, $states) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_parseGetStates";
- if (ref($states) ne 'HASH') {
- Log3 $name, 3, "$name: tahoma_parseGetStates response is not a valid hash";
- return;
- }
- if( defined($states->{devices}) ) {
- foreach my $devices ( @{$states->{devices}} ) {
- if( defined($devices->{deviceURL}) ) {
- my $id = $devices->{deviceURL};
- my $fid = tahoma_fhemIdFromDevice($id);
- my $devname = "tahoma_". $fid;
- my $d = $modules{$hash->{TYPE}}{defptr}{"$fid"};
- if( defined($d) )# && $d->{NAME} eq $devname )
- {
- readingsBeginUpdate($d);
- foreach my $state (@{$devices->{states}}) {
- next if (!defined($state->{name}) || !defined($state->{value}));
- if ($state->{name} eq "core:ClosureState") {
- $state->{value} = 100 - $state->{value} if ($attr{$d->{NAME}}{levelInvert});
- readingsBulkUpdate($d, "state", "dim".$state->{value});
- } elsif ($state->{name} eq "core:OpenClosedState") {
- readingsBulkUpdate($d, "devicestate", $state->{value});
- }
- readingsBulkUpdate($d, (split(":",$state->{name}))[-1], $state->{value});
- }
- my ($seconds) = gettimeofday();
- readingsBulkUpdate( $d, ".lastupdate", $seconds, 0 );
- readingsEndUpdate($d,1);
- }
- }
- }
- }
- }
- sub tahoma_parseEnduserAPISetupGateways($$)
- {
- my($hash, $json) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_parseEnduserAPISetupGateways";
- if (ref($json) ne 'HASH') {
- Log3 $name, 3, "$name: tahoma_parseEnduserAPISetupGateways response is not a valid hash";
- return;
- }
-
- eval { $hash->{inGateway} = $json->{result}; };
- eval { $hash->{inGateway} = $json->[0]{gatewayId}; };
- }
- sub tahoma_parseGetCurrentExecutions($$)
- {
- my($hash, $json) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_parseGetCurrentExecutions";
- if (ref($json) ne 'HASH') {
- Log3 $name, 3, "$name: tahoma_parseGetCurrentExecutions response is not a valid hash";
- return;
- }
- }
- sub tahoma_parseScheduleActionGroup($$)
- {
- my($hash, $json) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_parseScheduleActionGroup";
- if (ref($json) ne 'HASH') {
- Log3 $name, 3, "$name: tahoma_parseScheduleActionGroup response is not a valid hash";
- return;
- }
- if (defined $json->{actionGroup})
- {
- $hash->{inTriggerState} = 0;
- if (defined($json->{actionGroup}[0]{triggerId})) {
- $hash->{inTriggerId} = $json->{actionGroup}[0]{triggerId};
- } else {
- $hash->{inTriggerId} = "undefined";
- }
- }
- if (defined($json->{events}) && defined($hash->{IODev}))
- {
- tahoma_parseGetEvents($hash->{IODev},$json->{events})
- }
- }
- sub tahoma_parseLaunchActionGroup($$)
- {
- my($hash, $json) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_parseLaunchActionGroup";
- if (ref($json) ne 'HASH') {
- Log3 $name, 3, "$name: tahoma_parseLaunchActionGroup response is not a valid hash";
- return;
- }
- if (defined $json->{actionGroup})
- {
- $hash->{inExecState} = 0;
- if (defined($json->{actionGroup}[0]{execId})) {
- $hash->{inExecId} = $json->{actionGroup}[0]{execId};
- } else {
- $hash->{inExecId} = "undefined";
- }
- }
- if (defined($json->{events}) && defined($hash->{IODev}))
- {
- tahoma_parseGetEvents($hash->{IODev},$json->{events})
- }
- }
- sub tahoma_parseCancelExecutions($$)
- {
- my($hash, $json) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 4, "$name: tahoma_parseCancelExecutions";
- }
- sub tahoma_Get($$@)
- {
- my ($hash, $name, $cmd) = @_;
- my $list;
- if( $hash->{SUBTYPE} eq "DEVICE" ) {
- $list = "updateAll:noArg";
- if( $cmd eq "updateAll" ) {
- my ($seconds) = gettimeofday();
- $hash = $hash->{IODev} if (defined ($hash->{IODev}));
- $hash->{refreshStatesTimer} = $seconds;
- return undef;
- }
- } elsif( $hash->{SUBTYPE} eq "SCENE"
- || $hash->{SUBTYPE} eq "GROUP"
- || $hash->{SUBTYPE} eq "PLACE" ) {
- $list = "";
- } elsif( $hash->{SUBTYPE} eq "ACCOUNT" ) {
- $list = "devices:noArg reset:noArg";
- if( $cmd eq "devices" ) {
- my $devices = tahoma_getDevices($hash,0);
- my $ret;
- foreach my $device (@{$devices}) {
- $ret .= "$device->{deviceURL}\t".$device->{label}."\t$device->{uiClass}\t$device->{controllable}\t\n" if ($device->{deviceURL});
- $ret .= "$device->{oid}\t".$device->{label}."\n" if ($device->{oid});
- }
- $ret = "id\t\t\t\tname\t\t\tuiClass\t\tcontrollable\n" . $ret if( $ret );
- $ret = "no devices found" if( !$ret );
- return $ret;
- }
- elsif( $cmd eq "reset" ) {
- HttpUtils_Close($hash);
- $hash->{logged_in} = undef;
- $hash->{loginRetryTimer} = undef;
- return "connection closed";
- }
- }
- return "Unknown argument $cmd, choose one of $list";
- }
- sub tahoma_Set($$@)
- {
- my ($hash, $name, $cmd, $val) = @_;
- #Log3 $name, 3, "$name: tahoma_Set $cmd $val $hash->{SUBTYPE} $hash->{COMMANDS}";
- my $list = "";
- if( $hash->{SUBTYPE} eq "DEVICE" ||
- $hash->{SUBTYPE} eq "GROUP" ||
- $hash->{SUBTYPE} eq "PLACE" ) {
- $list = "dim:slider,0,1,100 setClosure open:noArg close:noArg my:noArg stop:noArg cancel:noArg";
- $list = $hash->{COMMANDS} if (defined $hash->{COMMANDS});
- if( $cmd eq "cancel" ) {
- tahoma_cancelExecutions($hash);
- return undef;
- }
- $cmd = "setClosure" if( $cmd eq "dim" );
-
- my @commands = split(" ",$list);
- foreach my $command (@commands)
- {
- if( $cmd eq (split(":",$command))[0])
- {
- tahoma_applyRequest($hash,$cmd,$val) if !($attr{$hash->{NAME}}{disable});
- return undef;
- }
- }
- }
-
- if( $hash->{SUBTYPE} eq "SCENE") {
- $list = "start:noArg startAt cancel:noArg";
- if( $cmd eq "start" ) {
- tahoma_launchActionGroup($hash) if !($attr{$hash->{NAME}}{disable});
- return undef;
- }
-
- if( $cmd eq "startAt" ) {
- tahoma_scheduleActionGroup($hash,$val) if !($attr{$hash->{NAME}}{disable});
- return undef;
- }
-
- if( $cmd eq "cancel" ) {
- tahoma_cancelExecutions($hash);
- return undef;
- }
- }
- if( $hash->{SUBTYPE} eq "ACCOUNT") {
- $list = "cancel:noArg reset:noArg refreshAllStates:noArg getStates:noArg";
- if( $cmd eq "cancel" ) {
- tahoma_cancelExecutions($hash);
- return undef;
- }
- elsif( $cmd eq "reset" ) {
- HttpUtils_Close($hash);
- $hash->{logged_in} = undef;
- $hash->{loginRetryTimer} = undef;
- return undef;
- }
- elsif( $cmd eq "refreshAllStates" ) {
- tahoma_refreshAllStates($hash);
- return undef;
- }
- elsif( $cmd eq "getStates" ) {
- tahoma_getStates($hash);
- return undef;
- }
- }
-
- return "Unknown argument $cmd, choose one of $list";
- }
- sub tahoma_Attr($$$)
- {
- my ($cmd, $name, $attrName, $attrVal) = @_;
- Log3 $name, 3, "$name: tahoma_Attr $cmd $attrName $attrVal";
-
- my $orig = $attrVal;
- if( $attrName eq "interval" ) {
- my $hash = $defs{$name};
- return "Attribut 'interval' only usable for type ACCOUNT" if $hash->{SUBTYPE} ne "ACCOUNT";
- $attrVal = defined $attrVal ? int($attrVal) : 0;
- $attrVal = int($attrVal);
- $attrVal = 120 if ($attrVal < 120 && $attrVal != 0);
- $hash->{refreshStatesInterval} = $attrVal ? $attrVal / 2 : 120;
- $hash->{getStatesInterval} = $attrVal;
- } elsif( $attrName eq "intervalRefresh" ) {
- my $hash = $defs{$name};
- return "Attribut 'intervalRefresh' only usable for type ACCOUNT" if $hash->{SUBTYPE} ne "ACCOUNT";
- $attrVal = defined $attrVal ? int($attrVal) : 120;
- $attrVal = 60 if ($attrVal < 60 && $attrVal != 0);
- $hash->{refreshStatesInterval} = $attrVal;
- } elsif( $attrName eq "intervalStates" ) {
- my $hash = $defs{$name};
- return "Attribut 'intervalStates' only usable for type ACCOUNT" if $hash->{SUBTYPE} ne "ACCOUNT";
- $attrVal = defined $attrVal ? int($attrVal) : 0;
- $attrVal = int($attrVal);
- $attrVal = 120 if ($attrVal < 120 && $attrVal != 0);
- $hash->{getStatesInterval} = $attrVal;
- } elsif( $attrName eq "intervalEvents" ) {
- my $hash = $defs{$name};
- return "Attribut 'intervalEvents' only usable for type ACCOUNT" if $hash->{SUBTYPE} ne "ACCOUNT";
- $attrVal = defined $attrVal ? int($attrVal) : 2;
- $attrVal = int($attrVal);
- $attrVal = 2 if ($attrVal < 2 && $attrVal != 0);
- $hash->{getEventsInterval} = $attrVal;
- } elsif( $attrName eq "disable" ) {
- my $hash = $defs{$name};
- RemoveInternalTimer($hash);
- if( $cmd eq "set" && $attrVal ne "0" ) {
- } else {
- $attr{$name}{$attrName} = 0;
- }
- } elsif( $attrName eq "blocking" ) {
- my $hash = $defs{$name};
- return "Attribut 'blocking' only usable for type ACCOUNT" if $hash->{SUBTYPE} ne "ACCOUNT";
- $attrVal = defined $attrVal ? int($attrVal) : 0;
- $hash->{BLOCKING} = $attrVal;
- } elsif( $attrName eq "placeClasses" ) {
- my $hash = $defs{$name};
- return "Attribut 'placeClasses' only usable for type PLACE" if $hash->{SUBTYPE} ne "PLACE";
- $attrVal = defined $attrVal ? $attrVal : 'RollerShutter';
- $hash->{inClass} = $attrVal;
- }
- elsif ( $attrName eq "levelInvert" ) {
- my $hash = $defs{$name};
- return "Attribut 'placeClasses' only usable for type DEVICE" if $hash->{SUBTYPE} ne "DEVICE";
- $attrVal = defined $attrVal ? int($attrVal) : 0;
- my $device = tahoma_getDeviceDetail( $hash, $hash->{device} );
- $device->{levelInvert} = $attrVal if (defined $device);
- }
-
- if( $cmd eq "set" ) {
- if( $orig ne $attrVal ) {
- $attr{$name}{$attrName} = $attrVal;
- return $attrName ." set to ". $attrVal;
- }
- }
- return;
- }
- sub tahoma_UserAgent_NonblockingGet($)
- {
- my ($param) = @_;
- my ($hash) = $param->{hash};
- $hash = $hash->{IODev} if (defined ($hash->{IODev}));
-
- # restore parameter from last HttpUtils call
- if (defined $hash->{paramHash} && $hash->{paramHash}{keepalive} && !$hash->{request_active})
- {
- my $paramHash = $hash->{paramHash};
- if (defined $paramHash)
- {
- delete $paramHash->{timeout};
- delete $paramHash->{noshutdown};
- delete $paramHash->{hash};
- delete $paramHash->{page};
- delete $paramHash->{subpage};
- delete $paramHash->{data};
- delete $paramHash->{method};
- delete $paramHash->{callback};
- delete $paramHash->{nonblocking};
- }
- $paramHash = {} if !(defined $paramHash);
- $paramHash->{$_} = $param->{$_} for (keys %$param);
- $param = $paramHash;
- }
- $hash->{paramHash} = $param;
- my $name = $hash->{NAME};
- Log3 $name, 5, "$name: tahoma_UserAgent_NonblockingGet page=$param->{page}";
- #"User-Agent":"TaHoma/7980 CFNetwork/758.5.3 Darwin/15.6.0","Proxy-Connection":"keep-alive","Accept":"*/*","Connection":"keep-alive","Content-Length":"49","Accept-Encoding":"gzip, deflate","Content-Type":"application/x-www-form-urlencoded","Accept-Language":"de-de","Host":"www.tahomalink.com"
- $param->{header} = {'User-Agent' => $hash->{userAgent} }; #, 'Accept-Language' => "de-de", 'Accept-Encoding' => "gzip, deflate"};
- $param->{header}{Cookie} = $hash->{HTTPCookies} if ($hash->{HTTPCookies});
- $param->{compress} = 1;
- $param->{keepalive} = 1;
- if (index($hash->{url},'file:') == 0)
- {
- $param->{url} = $hash->{url} . $param->{page} . '.json';
- my $find = "../";
- $find = quotemeta $find; # escape regex metachars if present
- $param->{url} =~ s/$find//g;
- }
- else
- {
- $param->{url} = $hash->{url} . $param->{page};
- $param->{url} .= $param->{subpage} if ($param->{subpage});
- }
-
- $hash->{request_active} = 1;
- $hash->{request_time} = time;
-
- if ($param->{blocking})
- {
- my($err,$data) = HttpUtils_BlockingGet($param);
- $param->{callback}($param, $err, $data, length $data) if($param->{callback});
- }
- else
- {
- my($err,$data) = HttpUtils_NonblockingGet($param);
- }
-
- }
- sub tahoma_encode_utf8($)
- {
- my ($text) = @_;
- $text =~ s/Ä/Ae/g;
- $text =~ s/Ö/Oe/g;
- $text =~ s/Ü/Ue/g;
- $text =~ s/ä/ae/g;
- $text =~ s/ö/oe/g;
- $text =~ s/ü/ue/g;
- $text =~ s/ß/ss/g;
- return $text;
- }
- sub tahoma_GetCookies($$)
- {
- my ($hash, $header) = @_;
- my $name = $hash->{NAME};
- Log3 $name, 5, "$name: tahoma_GetCookies looking for Cookies in header";
- foreach my $cookie ($header =~ m/set-cookie: ?(.*)/gi) {
- Log3 $name, 5, "$name: Set-Cookie: $cookie";
- $cookie =~ /([^,; ]+)=([^,; ]+)[;, ]*(.*)/;
- Log3 $name, 4, "$name: Cookie: $1 Wert $2 Rest $3";
- $hash->{HTTPCookieHash}{$1}{Value} = $2;
- $hash->{HTTPCookieHash}{$1}{Options} = ($3 ? $3 : "");
- }
- $hash->{HTTPCookies} = join ("; ", map ($_ . "=".$hash->{HTTPCookieHash}{$_}{Value},
- sort keys %{$hash->{HTTPCookieHash}}));
-
- }
- sub tahoma_encrypt($)
- {
- my ($decoded) = @_;
- my $key = getUniqueId();
- my $encoded;
- return $decoded if( $decoded =~ /^crypt:(.*)/ );
- for my $char (split //, $decoded) {
- my $encode = chop($key);
- $encoded .= sprintf("%.2x",ord($char)^ord($encode));
- $key = $encode.$key;
- }
- return 'crypt:'. $encoded;
- }
- sub tahoma_decrypt($)
- {
- my ($encoded) = @_;
- my $key = getUniqueId();
- my $decoded;
- return $encoded if not ( $encoded =~ /^crypt:(.*)/ );
-
- $encoded = $1 if( $encoded =~ /^crypt:(.*)/ );
- for my $char (map { pack('C', hex($_)) } ($encoded =~ /(..)/g)) {
- my $decode = chop($key);
- $decoded .= chr(ord($char)^ord($decode));
- $key = $decode.$key;
- }
-
- return $decoded;
- }
- 1;
- =pod
- =item summary commumication modul for io-homecontrol® gateway TaHoma®
- =item summary_DE Kommunicationsmodul füer io-homecontrol® Gateway TaHoma®
- =begin html
- <a name="tahoma"></a>
- <h3>tahoma</h3>
- <ul>
- The module realizes the communication with io-homecontrol® Devices e.g. from Somfy® or Velux®<br>
- A registered TaHoma® Connect gateway from Overkiz® sold by Somfy® which is continuously connected to the internet is necessary for the module.<br>
- <br><br>
- Notes:
- <ul>
- <li>JSON has to be installed on the FHEM host.</li>
- <li>on problems refer also the fhem forum <a href="https://forum.fhem.de/index.php/topic,28045.0.html">IO-Homecontrol Devices über Tahoma Box einbinden</a></li>
- </ul><br>
- <a name="tahoma_Define"></a>
- <b>Define</b>
- <ul>
- <code>define <name> tahoma ACCOUNT <username> <password></code><br>
- <code>define <name> tahoma DEVICE <DeviceURL></code><br>
- <code>define <name> tahoma PLACE <oid></code><br>
- <code>define <name> tahoma SCENE <oid></code><br>
- <code>define <name> tahoma GROUP <tahoma_device1>,<tahoma_device2>,<tahoma_device3></code><br>
- <br>
- <br>
- A definition is only necessary for a tahoma device:<br>
- <code>define <name> tahoma ACCOUNT <username> <password></code><br>
- <b>If a tahoma device of the type ACCOUNT is created, all other devices accessible by the tahoma gateway are automatically created!</b><br>
- If the account is valid, the setup will be read from the server.<br>
- All registered devices are automatically created with name tahoma_12345 (device number 12345 is used from setup)<br>
- All defined rooms will be are automatically created.<br>
- Also all defined scenes will be automatically created.<br>
- Groups of devices can be manually added to send out one group command for all attached devices<br>
- <br>
- <br>
- <b>global Attributes for ACCOUNT:</b>
- <ul>
- If autocreate is disabled, no devices, places and scenes will be created automatically:<br>
- <code>attr autocreate disable</code><br>
- </ul>
- <br>
- <b>local Attributes for ACCOUNT:</b>
- <ul>
- Normally, the web commands will be send asynchronous, and this can be forced to wait of the result by blocking=1<br>
- <code>attr tahoma1 blocking 1</code><br><br>
- </ul>
- <ul>
- Normally, the login data is stored encrypted after the first start, but this functionality can be disabled by cryptLoginData=0<br>
- <code>attr tahoma1 cryptLoginData 0</code><br><br>
- </ul>
- <ul>
- The account can be completely disabled, so no communication to server is running:<br>
- <code>attr tahoma1 disable 1</code><br><br>
- </ul>
- <ul>
- The interval [seconds] for refreshing and fetching all states can be set:<br>
- This is an old attribute, the default is 0 = off.<br>
- <code>attr tahoma1 interval 300</code><br><br>
- </ul>
- <ul>
- The interval [seconds] for refreshing states can be changed:<br>
- The default is 120s, allowed minimum is 60s, 0 = off.<br>
- This command actualizes the states of devices, which will be externally changed e.g. by controller.<br>
- <code>attr tahoma1 intervalRefresh 120</code><br><br>
- </ul>
- <ul>
- The interval [seconds] for fetching all states can be set:<br>
- The default is 0 = off, allowed minimum is 120s.<br>
- Normally this isn't necessary to set, because all states will be actualized by events.<br>
- <code>attr tahoma1 intervalStates 300</code><br><br>
- </ul>
- <ul>
- The interval [seconds] for fetching new events can be changed:<br>
- The default is 2s, allowed minimum is 2s.<br>
- <code>attr tahoma1 intervalEvents 300</code><br>
- </ul>
- <br>
- <b>local Attributes for DEVICE:</b>
- <ul>
- If the closure value 0..100 should be 100..0, the level can be inverted:<br>
- <code>attr tahoma_23234545 levelInvert 1</code><br><br>
- </ul>
- <ul>
- The device can be disabled:<br>
- The device is disabled then for direct access and indirect access by GROUP and PLACE, but not by SCENE.<br>
- <code>attr tahoma_23234545 disable 1</code><br>
- </ul>
- <br>
- <b>local Attributes for PLACE:</b>
- <ul>
- The commands in a room will only affect the devices in the room with inClass=RollerShutter.<br>
- This can be extend or changed by setting the placeClasses attribute:<br>
- <code>attr tahoma_abc12345 placeClasses RollerShutter ExteriorScreen Window</code><br><br>
- </ul>
- <ul>
- The place and its sub places can be disabled:<br>
- <code>attr tahoma_abc12345 disable 1</code><br>
- </ul>
- <br>
- <b>local Attributes for SCENE:</b>
- <ul>
- The scene can be disabled:<br>
- <code>attr tahoma_4ef30a23 disable 1</code><br>
- </ul>
- <br>
- <b>local Attributes for GROUP:</b>
- <ul>
- The group can be disabled:<br>
- <code>attr tahoma_group1 disable 1</code><br>
- </ul>
- <br>
- <b>Examples:</b>
- <ul>
- <code>define tahoma1 tahoma ACCOUNT abc@test.com myPassword</code><br>
- <code>attr tahoma1 blocking 0</code><br>
- <code>attr tahoma1 room tahoma</code><br>
- <br>
- <br>Automatic created device e.g.:<br>
- <code>define tahoma_23234545 tahoma DEVICE io://0234-5678-9012/23234545</code><br>
- <code>attr tahoma_23234545 IODev tahoma1</code><br>
- <code>attr tahoma_23234545 alias RollerShutter Badezimmer</code><br>
- <code>attr tahoma_23234545 room tahoma</code><br>
- <code>attr tahoma_23234545 webCmd dim</code><br>
- <br>
- <br>Automatic created place e.g.:<br>
- <code>define tahoma_abc12345 tahoma PLACE abc12345-0a23-0b45-0c67-d5e6f7a1b2c3</code><br>
- <code>attr tahoma_abc12345 IODev tahoma1</code><br>
- <code>attr tahoma_abc12345 alias room Wohnzimmer</code><br>
- <code>attr tahoma_abc12345 room tahoma</code><br>
- <br>
- <br>Automatic created scene e.g.:<br>
- <code>define tahoma_4ef30a23 tahoma SCENE 4ef30a23-0b45-0c67-d5e6-f7a1b2c32e3f</code><br>
- <code>attr tahoma_4ef30a23 IODev tahoma1</code><br>
- <code>attr tahoma_4ef30a23 alias scene Rolladen Südfenster zu</code><br>
- <code>attr tahoma_4ef30a23 room tahoma</code><br>
- <br>
- <br>manual created group e.g.:<br>
- <code>define tahoma_group1 tahoma GROUP tahoma_23234545,tahoma_23234546,tahoma_23234547</code><br>
- <code>attr tahoma_group1 IODev tahoma1</code><br>
- <code>attr tahoma_group1 alias Gruppe Rolladen Westen</code><br>
- <code>attr tahoma_group1 room tahoma</code><br>
- </ul>
- </ul><br>
- </ul>
- =end html
- =cut
|