From 512fe63b1e7adf4cb0bd3ee800b022c88c31a04c Mon Sep 17 00:00:00 2001
From: Ellert <>
Date: Fri, 13 Oct 2023 16:44:05 +0000
Subject: [PATCH] 74_AutomowerConnect: Commandref update Common.pm: add setter
for work zone start and stay out zone enabling/disabling. Zone handling is
for TESTING purpose implemented.
git-svn-id: https://svn.fhem.de/fhem/trunk@28048 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
fhem/CHANGED | 3 +
fhem/FHEM/74_AutomowerConnect.pm | 34 ++++++-
fhem/lib/FHEM/Devices/AMConnect/Common.pm | 109 ++++++++++++++++++----
3 files changed, 125 insertions(+), 21 deletions(-)
diff --git a/fhem/CHANGED b/fhem/CHANGED
index 6f5deb54a..2912b989a 100644
--- a/fhem/CHANGED
+++ b/fhem/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.
+ - feature: 74_AutomowerConnect: Commandref update, add Setter for work zone
+ start and stay out zone enabling/disabling.
+ Zone handling is for TESTING purpose
- feature: 76_SolarForecast: new consumer attr key 'noshow', minor fixes
- feature: 72_FRITZBOX - Log3 handling
- feature: 72_FB_CALLMONITOR - Log3 handling
diff --git a/fhem/FHEM/74_AutomowerConnect.pm b/fhem/FHEM/74_AutomowerConnect.pm
index a199ce5a6..8bd03fbf6 100644
--- a/fhem/FHEM/74_AutomowerConnect.pm
+++ b/fhem/FHEM/74_AutomowerConnect.pm
@@ -168,8 +168,9 @@ __END__
Starts immediately for <number of minutes>
StartInWorkArea
- set <name> StartInWorkArea <workAreaId> [<number of minutes>]
- Starts immediately in <workAreaId> for <number of minutes>
+ set <name> StartInWorkArea <workAreaId|name> [<number of minutes>]
+ Testing: Starts immediately in <workAreaId|name> for <number of minutes>
+ Zone name must not include space.
chargingStationPositionToAttribute
set <name> chargingStationPositionToAttribute
@@ -183,6 +184,14 @@ __END__
set <name> cuttingHeight <1..9>
Sets the cutting height. NOTE: Do not use for 550 EPOS and Ceora.
+ stayOutZone_enable
+ set <name> stayOutZone_enable <Id|name>
+ Testing: Enables stay out zone by Id or zone name. Zone name must not include space and contain at least one alphabetic character.
+
+ stayOutZone_disable
+ set <name> stayOutZone_disable <Id|name>
+ Testing: Disables stay out zone by Id or zone name. Zone name must not include space and contain at least one alphabetic character.
+
getNewAccessToken
set <name> getNewAccessToken
For debug purpose only.
@@ -418,6 +427,10 @@ __END__
Set timeout for API call, default 5 s.
The response time is meassured and logged if a timeout ist set to 60 s.
+ testing
+ attr <name> testing 1
+ Enables commands taged as Testing
+
@@ -531,8 +544,9 @@ __END__
Startet sofort für <number of minutes>
StartInWorkArea
- set <name> StartInWorkArea <workAreaId> [<number of minutes>]
- Startet sofort in <workAreaId> für <number of minutes>
+ set <name> StartInWorkArea <workAreaId|zone name> [<number of minutes>]
+ Testing: Startet sofort in <workAreaId|name> für <number of minutes>
+ Der Name der Zone darf keine Leerzeichen beinhalten und muss mindestens einen Buchstaben enthalten.
chargingStationPositionToAttribute
set <name> chargingStationPositionToAttribute
@@ -546,6 +560,14 @@ __END__
set <name> cuttingHeight <1..9>
Setzt die Schnitthöhe. HINWEIS: Nicht für 550 EPOS und Ceora geeignet.
+ stayOutZone_enable
+ set <name> stayOutZone_enable <Id|zone name>
+ Testing: Enabled stayOutZone für die Id oder den Namen der Zone, er darf keine Leerzeichen beinhalten und muss mindestens einen Buchstaben enthalten.
+
+ stayOutZone_disable
+ set <name> stayOutZone_disable <Id|zone name>
+ Testing: Disabled stayOutZone für die Id oder den Namen der Zone, er darf keine Leerzeichen beinhalten und muss mindestens einen Buchstaben enthalten.
+
getNewAccessToken
set <name> getNewAccessToken
Nur zur Fehlerbehebung.
@@ -785,6 +807,10 @@ __END__
Setzt den Timeout für Befehl senden, default 15 s.
Wird ein Timeout auf 60 s gesetzt, wird die Antwortzeit gemessen und geloggt.
+ testing
+ attr <name> testing 1
+ Macht Befehle verfügbar, die mit Testing markiert sind.
+
diff --git a/fhem/lib/FHEM/Devices/AMConnect/Common.pm b/fhem/lib/FHEM/Devices/AMConnect/Common.pm
index 30ae15fb8..ad318dae4 100644
--- a/fhem/lib/FHEM/Devices/AMConnect/Common.pm
+++ b/fhem/lib/FHEM/Devices/AMConnect/Common.pm
@@ -1053,6 +1053,7 @@ sub CMD {
my $type = $hash->{TYPE};
my $iam = "$type $name CMD:";
my $timeout = AttrVal( $name, 'timeoutCMD', $hash->{helper}->{timeout_cmd} );
+ my $method = 'POST';
$hash->{helper}{mower_commandSend} = $cmd[ 0 ] . ' ' . ( $cmd[ 1 ] ? $cmd[ 1 ] : '' );
if ( IsDisabled( $name ) ) {
@@ -1073,15 +1074,21 @@ sub CMD {
my $header = "Accept: application/vnd.api+json\r\nX-Api-Key: ".$client_id."\r\nAuthorization: Bearer " . $token . "\r\nAuthorization-Provider: " . $provider . "\r\nContent-Type: application/vnd.api+json";
- if ($cmd[0] eq "ParkUntilFurtherNotice") { $json = '{"data":{"type":"'.$cmd[0].'"}}'; $post = 'actions' }
- elsif ($cmd[0] eq "ParkUntilNextSchedule") { $json = '{"data": {"type":"'.$cmd[0].'"}}'; $post = 'actions' }
- elsif ($cmd[0] eq "ResumeSchedule") { $json = '{"data": {"type":"'.$cmd[0].'"}}'; $post = 'actions' }
- elsif ($cmd[0] eq "Pause") { $json = '{"data": {"type":"'.$cmd[0].'"}}'; $post = 'actions' }
- elsif ($cmd[0] eq "Park") { $json = '{"data": {"type":"'.$cmd[0].'","attributes":{"duration":'.$cmd[1].'}}}'; $post = 'actions' }
- elsif ($cmd[0] eq "Start") { $json = '{"data": {"type":"'.$cmd[0].'","attributes":{"duration":'.$cmd[1].'}}}'; $post = 'actions' }
- elsif ($cmd[0] eq "headlight") { $json = '{"data": {"type":"settings","attributes":{"'.$cmd[0].'": {"mode": "'.$cmd[1].'"}}}}'; $post = 'settings' }
- elsif ($cmd[0] eq "cuttingHeight") { $json = '{"data": {"type":"settings","attributes":{"'.$cmd[0].'": '.$cmd[1].'}}}'; $post = 'settings' }
- elsif ($cmd[0] eq "sendScheduleFromAttributeToMower" && AttrVal( $name, 'mowerSchedule', '')) {
+ if ($cmd[0] eq "ParkUntilFurtherNotice") { $json = '{"data":{"type":"'.$cmd[0].'"}}'; $post = 'actions' }
+ elsif ($cmd[0] eq "ParkUntilNextSchedule") { $json = '{"data": {"type":"'.$cmd[0].'"}}'; $post = 'actions' }
+ elsif ($cmd[0] eq "ResumeSchedule") { $json = '{"data": {"type":"'.$cmd[0].'"}}'; $post = 'actions' }
+ elsif ($cmd[0] eq "Pause") { $json = '{"data": {"type":"'.$cmd[0].'"}}'; $post = 'actions' }
+ elsif ($cmd[0] eq "Park") { $json = '{"data": {"type":"'.$cmd[0].'","attributes":{"duration":'.$cmd[1].'}}}'; $post = 'actions' }
+ elsif ($cmd[0] eq "Start") { $json = '{"data": {"type":"'.$cmd[0].'","attributes":{"duration":'.$cmd[1].'}}}'; $post = 'actions' }
+ elsif ($cmd[0] eq "StartInWorkArea" && $cmd[2])
+ { $json = '{"data": {"type":"'.$cmd[0].'","attributes":{"workAreaId":'.$cmd[1].',"duration":'.$cmd[2].'}}}'; $post = 'actions' }
+ elsif ($cmd[0] eq "StartInWorkArea" && !$cmd[2])
+ { $json = '{"data": {"type":"'.$cmd[0].'","attributes":{"workAreaId":'.$cmd[1].'}}}'; $post = 'actions' }
+ elsif ($cmd[0] eq "headlight") { $json = '{"data": {"type":"settings","attributes":{"'.$cmd[0].'": {"mode": "'.$cmd[1].'"}}}}'; $post = 'settings' }
+ elsif ($cmd[0] eq "cuttingHeight") { $json = '{"data": {"type":"settings","attributes":{"'.$cmd[0].'": '.$cmd[1].'}}}'; $post = 'settings' }
+ elsif ($cmd[0] eq "stayOutZone_enable") { $json = '{"data": {"type":"stayOutZone","id":"'.$cmd[1].'","attributes":{"enable": true}}}'; $post = 'stayOutZones/' . $cmd[1]; $method = 'PATCH' }
+ elsif ($cmd[0] eq "stayOutZone_disable") { $json = '{"data": {"type":"stayOutZone","id":"'.$cmd[1].'","attributes":{"enable": false}}}'; $post = 'stayOutZones/' . $cmd[1]; $method = 'PATCH' }
+ elsif ($cmd[0] eq "sendScheduleFromAttributeToMower" && AttrVal( $name, 'mowerSchedule', '')) {
my $perl = eval { decode_json (AttrVal( $name, 'mowerSchedule', '')) };
if ($@) {
@@ -1102,7 +1109,7 @@ my $header = "Accept: application/vnd.api+json\r\nX-Api-Key: ".$client_id."\r\nA
url => APIURL . "/mowers/". $mower_id . "/".$post,
timeout => $timeout,
hash => $hash,
- method => "POST",
+ method => $method,
header => $header,
data => $json,
callback => \&CMDResponse,
@@ -1121,7 +1128,7 @@ sub CMDResponse {
my $iam = "$type $name CMDResponse:";
Log3 $name, 1, "$iam response time ". sprintf( "%.2f", ( gettimeofday() - $param->{t_begin} ) ) . ' s' if ( $param->{timeout} == 60 );
- Log3 $name, 1, "\ndebug $iam \n\$statuscode [$statuscode]\n\$err [$err],\n \$data [$data] \n\$param->url $param->{url}" if ( AttrVal($name, 'debug', '') );
+ Log3 $name, 1, "\ndebug $iam \n\$statuscode >$statuscode<\n\$err >$err<,\n \$data >$data< \n\$param->url $param->{url}" if ( AttrVal($name, 'debug', '') );
if( !$err && $statuscode == 202 && $data ) {
@@ -1168,7 +1175,7 @@ sub CMDResponse {
readingsEndUpdate($hash, 1);
- Log3 $name, 2, "\n$iam \n\$statuscode [$statuscode]\n\$err [$err],\n\$data [$data]\n\$param->url $param->{url}";
+ Log3 $name, 2, "\n$iam \n\$statuscode >$statuscode<\n\$err >$err<,\n\$data >$data<\n\$param->url $param->{url}";
return undef;
}
@@ -1271,10 +1278,40 @@ sub Set {
CMD($hash,$setName);
return undef;
+ } elsif ( ReadingsVal( $name, 'device_state', 'defined' ) !~ /defined|initialized|authentification|authenticated|update/ && $setName =~ /^(StartInWorkArea)$/ && AttrVal( $name, 'testing', '' ) ) {
+
+ my $id = undef;
+ $id = name2id( $hash, $setVal, 'workAreas' ) if ( $setVal !~ /^(\d+)$/ );
+ $setVal = $id // $setVal;
+ if ( $setVal =~ /^(\d+)$/ && ( $setVal2 =~ /^(\d+)$/ or !$setVal2 ) ) { # && $hash->{helper}{mower}{attributes}{capabilities}{workAreas}
+
+ CMD($hash ,$setName, $setVal, $setVal2);
+ return undef;
+
+ }
+
+ Log3 $name, 2, "$iam $setName : no valid Id or zone name for $setVal .";
+
+ } elsif ( ReadingsVal( $name, 'device_state', 'defined' ) !~ /defined|initialized|authentification|authenticated|update/ && $setName =~ /^stayOutZone_(enable|disable)$/ && AttrVal( $name, 'testing', '' ) ) {
+
+ my $id = undef;
+ $id = name2id( $hash, $setVal, 'stayOutZones' ) if ( $setVal !~ /\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b/ );
+ $setVal = $id // $setVal;
+ if ( $setVal =~ /\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b/ ) { # && $hash->{helper}{mower}{attributes}{capabilities}{stayOutZones}
+
+ CMD($hash ,$setName, $setVal);
+ return undef;
+
+ }
+
+ Log3 $name, 2, "$iam $setName : no valid Id or zone name for $setVal .";
+
}
my $ret = " getNewAccessToken:noArg ParkUntilFurtherNotice:noArg ParkUntilNextSchedule:noArg Pause:noArg Start:selectnumbers,60,60,600,0,lin Park:selectnumbers,60,60,600,0,lin ResumeSchedule:noArg getUpdate:noArg client_secret ";
$ret .= "chargingStationPositionToAttribute:noArg headlight:ALWAYS_OFF,ALWAYS_ON,EVENING_ONLY,EVENING_AND_NIGHT cuttingHeight:1,2,3,4,5,6,7,8,9 mowerScheduleToAttribute:noArg ";
$ret .= "sendScheduleFromAttributeToMower:noArg defaultDesignAttributesToAttribute:noArg mapZonesTemplateToAttribute:noArg ";
+ $ret .= "StartInWorkArea " if ( $hash->{helper}{mower}{attributes}{capabilities}{workAreas} && AttrVal( $name, 'testing', '' ) );
+ $ret .= "stayOutZone_enable stayOutZone_disable " if ( $hash->{helper}{mower}{attributes}{capabilities}{stayOutZones} && AttrVal( $name, 'testing', '' ) );
return "Unknown argument $setName, choose one of".$ret;
}
@@ -1423,10 +1460,10 @@ sub Attr {
##########
} elsif ( $attrName eq 'numberOfWayPointsToDisplay' ) {
- return "$iam $attrVal is invalid, min value is 100." if ( $attrVal < 100 );
my $icurr = scalar @{$hash->{helper}{areapos}};
if( $cmd eq "set" && $attrVal =~ /\d+/ ) {
+ return "$iam $attrVal is invalid, min value is 100." if ( $attrVal < 100 );
# reduce array
$hash->{helper}{MOWING}{maxLength} = $attrVal;
for ( my $i = $icurr; $i > $attrVal; $i-- ) {
@@ -1586,6 +1623,36 @@ sub Attr {
return undef;
}
+#########################
+sub name2id {
+ my ( $hash, $zname, $ztype ) = @_;
+ $ztype = $ztype // 'workAreas';
+ if ( $ztype eq 'workAreas' && defined ( $hash->{helper}{mower}{attributes}{workAreas} ) ) {
+
+ my @ar = @{ $hash->{helper}{mower}{attributes}{workAreas} };
+ for ( @ar ) {
+
+ return $_->{workAreaId} if ( $_->{name} eq $zname );
+
+ }
+
+ } elsif ( $ztype eq 'stayOutZones' && defined( $hash->{helper}{mower}{attributes}{stayOutZones} ) && defined ( $hash->{helper}{mower}{attributes}{stayOutZones}{zones} ) ) {
+
+ if ( defined( $hash->{helper}{mower}{attributes}{stayOutZones}{dirty} ) && $hash->{helper}{mower}{attributes}{stayOutZones}{dirty} == 0) {
+
+ my @ar = @{ $hash->{helper}{mower}{attributes}{stayOutZones}{zones} };
+ for ( @ar ) {
+
+ return $_->{Id} if ( $_->{name} eq $zname );
+
+ }
+
+ }
+
+ }
+ return undef;
+}
+
#########################
sub AlignArray {
my ($hash) = @_;
@@ -2251,7 +2318,8 @@ sub listStatisticsData {
$ret .= ' $hash->{helper}{mower}{attributes}{statistics}{numberOfCollisions} | ' . $hash->{helper}{mower}{attributes}{statistics}{numberOfCollisions} . ' | |
';
$ret .= ' $hash->{helper}{mower}{attributes}{statistics}{totalChargingTime} | ' . sprintf( "%.0f", $hash->{helper}{mower}{attributes}{statistics}{totalChargingTime} / 3600 ) . ' | h |
';
$ret .= ' $hash->{helper}{mower}{attributes}{statistics}{totalCuttingTime} | ' . sprintf( "%.0f", $hash->{helper}{mower}{attributes}{statistics}{totalCuttingTime} / 3600 ) . ' | h |
';
- $ret .= ' $hash->{helper}{mower}{attributes}{statistics}{totalRunningTime} | ' . sprintf( "%.0f", $hash->{helper}{mower}{attributes}{statistics}{totalRunningTime} / 3600 ) . '1 | h |
';
+ $ret .= ' $hash->{helper}{mower}{attributes}{statistics}{totalDriveDistance} | ' . sprintf( "%.0f", $hash->{helper}{mower}{attributes}{statistics}{totalDriveDistance} / 1000 ) . '1 | km |
';
+ $ret .= ' $hash->{helper}{mower}{attributes}{statistics}{totalRunningTime} | ' . sprintf( "%.0f", $hash->{helper}{mower}{attributes}{statistics}{totalRunningTime} / 3600 ) . '2 | h |
';
$ret .= ' $hash->{helper}{mower}{attributes}{statistics}{totalSearchingTime} | ' . sprintf( "%.0f", $hash->{helper}{mower}{attributes}{statistics}{totalSearchingTime} / 3600 ) . ' | h |
';
my $prop = '';
@@ -2299,7 +2367,8 @@ sub listStatisticsData {
}
$ret .= '';
- $ret .= '1 totalRunningTime = totalCuttingTime + totalSearchingTime';
+ $ret .= '
1 totalDriveDistance = totalRunningTime * '. sprintf( "%.2f", $hash->{helper}{mower}{attributes}{statistics}{totalDriveDistance} / $hash->{helper}{mower}{attributes}{statistics}{totalRunningTime} ) if ( $hash->{helper}{mower}{attributes}{statistics}{totalRunningTime} );
+ $ret .= '
2 totalRunningTime = totalCuttingTime + totalSearchingTime';
$ret .= '