# $Id: 74_THINKINGCLEANER.pm 13389 2017-02-11 13:34:44Z loredo $ ############################################################################## # # 74_THINKINGCLEANER.pm # An FHEM Perl module for controlling ThinkingCleaner connected # Roomba vacuum cleaning robot. # # Copyright by Julian Pawlowski # e-mail: julian.pawlowski at gmail.com # # 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 vars qw(%data); use HttpUtils; use Encode; use Data::Dumper; no warnings "all"; sub THINKINGCLEANER_Set($@); sub THINKINGCLEANER_GetStatus($;$); sub THINKINGCLEANER_Attr($@); sub THINKINGCLEANER_Define($$); sub THINKINGCLEANER_Undefine($$); ################################### sub THINKINGCLEANER_Initialize($) { my ($hash) = @_; Log3 $hash, 5, "THINKINGCLEANER_Initialize: Entering"; my $webhookFWinstance = join( ",", devspec2array('TYPE=FHEMWEB:FILTER=TEMPORARY!=1') ); $hash->{SetFn} = "THINKINGCLEANER_Set"; $hash->{DefFn} = "THINKINGCLEANER_Define"; $hash->{AttrFn} = "THINKINGCLEANER_Attr"; $hash->{UndefFn} = "THINKINGCLEANER_Undefine"; $hash->{parseParams} = 1; $hash->{AttrList} = "disable:0,1 timeout:1,2,3,4,5 pollInterval:30,45,60,75,90 pollMultiplierWebhook pollMultiplierCleaning model webhookHttpHostname webhookPort webhookFWinstance:$webhookFWinstance restart:noArg " . $readingFnAttributes; # 98_powerMap.pm support $hash->{powerMap} = { model => 'modelid', # fallback to attribute modelid => { 'Roomba_700_Series' => { rname_E => 'energy', rname_P => 'consumption', map => { presence => { absent => 0, }, deviceStatus => { base => 0.1, plug => 0.1, base_recon => 33, plug_recon => 33, base_full => 33, plug_full => 33, base_trickle => 5, plug_trickle => 5, base_wait => 0.1, plug_wait => 0.1, '*' => 0, }, }, }, }, }; return; } ##################################### sub THINKINGCLEANER_GetStatus($;$) { my ( $hash, $delay ) = @_; my $name = $hash->{NAME}; $hash->{INTERVAL_MULTIPLIER} = ( ReadingsVal( $name, "state", "off" ) ne "off" && ReadingsVal( $name, "state", "absent" ) ne "absent" && ReadingsVal( $name, "state", "standby" ) ne "standby" ? AttrVal( $name, "pollMultiplierCleaning", "0.5" ) : ( $hash->{WEBHOOK_REGISTER} eq "success" ? AttrVal( $name, "pollMultiplierWebhook", "2" ) : "1" ) ); $hash->{INTERVAL} = AttrVal( $name, "pollInterval", "45" ) * $hash->{INTERVAL_MULTIPLIER}; my $interval = ( $delay ? $delay : $hash->{INTERVAL} ); Log3 $name, 5, "THINKINGCLEANER $name: called function THINKINGCLEANER_GetStatus()"; RemoveInternalTimer($hash); InternalTimer( gettimeofday() + $interval, "THINKINGCLEANER_GetStatus", $hash, 0 ); return if ( $delay || AttrVal( $name, "disable", 0 ) == 1 ); THINKINGCLEANER_SendCommand( $hash, "full_status.json" ); return; } ################################### sub THINKINGCLEANER_Set($$$) { my ( $hash, $a, $h ) = @_; my $name = $hash->{NAME}; my $state = ReadingsVal( $name, "state", "absent" ); my $deviceStatus = ReadingsVal( $name, "deviceStatus", "off" ); my $presence = ReadingsVal( $name, "presence", "absent" ); my $power = ReadingsVal( $name, "power", "off" ); Log3 $name, 5, "THINKINGCLEANER $name: called function THINKINGCLEANER_Set()"; return "Argument is missing" if ( int(@$a) < 1 ); my $usage = "Unknown argument " . @$a[1] . ", choose one of statusRequest:noArg toggle:noArg on:noArg on-spot:noArg on-max:noArg off:noArg power:off,on dock:noArg undock:noArg locate:noArg on-delayed:noArg cleaningDelay remoteControl:forward,backward,left,left-spin,right,right-spin,stop,drive scheduleAdd name damageProtection:off,on reboot:noArg autoUpdate:on,off vacuumDrive:off,on restartAC:on,off alwaysMAX:on,off autoDock:on,off keepAwakeOnDock:on,off songSubmit songReset:noArg dockAt stopAt"; my $cmd = ''; my $result; # find existing schedules and offer set commands my $sd0 = ReadingsVal( $name, "schedule0", "" ); my $sd1 = ReadingsVal( $name, "schedule1", "" ); my $sd2 = ReadingsVal( $name, "schedule2", "" ); my $sd3 = ReadingsVal( $name, "schedule3", "" ); my $sd4 = ReadingsVal( $name, "schedule4", "" ); my $sd5 = ReadingsVal( $name, "schedule5", "" ); my $sd6 = ReadingsVal( $name, "schedule6", "" ); my $schedules = ""; my $si = "0"; foreach ( $sd0, $sd1, $sd2, $sd3, $sd4, $sd5, $sd6 ) { if ( $_ ne "" ) { $schedules .= "," if ( $schedules ne "" ); $_ =~ s/(\d+)_(\d{2}:\d{2}:\d{2})_(([A-Za-z]+),?)/$si\_$1_$2_$3/g; $schedules .= $_; } $si++; } $usage .= " scheduleDel:$schedules scheduleMod:$schedules" if ( $schedules ne "" ); # statusRequest if ( lc( @$a[1] ) eq "statusrequest" ) { Log3 $name, 3, "THINKINGCLEANER set $name " . @$a[1]; THINKINGCLEANER_GetStatus($hash); } # scheduleAdd elsif ( lc( @$a[1] ) eq "scheduleadd" ) { if ( $state ne "absent" ) { Log3 $name, 3, "THINKINGCLEANER set $name " . @$a[1] . " " . @$a[2] . " " . @$a[3] . " " . @$a[4]; return "Missing arguments. Usage: scheduleAdd