From 09732ce63ea37c5db548aef0fe0b7e87441b367e Mon Sep 17 00:00:00 2001
From: vuffiraa <>
Date: Thu, 30 Apr 2020 17:29:42 +0000
Subject: [PATCH] 70_BOTVAC.pm: Optimize error message handling; Renew
accessToken if necessary; PBP issues
git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@21819 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
CHANGED | 5 +-
FHEM/70_BOTVAC.pm | 344 +++++++++++++++++++++++++++-------------------
2 files changed, 203 insertions(+), 146 deletions(-)
diff --git a/CHANGED b/CHANGED
index 4f6880c39..f373794cd 100644
--- a/CHANGED
+++ b/CHANGED
@@ -1,5 +1,8 @@
# 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.
+# Do not insert empty lines here, update check depends on it.
+ - change: 70_BOTVAC: Optimze error message handling
+ Renew accessToken if necessary
+ PBP issues
- change: 57_Calendar: reactivated random delay for calendar updates on start
- bugfix 98_todoist: Forum: #1048705
- bugfix: 74_GardenaSmartDevice: setter from mower not visible
diff --git a/FHEM/70_BOTVAC.pm b/FHEM/70_BOTVAC.pm
index 544026dda..cd6793378 100755
--- a/FHEM/70_BOTVAC.pm
+++ b/FHEM/70_BOTVAC.pm
@@ -24,32 +24,7 @@
#
##############################################################################
-package main;
-
-use strict;
-use warnings;
-
-
-sub BOTVAC_Initialize($) {
- my ($hash) = @_;
- our $readingFnAttributes;
-
- $hash->{DefFn} = "BOTVAC::Define";
- $hash->{GetFn} = "BOTVAC::Get";
- $hash->{SetFn} = "BOTVAC::Set";
- $hash->{UndefFn} = "BOTVAC::Undefine";
- $hash->{DeleteFn} = "BOTVAC::Delete";
- $hash->{ReadFn} = "BOTVAC::wsRead";
- $hash->{ReadyFn} = "BOTVAC::wsReady";
- $hash->{AttrFn} = "BOTVAC::Attr";
- $hash->{AttrList} = "disable:0,1 " .
- "actionInterval " .
- "boundaries:textField-long " .
- "sslVerify:0,1 " .
- $readingFnAttributes;
-}
-
-package BOTVAC;
+package FHEM::BOTVAC;
use strict;
use warnings;
@@ -58,40 +33,55 @@ use POSIX;
use GPUtils qw(:all); # wird für den Import der FHEM Funktionen aus der fhem.pl benötigt
use Time::HiRes qw(gettimeofday);
+use Time::Local qw(timelocal);
use JSON qw(decode_json encode_json);
use Digest::SHA qw(hmac_sha256_hex sha1_hex);
use Encode qw(encode_utf8);
use MIME::Base64;
-require "DevIo.pm";
-require "HttpUtils.pm";
+require DevIo;
+require HttpUtils;
## Import der FHEM Funktionen
BEGIN {
GP_Import(qw(
- AttrVal
- createUniqueId
- FmtDateTime
- FmtDateTimeRFC1123
- fhemTzOffset
- getKeyValue
- setKeyValue
- getUniqueId
- InternalTimer
- InternalVal
- readingsSingleUpdate
- readingsBulkUpdate
- readingsBulkUpdateIfChanged
- readingsBeginUpdate
- readingsDelete
- readingsEndUpdate
- ReadingsNum
- ReadingsVal
- RemoveInternalTimer
- Log3
- trim
- ))
-};
+ AttrVal
+ CommandAttr
+ createUniqueId
+ fhemTzOffset
+ FmtDateTime
+ FmtDateTimeRFC1123
+ getKeyValue
+ getUniqueId
+ InternalTimer
+ InternalVal
+ Log3
+ readingFnAttributes
+ readingsBeginUpdate
+ readingsBulkUpdate
+ readingsBulkUpdateIfChanged
+ readingsDelete
+ readingsEndUpdate
+ ReadingsNum
+ readingsSingleUpdate
+ ReadingsVal
+ RemoveInternalTimer
+ setKeyValue
+ trim
+ ));
+}
+
+GP_Export(
+ qw(
+ Initialize
+ )
+);
+
+my $useDigestMD5 = 0;
+if ( eval { require Digest::MD5; 1 } ) {
+ $useDigestMD5 = 1;
+ Digest::MD5->import();
+}
my %opcode = ( # Opcode interpretation of the ws "Payload data
'continuation' => 0x00,
@@ -103,7 +93,28 @@ my %opcode = ( # Opcode interpretation of the ws "Payload data
);
###################################
-sub Define($$) {
+sub Initialize {
+ my ($hash) = @_;
+
+ $hash->{DefFn} = \&Define;
+ $hash->{GetFn} = \&Get;
+ $hash->{SetFn} = \&Set;
+ $hash->{UndefFn} = \&Undefine;
+ $hash->{DeleteFn} = \&Delete;
+ $hash->{ReadFn} = \&wsRead;
+ $hash->{ReadyFn} = \&wsReady;
+ $hash->{AttrFn} = \&Attr;
+ $hash->{AttrList} = "disable:0,1 " .
+ "actionInterval " .
+ "boundaries:textField-long " .
+ "sslVerify:0,1 " .
+ $readingFnAttributes;
+
+ return;
+}
+
+###################################
+sub Define {
my ( $hash, $def ) = @_;
my @a = split( "[ \t][ \t]*", $def );
my $name = $hash->{NAME};
@@ -147,22 +158,20 @@ sub Define($$) {
$hash->{VENDOR} = $vendor;
$hash->{INTERVAL} = $interval;
- unless ( defined( AttrVal( $name, "webCmd", undef ) ) ) {
- no warnings "once";
- $::attr{$name}{webCmd} = 'startCleaning:stop:sendToBase';
- }
+ CommandAttr($hash, "$name webCmd startCleaning:stop:sendToBase")
+ if (AttrVal( $name, 'webCmd', 'none' ) eq 'none');
# start the status update timer
RemoveInternalTimer($hash);
- InternalTimer( gettimeofday() + 2, "BOTVAC::GetStatus", $hash, 1 );
+ InternalTimer( gettimeofday() + 2, \&GetStatus, $hash, 1 );
- AddExtension($name, "BOTVAC::GetMap", "BOTVAC/$name/map");
+ AddExtension($name, \&GetMap, "BOTVAC/$name/map");
return;
}
#####################################
-sub GetStatus($;$) {
+sub GetStatus {
my ( $hash, $update ) = @_;
my $name = $hash->{NAME};
my $interval = $hash->{INTERVAL};
@@ -171,10 +180,10 @@ sub GetStatus($;$) {
Log3($name, 5, "BOTVAC $name: called function GetStatus()");
# use actionInterval if state is busy or paused
- $interval = AttrVal($name, "actionInterval", $interval) if (ReadingsVal($name, "stateId", "0") =~ /2|3/);
+ $interval = AttrVal($name, "actionInterval", $interval) if (ReadingsVal($name, "stateId", "0") =~ /2|3/x);
RemoveInternalTimer($hash);
- InternalTimer( gettimeofday() + $interval, "BOTVAC::GetStatus", $hash, 0 );
+ InternalTimer( gettimeofday() + $interval, \&GetStatus, $hash, 0 );
return if ( AttrVal($name, "disable", 0) == 1 or ReadingsVal($name,"pollingMode",1) == 0);
@@ -187,8 +196,8 @@ sub GetStatus($;$) {
push(@successor, ["dashboard", undef]) if ($secs <= $interval);
push(@successor, ["messages", "getSchedule"]);
- push(@successor, ["messages", "getGeneralInfo"]) if (GetServiceVersion($hash, "generalInfo") =~ /.*-1/);
- push(@successor, ["messages", "getPreferences"]) if (GetServiceVersion($hash, "preferences") ne "");
+ push(@successor, ["messages", "getGeneralInfo"]) if (GetServiceVersion($hash, "generalInfo") =~ /.*-1/x);
+ push(@successor, ["messages", "getPreferences"]) if (GetServiceVersion($hash, "preferences") ne '');
SendCommand($hash, "messages", "getRobotState", undef, @successor);
}
@@ -201,7 +210,7 @@ sub GetStatus($;$) {
}
###################################
-sub Get($@) {
+sub Get {
my ( $hash, @a ) = @_;
my $name = $hash->{NAME};
my $what;
@@ -230,7 +239,7 @@ sub Get($@) {
}
###################################
-sub Set($@) {
+sub Set {
my ( $hash, @a ) = @_;
my $name = $hash->{NAME};
@@ -315,7 +324,7 @@ sub Set($@) {
my @names;
for (my $i = 0; $i < @Boundaries; $i++) {
my $name = $Boundaries[$i]->{name};
- push @names,$name if (!(grep { $_ eq $name } @names) and ($name ne ""));
+ push @names,$name if (!(grep { $_ eq $name } @names) && ($name ne ""));
}
my $BoundariesList = @names ? "multiple-strict,".join(",", @names) : "textField";
$usage .= " setBoundariesOnFloorplan_0:".$BoundariesList if (ReadingsVal($name, "floorplan_0_id" ,"") ne "");
@@ -574,7 +583,7 @@ sub Set($@) {
}
###################################
-sub Undefine($$) {
+sub Undefine {
my ( $hash, $arg ) = @_;
my $name = $hash->{NAME};
@@ -589,7 +598,7 @@ sub Undefine($$) {
}
###################################
-sub Delete($$) {
+sub Delete {
my ( $hash, $arg ) = @_;
my $name = $hash->{NAME};
@@ -602,7 +611,7 @@ sub Delete($$) {
}
###################################
-sub Attr(@)
+sub Attr
{
my ($cmd,$name,$attr_name,$attr_value) = @_;
my $hash = $::defs{$name};
@@ -637,7 +646,7 @@ sub Attr(@)
############################################################################################################
#########################
-sub AddExtension($$$) {
+sub AddExtension {
my ( $name, $func, $link ) = @_;
my $url = "/$link";
@@ -645,20 +654,24 @@ sub AddExtension($$$) {
$::data{FWEXT}{$url}{deviceName} = $name;
$::data{FWEXT}{$url}{FUNC} = $func;
$::data{FWEXT}{$url}{LINK} = $link;
+
+ return;
}
#########################
-sub RemoveExtension($) {
+sub RemoveExtension {
my ($link) = @_;
my $url = "/$link";
my $name = $::data{FWEXT}{$url}{deviceName};
Log3($name, 2, "Unregistering BOTVAC $name for URL $url...");
delete $::data{FWEXT}{$url};
+
+ return;
}
###################################
-sub SendCommand($$;$$@) {
+sub SendCommand {
my ( $hash, $service, $cmd, $option, @successor ) = @_;
my $name = $hash->{NAME};
my $email = $hash->{EMAIL};
@@ -694,11 +707,11 @@ sub SendCommand($$;$$@) {
my $sslVerify= AttrVal($name, "sslVerify", undef);
if(defined($sslVerify)) {
- eval "use IO::Socket::SSL";
+ eval {use IO::Socket::SSL};
if($@) {
Log3($name, 2, $@);
} else {
- my $sslVerifyMode= eval("$sslVerify ? SSL_VERIFY_PEER : SSL_VERIFY_NONE");
+ my $sslVerifyMode= eval {$sslVerify ? SSL_VERIFY_PEER : SSL_VERIFY_NONE};
Log3($name, 5, "SSL verify mode set to $sslVerifyMode");
$sslArgs{SSL_verify_mode} = $sslVerifyMode;
}
@@ -835,7 +848,7 @@ sub SendCommand($$;$$@) {
if ( defined($data) );
Log3($name, 5, "BOTVAC $name: GET $URL")
if ( !defined($data) );
- Log3($name, 5, "BOTVAC $name: header ".join("\n", map(($_.': '.$header{$_}), keys %header)))
+ Log3($name, 5, "BOTVAC $name: header ".join("\n", map {$_.': '.$header{$_}} keys %header))
if ( %header );
my $params = {
@@ -865,7 +878,7 @@ sub SendCommand($$;$$@) {
}
###################################
-sub ReceiveCommand($$$) {
+sub ReceiveCommand {
my ( $param, $err, $data ) = @_;
my $hash = $param->{hash};
my $name = $hash->{NAME};
@@ -905,6 +918,9 @@ sub ReceiveCommand($$$) {
# stop pulling for current interval
Log3($name, 4, "BOTVAC $name: drop successors");
LogSuccessors($hash, @successor);
+
+ readingsEndUpdate( $hash, 1 );
+
return;
}
@@ -921,11 +937,30 @@ sub ReceiveCommand($$$) {
if ( $data ne "" ) {
if ( $service eq "loadmap" ) {
# use $data later
- } elsif ( $data =~ /^{"message":"Could not find robot_serial for specified vendor_name"}$/ ) {
+ } elsif ( $data eq '{"message":"Could not find robot_serial for specified vendor_name"}' ) {
# currently no data available
readingsBulkUpdateIfChanged($hash, "state", "Couldn't find robot");
readingsEndUpdate( $hash, 1 );
return;
+ } elsif ( $data eq '{"message":"Bad credentials"}' ||
+ $data eq '{"message":"Not allowed"}' ) {
+ if ( !defined($cmd) || $cmd eq "" ) {
+ Log3($name, 3, "BOTVAC $name: RES $service - $data");
+ } else {
+ Log3($name, 3, "BOTVAC $name: RES $service/$cmd - $data");
+ }
+
+ # remove invalid access token
+ readingsDelete($hash, ".accessToken");
+ readingsEndUpdate( $hash, 1 );
+
+ if ( $service ne "sessions") {
+ # put last command back into queue
+ unshift(@successor, [$service, $cmd]);
+ # send registration
+ SendCommand($hash, "sessions", undef, undef, @successor);
+ }
+ return;
} elsif ( $data =~ /^{/ || $data =~ /^\[/ ) {
if ( !defined($cmd) || $cmd eq "" ) {
Log3($name, 4, "BOTVAC $name: RES $service - $data");
@@ -940,7 +975,8 @@ sub ReceiveCommand($$$) {
} else {
Log3($name, 5, "BOTVAC $name: RES ERROR $service/$cmd\n$data");
}
- return undef;
+ readingsEndUpdate( $hash, 1 );
+ return;
}
}
@@ -1294,7 +1330,7 @@ sub ReceiveCommand($$$) {
readingsEndUpdate( $hash, 1 );
if (defined($hash->{helper}{".HTTP_CONNECTION"}) and
- (($keepalive and $closeConnection) or !@successor)) {
+ (($keepalive && $closeConnection) || !@successor)) {
Log3($name, 4, "BOTVAC $name: Close connection");
::HttpUtils_Close($hash->{helper}{".HTTP_CONNECTION"});
undef($hash->{helper}{".HTTP_CONNECTION"});
@@ -1330,31 +1366,29 @@ sub ReceiveCommand($$$) {
return;
}
-sub GetTimeFromString($) {
+sub GetTimeFromString {
my ($timeStr) = @_;
- eval {
- use Time::Local;
- if(defined($timeStr) and $timeStr =~ m/^(\d{4})-(\d{2})-(\d{2})T([0-2]\d):([0-5]\d):([0-5]\d)Z$/) {
- my $time = timelocal($6, $5, $4, $3, $2 - 1, $1 - 1900);
- return FmtDateTime($time + fhemTzOffset($time));
- }
+ if(defined($timeStr) and $timeStr =~ m/^(\d{4})-(\d{2})-(\d{2})T([0-2]\d):([0-5]\d):([0-5]\d)Z$/x) {
+ my $time = timelocal($6, $5, $4, $3, $2 - 1, $1 - 1900);
+ return FmtDateTime($time + fhemTzOffset($time));
}
+
+ return;
}
-sub GetSecondsFromString($) {
+sub GetSecondsFromString {
my ($timeStr) = @_;
- eval {
- use Time::Local;
- if(defined($timeStr) and $timeStr =~ m/^(\d{4})-(\d{2})-(\d{2})T([0-2]\d):([0-5]\d):([0-5]\d)Z$/) {
- my $time = timelocal($6, $5, $4, $3, $2 - 1, $1 - 1900);
- return $time;
- }
+ if(defined($timeStr) and $timeStr =~ m/^(\d{4})-(\d{2})-(\d{2})T([0-2]\d):([0-5]\d):([0-5]\d)Z$/x) {
+ my $time = timelocal($6, $5, $4, $3, $2 - 1, $1 - 1900);
+ return $time;
}
+
+ return;
}
-sub SetRobot($$) {
+sub SetRobot {
my ( $hash, $robot ) = @_;
my $name = $hash->{NAME};
@@ -1370,9 +1404,11 @@ sub SetRobot($$) {
readingsBulkUpdateIfChanged($hash, "macAddr", $robots[$robot]->{macAddr});
readingsBulkUpdateIfChanged($hash, "nucleoUrl", $robots[$robot]->{nucleoUrl});
readingsBulkUpdateIfChanged($hash, "robot", $robot);
+
+ return;
}
-sub GetCleaningParameter($$$) {
+sub GetCleaningParameter {
my ($hash, $param, $default) = @_;
my $name = $hash->{NAME};
@@ -1380,7 +1416,7 @@ sub GetCleaningParameter($$$) {
return ReadingsVal($name, $nextReading, ReadingsVal($name, $param, $default));
}
-sub GetServiceVersion($$) {
+sub GetServiceVersion {
my ($hash, $service) = @_;
my $name = $hash->{NAME};
@@ -1396,16 +1432,18 @@ sub SetServices {
my $name = $hash->{NAME};
my $serviceList = join(", ", map { "$_:$services->{$_}" } keys %$services);
- $hash->{SERVICES} = $serviceList if (!defined($hash->{SERVICES}) or $hash->{SERVICES} ne $serviceList);
+ $hash->{SERVICES} = $serviceList if (!defined($hash->{SERVICES}) || $hash->{SERVICES} ne $serviceList);
+
+ return;
}
-sub StorePassword($$) {
+sub StorePassword {
my ($hash, $password) = @_;
my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd";
my $key = getUniqueId().$index;
my $enc_pwd = "";
- if(eval "use Digest::MD5;1") {
+ if($useDigestMD5) {
$key = Digest::MD5::md5_hex(unpack "H*", $key);
$key .= Digest::MD5::md5_hex($key);
}
@@ -1422,7 +1460,7 @@ sub StorePassword($$) {
return "password successfully saved";
}
-sub ReadPassword($) {
+sub ReadPassword {
my ($hash) = @_;
my $name = $hash->{NAME};
my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd";
@@ -1435,16 +1473,16 @@ sub ReadPassword($) {
if ( defined($err) ) {
Log3($name, 3, "BOTVAC $name: unable to read password from file: $err");
- return undef;
+ return;
}
if ( defined($password) ) {
- if ( eval "use Digest::MD5;1" ) {
+ if($useDigestMD5) {
$key = Digest::MD5::md5_hex(unpack "H*", $key);
$key .= Digest::MD5::md5_hex($key);
}
my $dec_pwd = '';
- for my $char (map { pack('C', hex($_)) } ($password =~ /(..)/g)) {
+ for my $char (map { pack('C', hex($_)) } ($password =~ /(..)/gx)) {
my $decode=chop($key);
$dec_pwd.=chr(ord($char)^ord($decode));
$key=$decode.$key;
@@ -1452,11 +1490,11 @@ sub ReadPassword($) {
return $dec_pwd;
} else {
Log3($name, 3, "BOTVAC $name: No password in file");
- return undef;
+ return;
}
}
-sub CheckRegistration($$$$$) {
+sub CheckRegistration {
my ( $hash, $service, $cmd, $option, @successor ) = @_;
my $name = $hash->{NAME};
@@ -1482,7 +1520,7 @@ sub CheckRegistration($$$$$) {
return;
}
-sub GetBoolean($) {
+sub GetBoolean {
my ($value) = @_;
my $booleans = {
'0' => "0",
@@ -1498,7 +1536,7 @@ sub GetBoolean($) {
}
}
-sub SetBoolean($) {
+sub SetBoolean {
my ($value) = @_;
my $booleans = {
'0' => "false",
@@ -1514,7 +1552,7 @@ sub SetBoolean($) {
}
}
-sub BuildState($$$$) {
+sub BuildState {
my ($hash,$state,$action,$error) = @_;
my $states = {
'0' => "Invalid",
@@ -1539,7 +1577,7 @@ sub BuildState($$$$) {
}
}
-sub GetActionText($) {
+sub GetActionText {
my ($action) = @_;
my $actions = {
'0' => "Invalid",
@@ -1567,7 +1605,7 @@ sub GetActionText($) {
}
}
-sub GetErrorText($) {
+sub GetErrorText {
my ($error) = @_;
my $errors = {
'ui_alert_invalid' => 'Ok',
@@ -1589,7 +1627,7 @@ sub GetErrorText($) {
}
}
-sub GetDayText($) {
+sub GetDayText {
my ($day) = @_;
my $days = {
'0' => "Sunday",
@@ -1608,7 +1646,7 @@ sub GetDayText($) {
}
}
-sub GetCategoryText($) {
+sub GetCategoryText {
my ($category) = @_;
my $categories = {
'1' => 'manual',
@@ -1624,7 +1662,7 @@ sub GetCategoryText($) {
}
}
-sub GetModeText($) {
+sub GetModeText {
my ($mode) = @_;
my $modes = {
'1' => 'eco',
@@ -1638,7 +1676,7 @@ sub GetModeText($) {
}
}
-sub GetModifierText($) {
+sub GetModifierText {
my ($modifier) = @_;
my $modifiers = {
'1' => 'normal',
@@ -1652,7 +1690,7 @@ sub GetModifierText($) {
}
}
-sub GetNavigationModeText($) {
+sub GetNavigationModeText {
my ($navMode) = @_;
my $navModes = {
'1' => 'normal',
@@ -1667,7 +1705,7 @@ sub GetNavigationModeText($) {
}
}
-sub GetAuthStatusText($) {
+sub GetAuthStatusText {
my ($authStatus) = @_;
my $authStatusHash = {
'0' => 'not supported',
@@ -1682,7 +1720,7 @@ sub GetAuthStatusText($) {
}
}
-sub GetBeehiveHost($) {
+sub GetBeehiveHost {
my ($vendor) = @_;
my $vendors = {
'neato' => 'beehive.neatocloud.com',
@@ -1696,7 +1734,7 @@ sub GetBeehiveHost($) {
}
}
-sub GetNucleoHost($) {
+sub GetNucleoHost {
my ($vendor) = @_;
my $vendors = {
'neato' => 'nucleo.neatocloud.com',
@@ -1710,12 +1748,12 @@ sub GetNucleoHost($) {
}
}
-sub GetValidityEnd($) {
+sub GetValidityEnd {
my ($validFor) = @_;
return ($validFor =~ /\d+/ ? FmtDateTime(time() + $validFor) : $validFor);
}
-sub LogSuccessors($@) {
+sub LogSuccessors {
my ($hash,@successor) = @_;
my $name = $hash->{NAME};
@@ -1727,9 +1765,11 @@ sub LogSuccessors($@) {
$msg .= join(",", map { defined($_) ? $_ : '' } @succ_item);
}
Log3($name, 4, $msg) if (@successor > 0);
+
+ return;
}
-sub ShowMap($;$$) {
+sub ShowMap {
my ($name,$width,$height) = @_;
my $img = '{helper}{MAPS}) or @{$hash->{helper}{MAPS}} == 0);
+ if (!defined($hash->{helper}{MAPS}) || @{$hash->{helper}{MAPS}} == 0);
return GetStatistics($hash);
}
-sub GetStatistics($) {
+sub GetStatistics {
my($hash) = @_;
my $name = $hash->{NAME};
my $mapcount = @{$hash->{helper}{MAPS}};
@@ -1866,7 +1906,7 @@ sub GetStatistics($) {
#######################################
# Websocket Functions
#######################################
-sub wsOpen($$$) {
+sub wsOpen {
my ($hash,$ip_address,$port) = @_;
my $name = $hash->{NAME};
@@ -1875,16 +1915,18 @@ sub wsOpen($$$) {
::DevIo_CloseDev($hash) if(::DevIo_IsOpen($hash));
- if (::DevIo_OpenDev($hash, 0, "BOTVAC::wsHandshake")) {
+ if (::DevIo_OpenDev($hash, 0, \&wsHandshake)) {
Log3($name, 2, "BOTVAC(ws) $name: ERROR: Can't open websocket to $hash->{DeviceName}");
readingsSingleUpdate($hash,'result','ws_connect_error',1);
readingsSingleUpdate($hash,'result','ws_ko',1);
} else {
readingsSingleUpdate($hash,'result','ws_ok',1);
}
+
+ return;
}
-sub wsClose($) {
+sub wsClose {
my $hash = shift;
my $name = $hash->{NAME};
my $normal_closure = pack("H*", "03e8"); #code 1000
@@ -1894,10 +1936,12 @@ sub wsClose($) {
wsEncode($hash, $normal_closure, "close");
delete $hash->{HELPER}{WEBSOCKETS};
delete $hash->{HELPER}{wsKey};
- readingsSingleUpdate($hash,'state','ws_closed',1) if (::DevIo_CloseDev($hash))
+ readingsSingleUpdate($hash,'state','ws_closed',1) if (::DevIo_CloseDev($hash));
+
+ return;
}
-sub wsHandshake($) {
+sub wsHandshake {
my $hash = shift;
my $name = $hash->{NAME};
my $host = ReadingsVal($name, "wlanIpAddress", "");
@@ -1926,10 +1970,10 @@ sub wsHandshake($) {
$hash->{HELPER}{wsKey} = $wsKey;
- return undef;
+ return;
}
-sub wsCheckHandshake($$) {
+sub wsCheckHandshake {
my ($hash,$response) = @_;
my $name = $hash->{NAME};
@@ -1959,20 +2003,20 @@ sub wsCheckHandshake($$) {
readingsSingleUpdate($hash,'state','ws_handshake-error',1);
}
}
- return undef;
+ return;
}
-sub wsWrite($@) {
+sub wsWrite {
my ($hash,$string) = @_;
my $name = $hash->{NAME};
Log3($name, 4, "BOTVAC(ws) $name: WriteFn called:\n$string");
::DevIo_SimpleWrite($hash, $string, 0);
- return undef;
+ return;
}
-sub wsRead($) {
+sub wsRead {
my $hash = shift;
my $name = $hash->{NAME};
my $buf;
@@ -1987,13 +2031,15 @@ sub wsRead($) {
wsDecode($hash,$buf);
} elsif( $buf =~ /HTTP\/1.1 101 Switching Protocols/ ) {
Log3($name, 4, "BOTVAC(ws) $name: received HTTP data string, start response processing:\n$buf");
- BOTVAC::wsCheckHandshake($hash,$buf);
+ wsCheckHandshake($hash,$buf);
} else {
Log3($name, 1, "BOTVAC(ws) $name: corrupted data found:\n$buf");
}
+
+ return;
}
-sub wsCallback(@) {
+sub wsCallback {
my ($param, $err, $data) = @_;
my $hash = $param->{hash};
my $name = $hash->{NAME};
@@ -2009,12 +2055,15 @@ sub wsCallback(@) {
} else {
Log3($name, 2, "received callback without Data and Error String!!!");
}
- return undef;
+ return;
}
-sub wsReady($) {
+sub wsReady {
my ($hash) = @_;
- return ::DevIo_OpenDev($hash, 1, "BOTVAC::wsHandshake") if ( $hash->{STATE} eq "disconnected" );
+ if ( $hash->{STATE} eq "disconnected" ) {
+ return ::DevIo_OpenDev($hash, 1, \&wsHandshake);
+ }
+ return;
}
# 0 1 2 3
@@ -2036,7 +2085,7 @@ sub wsReady($) {
# | Payload Data continued ... |
# +---------------------------------------------------------------+
# https://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17
-sub wsEncode($$;$$) {
+sub wsEncode {
my ($hash, $payload, $type, $masked) = @_;
my $name = $hash->{NAME};
$type //= "text";
@@ -2072,16 +2121,19 @@ sub wsEncode($$;$$) {
Log3($name, 3, "BOTVAC(ws) $name: String: " . unpack('H*',$wsString));
wsWrite($hash, $wsString);
+
+ return;
}
-sub wsPong($) {
+sub wsPong {
my $hash = shift;
my $name = $hash->{NAME};
Log3($name, 3, "BOTVAC(ws) $name: wsPong");
wsEncode($hash, undef, "pong");
+ return;
}
-sub wsDecode($$) {
+sub wsDecode {
my ($hash,$wsString) = @_;
my $name = $hash->{NAME};
@@ -2122,9 +2174,11 @@ sub wsDecode($$) {
wsPong($hash) if ($OPCODE == $opcode{"ping"});
}
}
+
+ return;
}
-sub wsMasking($$) {
+sub wsMasking {
my ($payload, $mask) = @_;
$mask = $mask x (int(length($payload) / 4) + 1);
$mask = substr($mask, 0, length($payload));
@@ -2346,7 +2400,7 @@ sub wsMasking($$) {
Even though an internet connection is necessary as the initialization is triggered by a remote call.
Note: If the robot does not receive any messages for 30 seconds it will exit Manual Cleaning,
- but it will not close the websocket connection automaticaly.
+ but it will not close the websocket connection automatically.