diff --git a/fhem/CHANGED b/fhem/CHANGED
index a4fff875e..74f695f53 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: rework detail view
+ getter for MowerData and StatisticsData
+ - feature: 75_AutomowerConnectDevice: same as AutomowerConnect
- feature: 93_DbLog: new Get menu for a selection of getters,
send Log data back to parent process, Forum:#131790
- change: 93_DbRep: ignore non-numeric values in diffValue and output
diff --git a/fhem/FHEM/74_AutomowerConnect.pm b/fhem/FHEM/74_AutomowerConnect.pm
index b51ea0085..8aad4176b 100644
--- a/fhem/FHEM/74_AutomowerConnect.pm
+++ b/fhem/FHEM/74_AutomowerConnect.pm
@@ -202,6 +202,17 @@ sub Define{
arrayName => '',
maxLength => 0,
callFn => ''
+ },
+ statistics => {
+ currentSpeed => 0,
+ currentDayTrack => 0,
+ currentDayArea => 0,
+ lastDayTrack => 0,
+ lastDayArea => 0,
+ currentWeekTrack => 0,
+ currentWeekArea => 0,
+ lastWeekTrack => 0,
+ lastWeekArea => 0
}
}
);
@@ -337,7 +348,6 @@ sub APIAuthResponse {
readingsBulkUpdateIfChanged($hash,'.expires',$hash->{helper}{auth}{expires},0 );
readingsBulkUpdateIfChanged($hash,'.scope',$hash->{helper}{auth}{scope},0 );
readingsBulkUpdateIfChanged($hash,'.token_type',$hash->{helper}{auth}{token_type},0 );
- readingsBulkUpdateIfChanged($hash,'.provider',$hash->{helper}{auth}{provider} );
my $expire_date = FmtDateTime($hash->{helper}{auth}{expires});
readingsBulkUpdateIfChanged($hash,'api_token_expires',$expire_date );
@@ -480,7 +490,6 @@ sub getMowerResponse {
readingsBulkUpdateIfChanged($hash, "batteryPercent", $hash->{helper}{mower}{attributes}{battery}{batteryPercent} );
readingsBulkUpdateIfChanged($hash, 'api_MowerFound', $foundMower );
my $pref = 'mower';
- readingsBulkUpdateIfChanged($hash, $pref.'_id', $hash->{helper}{mower}{id} );
readingsBulkUpdateIfChanged($hash, $pref.'_mode', $hash->{helper}{mower}{attributes}{$pref}{mode} );
readingsBulkUpdateIfChanged($hash, $pref.'_activity', $hash->{helper}{mower}{attributes}{$pref}{activity} );
readingsBulkUpdateIfChanged($hash, $pref.'_state', $hash->{helper}{mower}{attributes}{$pref}{state} );
@@ -497,8 +506,6 @@ sub getMowerResponse {
my $model = $hash->{helper}{mower}{attributes}{$pref}{model};
$model =~ s/AUTOMOWER./AM/;
$hash->{MODEL} = $model if ( $model && $hash->{MODEL} ne $model );
- # readingsBulkUpdateIfChanged($hash, $pref."_model", $model );
- readingsBulkUpdateIfChanged($hash, $pref."_serialNumber", $hash->{helper}{mower}{attributes}{$pref}{serialNumber} );
$pref = 'planner';
readingsBulkUpdateIfChanged($hash, "planner_restrictedReason", $hash->{helper}{mower}{attributes}{$pref}{restrictedReason} );
readingsBulkUpdateIfChanged($hash, "planner_overrideAction", $hash->{helper}{mower}{attributes}{$pref}{override}{action} );
@@ -507,12 +514,7 @@ sub getMowerResponse {
$timestamp = FmtDateTime($tstamp/1000);
readingsBulkUpdateIfChanged($hash, "planner_nextStart", $tstamp ? $timestamp : '-' );
$pref = 'statistics';
- readingsBulkUpdateIfChanged($hash, $pref."_numberOfChargingCycles", $hash->{helper}->{mower}{attributes}{$pref}{numberOfChargingCycles} );
- readingsBulkUpdateIfChanged($hash, $pref."_totalCuttingTime", $hash->{helper}->{mower}{attributes}{$pref}{totalCuttingTime} );
- readingsBulkUpdateIfChanged($hash, $pref."_totalChargingTime", $hash->{helper}->{mower}{attributes}{$pref}{totalChargingTime} );
- readingsBulkUpdateIfChanged($hash, $pref."_totalSearchingTime", $hash->{helper}->{mower}{attributes}{$pref}{totalSearchingTime} );
readingsBulkUpdateIfChanged($hash, $pref."_numberOfCollisions", $hash->{helper}->{mower}{attributes}{$pref}{numberOfCollisions} );
- readingsBulkUpdateIfChanged($hash, $pref."_totalRunningTime", $hash->{helper}->{mower}{attributes}{$pref}{totalRunningTime} );
$pref = 'settings';
readingsBulkUpdateIfChanged($hash, $pref."_headlight", $hash->{helper}->{mower}{attributes}{$pref}{headlight}{mode} );
readingsBulkUpdateIfChanged($hash, $pref."_cuttingHeight", $hash->{helper}->{mower}{attributes}{$pref}{cuttingHeight} );
@@ -521,9 +523,7 @@ sub getMowerResponse {
readingsBulkUpdateIfChanged($hash, $pref."_Timestamp", FmtDateTime( $hash->{helper}{mower}{attributes}{metadata}{statusTimestamp}/1000 ));
readingsBulkUpdateIfChanged($hash, $pref."_TimestampDiff", $storediff/1000 );
readingsBulkUpdateIfChanged($hash, $pref."_TimestampOld", FmtDateTime( $hash->{helper}{mowerold}{attributes}{metadata}{statusTimestamp}/1000 ));
- $pref = 'positions';
- readingsBulkUpdateIfChanged($hash, $pref."_lastLonLat", $hash->{helper}{mower}{attributes}{$pref}[0]{longitude} . ' ' . $hash->{helper}{mower}{attributes}{$pref}[0]{latitude} );
- readingsBulkUpdateIfChanged($hash, 'state', 'connected' );
+ readingsEndUpdate($hash, 1);
my @time = localtime();
my $secs = ( $time[2] * 3600 ) + ( $time[1] * 60 ) + $time[0];
@@ -531,23 +531,23 @@ sub getMowerResponse {
# do at midnight
if ( $secs <= $interval ) {
- readingsBulkUpdateIfChanged( $hash, 'statistics_lastDayTrack', ReadingsNum( $name, 'statistics_currentDayTrack', 0 ));
- readingsBulkUpdateIfChanged( $hash, 'statistics_lastDayArea', ReadingsNum( $name, 'statistics_currentDayArea', 0 ));
- readingsBulkUpdateIfChanged( $hash, 'statistics_currentWeekTrack', ReadingsNum( $name, 'statistics_currentWeekTrack', 0 ) + ReadingsNum( $name, 'statistics_currentDayTrack', 0 ));
- readingsBulkUpdateIfChanged( $hash, 'statistics_currentWeekArea', ReadingsNum( $name, 'statistics_currentWeekArea', 0 ) + ReadingsNum( $name, 'statistics_currentDayArea', 0 ));
- readingsBulkUpdateIfChanged( $hash, 'statistics_currentDayTrack', 0, 0);
- readingsBulkUpdateIfChanged( $hash, 'statistics_currentDayArea', 0, 0);
- # do on mondays
+ $hash->{helper}{statistics}{lastDayTrack} = $hash->{helper}{statistics}{currentDayTrack};
+ $hash->{helper}{statistics}{lastDayArea} = $hash->{helper}{statistics}{currentDayArea};
+ $hash->{helper}{statistics}{currentWeekTrack} += $hash->{helper}{statistics}{currentDayTrack};
+ $hash->{helper}{statistics}{currentWeekArea} += $hash->{helper}{statistics}{currentDayArea};
+ $hash->{helper}{statistics}{currentDayTrack} = 0;
+ $hash->{helper}{statistics}{currentDayArea} = 0;
+ # do on mondays
if ( $time[6] == 1 && $secs <= $interval ) {
- readingsBulkUpdateIfChanged( $hash, 'statistics_lastWeekTrack', ReadingsNum( $name, 'statistics_currentWeekTrack', 0 ));
- readingsBulkUpdateIfChanged( $hash, 'statistics_lastWeekArea', ReadingsNum( $name, 'statistics_currentWeekArea', 0 ));
- readingsBulkUpdateIfChanged( $hash, 'statistics_currentWeekTrack', 0, 0);
- readingsBulkUpdateIfChanged( $hash, 'statistics_currentWeekArea', 0, 0);
+ $hash->{helper}{statistics}{lastWeekTrack} = $hash->{helper}{statistics}{currentWeekTrack};
+ $hash->{helper}{statistics}{lastWeekArea} = $hash->{helper}{statistics}{currentWeekArea};
+ $hash->{helper}{statistics}{currentWeekTrack} = 0;
+ $hash->{helper}{statistics}{currentWeekArea} = 0;
}
}
- readingsEndUpdate($hash, 1);
+ readingsSingleUpdate($hash, 'state', 'connected', 1 );
RemoveInternalTimer( $hash, \&APIAuth );
InternalTimer( gettimeofday() + $interval, \&APIAuth, $hash, 0 );
@@ -699,19 +699,29 @@ sub Get {
my $ret = '' . FW_detailFn( undef, $name, undef, undef) . '';
return $ret;
- } elsif ( $setName eq 'listErrorCodes' ) {
+ } elsif ( $setName eq 'errorCodes' ) {
my $ret = listErrorCodes($hash);
return $ret;
- } elsif ( $setName eq 'listInternalData' ) {
+ } elsif ( $setName eq 'InternalData' ) {
my $ret = listInternalData($hash);
return $ret;
+ } elsif ( $setName eq 'MowerData' ) {
+
+ my $ret = listMowerData($hash);
+ return $ret;
+
+ } elsif ( $setName eq 'StatisticsData' ) {
+
+ my $ret = listStatisticsData($hash);
+ return $ret;
+
} else {
-
- return "Unknown argument $setName, choose one of listErrorCodes:noArg listInternalData:noArg ";
+
+ return "Unknown argument $setName, choose one of StatisticsData:noArg MowerData:noArg InternalData:noArg errorCodes:noArg ";
}
}
@@ -743,7 +753,7 @@ sub Set {
} elsif ( ReadingsVal( $name, 'state', 'defined' ) !~ /defined|initialized|authentification|authenticated|update/ && $setName eq 'mowerScheduleToAttribute' ) {
- my $calendarjson = JSON::XS->new->pretty(1)->encode ($hash->{helper}{mower}{attributes}{calendar}{tasks});
+ my $calendarjson = eval { JSON::XS->new->pretty(1)->encode ($hash->{helper}{mower}{attributes}{calendar}{tasks}) };
if ( $@ ) {
return "$iam $@";
}
@@ -1212,7 +1222,8 @@ sub ChargingStationPosition {
sub AreaStatistics {
my ($hash) = @_;
my $name = $hash->{NAME};
- my $i = $hash->{helper}{MOWING}{cnt};
+ my $activity = 'MOWING';
+ my $i = $hash->{helper}{$activity}{cnt};
my $k = 0;
my @xyarr = @{$hash->{helper}{areapos}};# areapos
my $n = @xyarr;
@@ -1223,19 +1234,22 @@ sub AreaStatistics {
my $vm = 0;
for ( $k = 0; $k <= $i-1; $k++) {
- $lsum += ((($xyarr[ $k ]{longitude} - $xyarr[ $k+1 ]{longitude}) * $sclon)**2 + (($xyarr[ $k ]{latitude} - $xyarr[ $k+1 ]{latitude}) * $sclat)**2)**0.5;
+
+ $lsum += ((($xyarr[ $k ]{longitude} - $xyarr[ $k+1 ]{longitude}) * $sclon)**2 + (($xyarr[ $k ]{latitude} - $xyarr[ $k+1 ]{latitude}) * $sclat)**2)**0.5;
+
}
+
$asum = $lsum * AttrVal($name,'mowerCuttingWidth',0.24);
my $td = $xyarr[ 0 ]{storedTimestamp} - $xyarr[ $k ]{storedTimestamp};
- $vm = sprintf( '%.6f', $lsum / $td ) * 1000 if ($td);
- $lsum += int( ReadingsNum( $name, 'statistics_currentDayTrack', 0 ) );
- $asum += int( ReadingsNum( $name, 'statistics_currentDayArea', 0 ) );
- readingsBeginUpdate($hash);
- readingsBulkUpdateIfChanged($hash,'statistics_currentDayTrack', int($lsum)); # m
- readingsBulkUpdateIfChanged($hash,'statistics_currentDayArea', int($asum)); # qm
- readingsBulkUpdateIfChanged($hash,'statistics_lastIntervalMowerSpeed', $vm); # m/s
- readingsBulkUpdateIfChanged($hash,'statistics_lastIntervalNumberOfWayPoints', $i-1); # m/s
- readingsEndUpdate($hash,1);
+ $vm = sprintf( '%.6f', $lsum / $td ) * 1000 if ($td); # m/s
+ $hash->{helper}{$activity}{speed} = $vm;
+ $hash->{helper}{$activity}{track} = $lsum;
+ $hash->{helper}{$activity}{area} = $asum;
+ $hash->{helper}{statistics}{currentSpeed} = $vm;
+ $hash->{helper}{statistics}{currentDayTrack} += $lsum;
+ $hash->{helper}{statistics}{currentDayArea} += $asum;
+ $hash->{helper}{statistics}{currentSpeed} = $vm;
+
return undef;
}
@@ -1335,6 +1349,89 @@ sub posMinMax {
return undef;
}
+#########################
+sub listStatisticsData {
+ my ( $hash ) = @_;
+ my $name = $hash->{NAME};
+ my $cnt = 0;
+ my $ret = '';
+ $ret .= '
';
+ $ret .= 'Statistics Data';
+
+ $ret .= '';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{numberOfChargingCycles} | ' . $hash->{helper}{mower}{attributes}{statistics}{numberOfChargingCycles} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{numberOfCollisions} | ' . $hash->{helper}{mower}{attributes}{statistics}{numberOfCollisions} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{totalChargingTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{totalChargingTime} . ' | s |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{totalCuttingTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{totalCuttingTime} . ' | s |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{totalRunningTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{totalRunningTime} . '1 | s |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{totalSearchingTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{totalSearchingTime} . ' | s |
';
+
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{currentSpeed} | ' . $hash->{helper}{statistics}{currentSpeed} . ' | m/s |
';
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{currentDayTrack} | ' . $hash->{helper}{statistics}{currentDayTrack} . ' | m |
';
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{currentDayArea} | ' . $hash->{helper}{statistics}{currentDayArea} . ' | qm |
';
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{lastDayTrack} | ' . $hash->{helper}{statistics}{lastDayTrack} . ' | m |
';
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{lastDayArea} | ' . $hash->{helper}{statistics}{lastDayArea} . ' | qm |
';
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{currentWeekTrack} | ' . $hash->{helper}{statistics}{currentWeekTrack} . ' | m |
';
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{currentWeekArea} | ' . $hash->{helper}{statistics}{currentWeekArea} . ' | qm |
';
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{lastWeekTrack} | ' . $hash->{helper}{statistics}{lastWeekTrack} . ' | m |
';
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{lastWeekArea} | ' . $hash->{helper}{statistics}{lastWeekArea} . ' | qm |
';
+
+ $ret .= '
';
+ $ret .= '1 totalRunningTime = totalCuttingTime + totalSearchingTime';
+ $ret .= '';
+
+ return $ret;
+}
+
+#########################
+sub listMowerData {
+ my ( $hash ) = @_;
+ my $name = $hash->{NAME};
+ my $cnt = 0;
+ my $ret = '';
+ $ret .= '
';
+ $ret .= 'Mower Data';
+
+ $ret .= '';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{type} | ' . $hash->{helper}{mower}{type} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{id} | ' . $hash->{helper}{mower}{id} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{system}{name} | ' . $hash->{helper}{mower}{attributes}{system}{name} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{system}{model} | ' . $hash->{helper}{mower}{attributes}{system}{model} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{system}{serialNumber} | ' . $hash->{helper}{mower}{attributes}{system}{serialNumber} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{battery}{batteryPercent} | ' . $hash->{helper}{mower}{attributes}{battery}{batteryPercent} . ' | % |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{mower}{mode} | ' . $hash->{helper}{mower}{attributes}{mower}{mode} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{mower}{activity} | ' . $hash->{helper}{mower}{attributes}{mower}{activity} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{mower}{state} | ' . $hash->{helper}{mower}{attributes}{mower}{state} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{mower}{errorCode} | ' . $hash->{helper}{mower}{attributes}{mower}{errorCode} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{mower}{errorCodeTimestamp} | ' . $hash->{helper}{mower}{attributes}{mower}{errorCodeTimestamp} . ' | ms |
';
+
+ my $calendarjson = eval { JSON::XS->new->pretty(1)->encode ($hash->{helper}{mower}{attributes}{calendar}{tasks}) };
+
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{calendar}{tasks} | ' . ($@ ? $@ : $calendarjson) . ' |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{planner}{nextStartTimestamp} | ' . $hash->{helper}{mower}{attributes}{planner}{nextStartTimestamp} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{planner}{override}{action} | ' . $hash->{helper}{mower}{attributes}{planner}{override}{action} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{planner}{restrictedReason} | ' . $hash->{helper}{mower}{attributes}{planner}{restrictedReason} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{metadata}{connected} | ' . $hash->{helper}{mower}{attributes}{metadata}{connected} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{metadata}{statusTimestamp} | ' . $hash->{helper}{mower}{attributes}{metadata}{statusTimestamp} . ' | ms |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{positions}[0]{longitude} | ' . $hash->{helper}{mower}{attributes}{positions}[0]{longitude} . ' | decimal degree |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{positions}[0]{latitude} | ' . $hash->{helper}{mower}{attributes}{positions}[0]{latitude} . ' | decimal degree |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{settings}{cuttingHeight} | ' . $hash->{helper}{mower}{attributes}{settings}{cuttingHeight} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{settings}{headlight}{mode} | ' . $hash->{helper}{mower}{attributes}{settings}{headlight}{mode} . ' | |
';
+# $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{cuttingBladeUsageTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{cuttingBladeUsageTime} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{numberOfChargingCycles} | ' . $hash->{helper}{mower}{attributes}{statistics}{numberOfChargingCycles} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{numberOfCollisions} | ' . $hash->{helper}{mower}{attributes}{statistics}{numberOfCollisions} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{totalChargingTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{totalChargingTime} . ' | s |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{totalCuttingTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{totalCuttingTime} . ' | s |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{totalRunningTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{totalRunningTime} . '1 | s |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{totalSearchingTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{totalSearchingTime} . ' | s |
';
+
+ $ret .= '
';
+ $ret .= '1 totalRunningTime = totalCuttingTime + totalSearchingTime';
+ $ret .= '';
+
+ return $ret;
+}
+
#########################
sub listInternalData {
my ( $hash ) = @_;
@@ -1376,9 +1473,17 @@ sub listInternalData {
if ( $hash->{TYPE} eq 'AutomowerConnect' ) {
$ret .= '
';
- $ret .= 'Access Token ( expires: ' . ReadingsVal( $name, 'api_token_expires', 'none') . ' ) ';
+ $ret .= 'Authentification Data';
- $ret .= '| ' . ReadingsVal( $name, '.access_token', 'none') . ' |
';
+ $ret .= '| Authentification URL | ' . AUTHURL . ' |
';
+ $ret .= '| Client-Id | ' . $hash->{helper}{client_id} . ' |
';
+ $ret .= '| Grant-Type | ' . $hash->{helper}{grant_type} . ' |
';
+ $ret .= '| User-Id | ' . ReadingsVal($name, '.user_id', '-') . ' |
';
+ $ret .= '| Provider | ' . ReadingsVal($name, '.provider', '-') . ' |
';
+ $ret .= '| Scope | ' . ReadingsVal($name, '.scope', '-') . ' |
';
+ $ret .= '| Token Type | ' . ReadingsVal($name, '.token_type', '-') . ' |
';
+ $ret .= '| Token Expires | ' . FmtDateTime( ReadingsVal($name, '.expires', '0') ) . ' |
';
+ $ret .= '| Access Token | ' . ReadingsVal($name, '.access_token', '0') . ' |
';
$ret .= '
';
@@ -1487,43 +1592,56 @@ sub listErrorCodes {
- Park
set <name> Park <number of minutes>
- Parks mower in charging station for <number of minutes>
+ Parks mower in charging station for <number of minutes>
+
- ParkUntilFurtherNotice
set <name> ParkUntilFurtherNotice
Parks mower in charging station until further notice
+
- ParkUntilNextSchedule
set <name> ParkUntilNextSchedule
Parks mower in charging station and starts with next planned start
+
- Pause
set <name> Pause
Pauses mower immediately at current position
+
- ResumeSchedule
set <name> ResumeSchedule
Starts immediately if in planned intervall, otherwise with next scheduled start>
+
- Start
set <name> Start <number of minutes>
Starts immediately for <number of minutes>
+
- chargingStationPositionToAttribute
set <name> chargingStationPositionToAttribute
Sets the calculated charging station coordinates to the corresponding attributes.
+
- client_secret
set <name> client_secret <application secret>
Sets the mandatory application secret (client secret)
+
- cuttingHeight
set <name> cuttingHeight <1..9>
Sets the cutting height. NOTE: Do not use for 550 EPOS and Ceora.
+
- getNewAccessToken
set <name> getNewAccessToken
Gets a new access token
+
- getUpdate
set <name> getUpdate
Gets data from the API. This is done each intervall automatically.
+
- headlight
set <name> headlight <ALWAYS_OFF|ALWAYS_ON|EVENIG_ONLY|EVENING_AND_NIGHT>
+
- - mowerScheduleToAttrbute
- set <name> mowerScheduleToAttrbute
+ - mowerScheduleToAttribute
+ set <name> mowerScheduleToAttribute
Writes the schedule in to the attribute moverSchedule.
+
- sendScheduleFromAttributeToMower
set <name> sendScheduleFromAttributeToMower
Sends the schedule to the mower. NOTE: Do not use for 550 EPOS and Ceora.
@@ -1543,12 +1661,22 @@ sub listErrorCodes {
get <name> html
Returns the mower area image as html code. For use in uiTable, TabletUI, Floorplan, readingsGroup, weblink etc.
- - listInternalData
- get <name> listInternalData
+ - InternalData
+ get <name> InternalData
Lists some device internal data
- - listErrorCodes
- get <name> listErrorCodes
+ - MowerData
+ get <name> MowerData
+ Lists all mower data with its hash path exept positon array. The hash path can be used for generating userReadings. The trigger is connected.
+ Example: created reading serialnumber with hash path $hash->{helper}{mower}{attributes}{system}{serialNumber}
+ attr <name> userReadings serialnumber:connected {$defs{$name}->{helper}{mower}{attributes}{system}{serialNumber}}
+
+ - StatisticsData
+ get <name> StatisticsData
+ Lists statistics data with its hash path. The hash path can be used for generating userReadings. The trigger is connected.
+
+ - errorCodes
+ get <name> errorCodes
Lists API response status codes and mower error codes
@@ -1640,47 +1768,27 @@ sub listErrorCodes {
- api_MowerFound - all mower registered under the application key (client_id)
- api_token_expires - date when session of Husqvarna Cloud expires
- - api_access_token - current session token (shortend) of Husqvarna Cloud
- batteryPercent - battery state of charge in percent
- mower_activity - current activity "UNKNOWN" | "NOT_APPLICABLE" | "MOWING" | "GOING_HOME" | "CHARGING" | "LEAVING" | "PARKED_IN_CS" | "STOPPED_IN_GARDEN"
- mower_commandStatus - Status of the last sent command cleared each status update
- mower_errorCode - last error code
- mower_errorCodeTimestamp - last error code time stamp
- mower_errorDescription - error description
- - mower_id - ID of the mower
- mower_mode - current working mode "MAIN_AREA" | "SECONDARY_AREA" | "HOME" | "DEMO" | "UNKNOWN"
- mower_state - current status "UNKNOWN" | "NOT_APPLICABLE" | "PAUSED" | "IN_OPERATION" | "WAIT_UPDATING" | "WAIT_POWER_UP" | "RESTRICTED" | "OFF" | "STOPPED" | "ERROR" | "FATAL_ERROR" |"ERROR_AT_POWER_UP"
- planner_nextStart - next start time
- planner_restrictedReason - reason for parking NONE, WEEK_SCHEDULE, PARK_OVERRIDE, SENSOR, DAILY_LIMIT, FOTA, FROST
- planner_overrideAction - reason for override a planned action NOT_ACTIVE, FORCE_PARK, FORCE_MOW
- - positions_lastLonLat - last known position (longitude latitude)
- state - status of connection FHEM to Husqvarna Cloud API and device state(e.g. defined, authorization, authorized, connected, error, update)
- - status_statusTimestampOld - local time of second last change of the API content
- settings_cuttingHeight - actual cutting height from API
- settings_headlight - actual headlight mode from API
- statistics_newGeoDataSets - number of new data sets between the last two different time stamps
- - statistics_numberOfChargingCycles - number of charging cycles
- - statistics_numberOfCollisions - number of collisions
- - statistics_totalChargingTime - total charging time in hours
- - statistics_totalCuttingTime - total cutting time in hours
- - statistics_totalRunningTime - total running time in hours
- - statistics_totalSearchingTime - total searching time in hours
- - statistics_currentDayTrack - calculated mowed track length in meter during mower_activity MOWING since midnight
- - statistics_currentDayArea - calculated mowed area in square meter during mower_activity MOWING since midnight
- - statistics_lastIntervalNumberOfWayPoints - last Intervals Number of way points
- - statistics_currentMowerSpeed - calculated mower speed in meter per second during mower_activity MOWING for the last interval
- - statistics_lastDayTrack - calculated mowed track length in meter during mower_activity MOWING for yesterday
- - statistics_lastDayArea - calculated mowed area in square meter during mower_activity MOWING for yesterday
- - statistics_currentWeekTrack - calculated mowed track length in meter during mower_activity MOWING of the current week
- - statistics_currentWeekArea - calculated mowed area in square meter during mower_activity MOWING of the current week
- - statistics_lastWeekTrack - calculated mowed track length in meter during mower_activity MOWING of the last week
- - statistics_lastWeekArea - calculated mowed area in square meter during mower_activity MOWING of the last week
+ - statistics_numberOfCollisions - Number of Collisions
- status_connected - state of connetion between mower and Husqvarna Cloud, (1 => true, 0 => false)
- status_statusTimestamp - local time of last change of the API content
- status_statusTimestampDiff - time difference in seconds between the last and second last change of the API content
- status_statusTimestampOld - local time of second last change of the API content
- system_name - name of the mower
- - system_serialNumber - serial number of the mower
@@ -1747,43 +1855,56 @@ sub listErrorCodes {
- Park
set <name> Park <number of minutes>
- Parkt den Mäher in der Ladestation (LS) für <number of minutes>
+ Parkt den Mäher in der Ladestation (LS) für <number of minutes>
+
- ParkUntilFurtherNotice
set <name> ParkUntilFurtherNotice
Parkt den Mäher bis auf Weiteres in der LS
+
- ParkUntilNextSchedule
set <name> ParkUntilNextSchedule
Parkt den Mäher bis auf Weiteres in der LS und startet zum nächsten geplanten Zeitpunkt
+
- Pause
set <name> Pause
Pausiert den Mäher sofort am aktuellen Standort
+
- ResumeSchedule
set <name> ResumeSchedule
Startet im geplanten Interval den Mäher sofort, sonst zum nächsten geplanten Zeitpunkt
+
- Start
set <name> Start <number of minutes>
Startet sofort für <number of minutes>
+
- chargingStationPositionToAttribute
set <name> chargingStationPositionToAttribute
Setzt die berechneten Koordinaten der LS in das entsprechende Attribut.
+
- client_secret
set <name> client_secret <application secret>
Setzt das erforderliche Application Secret (client secret)
+
- cuttingHeight
set <name> cuttingHeight <1..9>
Setzt die Schnitthöhe. HINWEIS: Nicht für 550 EPOS und Ceora geeignet.
+
- getNewAccessToken
set <name> getNewAccessToken
Holt ein neues Access Token.
+
- getUpdate
set <name> getUpdate
Liest die Daten von der API. Das passiert jedes Interval automatisch.
+
- headlight
set <name> headlight <ALWAYS_OFF|ALWAYS_ON|EVENIG_ONLY|EVENING_AND_NIGHT>
Setzt den Scheinwerfermode
- - mowerScheduleToAttrbute
- set <name> mowerScheduleToAttrbute
+
+ - mowerScheduleToAttribute
+ set <name> mowerScheduleToAttribute
Schreibt den Mähplan ins Attribut moverSchedule.
+
- sendScheduleFromAttributeToMower
set <name> sendScheduleFromAttributeToMower
Sendet den Mähplan zum Mäher. HINWEIS: Nicht für 550 EPOS und Ceora geeignet.
@@ -1799,13 +1920,23 @@ sub listErrorCodes {
get <name> html
Gibt das Bild des Mäherbereiches html kodiert zurück, zur Verwendung in uiTable, TabletUI, Floorplan, readingsGroup, weblink usw.
- - listErrorCodes
- get <name> listErrorCodes
+ - errorCodes
+ get <name> errorCodes
Listet die Statuscode der API-Anfrage und die Fehlercodes des Mähroboters auf.
- - listInternalData
- get <name> listErrorCodes
+ - InternalData
+ get <name> InternalData
Listet einige Daten des FHEM-Gerätes auf.
+
+ - MowerData
+ get <name> MowerData
+ Listet alle Daten des Mähers einschließlich Hashpfad auf ausgenommen das Positonsarray. Der Hashpfad kann zur Erzeugung von userReadings genutzt werden, getriggert wird durch connected.
+ Beispiel: erzeugen des Reading serialnumber mit dem Hashpfad $hash->{helper}{mower}{attributes}{system}{serialNumber}
+ attr <name> userReadings serialnumber:connected {$defs{$name}->{helper}{mower}{attributes}{system}{serialNumber}}
+
+ - StatisticsData
+ get <name> StatisticsData
+ Listet statistische Daten mit ihrem Hashpfad auf. Der Hashpfad kann zur Erzeugung von userReadings genutzt werden, getriggert wird durch connected
@@ -1902,46 +2033,27 @@ sub listErrorCodes {
- api_MowerFound - Alle Mähroboter, die unter dem genutzten Application Key (client_id) registriert sind.
- api_token_expires - Datum wann die Session der Husqvarna Cloud abläuft
- - api_access_token - aktueller Sitzungstoken (gekürzt) für die Husqvarna Cloud
- batteryPercent - Batterieladung in Prozent
- mower_activity - aktuelle Aktivität "UNKNOWN" | "NOT_APPLICABLE" | "MOWING" | "GOING_HOME" | "CHARGING" | "LEAVING" | "PARKED_IN_CS" | "STOPPED_IN_GARDEN"
- mower_commandStatus - Status des letzten uebermittelten Kommandos wird duch Statusupdate zurückgesetzt.
- mower_errorCode - last error code
- mower_errorCodeTimestamp - last error code time stamp
- mower_errorDescription - error description
- - mower_id - ID des Automowers
- mower_mode - aktueller Arbeitsmodus "MAIN_AREA" | "SECONDARY_AREA" | "HOME" | "DEMO" | "UNKNOWN"
- mower_state - aktueller Status "UNKNOWN" | "NOT_APPLICABLE" | "PAUSED" | "IN_OPERATION" | "WAIT_UPDATING" | "WAIT_POWER_UP" | "RESTRICTED" | "OFF" | "STOPPED" | "ERROR" | "FATAL_ERROR" |"ERROR_AT_POWER_UP"
- planner_nextStart - nächste Startzeit
- planner_restrictedReason - Grund für Parken NONE, WEEK_SCHEDULE, PARK_OVERRIDE, SENSOR, DAILY_LIMIT, FOTA, FROST
- planner_overrideAction - Grund für vorrangige Aktion NOT_ACTIVE, FORCE_PARK, FORCE_MOW
- - positions_lastLonLat - letzte bekannte Position (Längengrad Breitengrad)
- state - Status der Verbindung des FHEM-Gerätes zur Husqvarna Cloud API (defined, authentification, authentified, connected, error, update).
- settings_cuttingHeight - aktuelle Schnitthöhe aus der API
- settings_headlight - aktueller Scheinwerfermode aus der API
- statistics_newGeoDataSets - Anzahl der neuen Datensätze zwischen den letzten zwei unterschiedlichen Zeitstempeln
- - statistics_numberOfChargingCycles - Anzahl der Ladezyklen
- statistics_numberOfCollisions - Anzahl der Kollisionen
- - statistics_totalChargingTime - Gesamtladezeit in Stunden
- - statistics_totalCuttingTime - Gesamtschneidezeit in Stunden
- - statistics_totalRunningTime - Gesamtlaufzeit in Stunden
- - statistics_totalSearchingTime - Gesamtsuchzeit in Stunden
- - statistics_currentDayTrack - berechnete gefahrene Strecke in Meter bei_Activity MOWING seit Mitternacht
- - statistics_currentDayArea - berechnete übermähte Fläche in Quadratmeter bei der Activity MOWING seit Mitternacht
- - statistics_lastIntervalNumberOfWayPoints - Anzahl der Wegpunkte im letzten Interval
- - statistics_currentMowerSpeed - berechnet Geschwindigkeit in Meter pro Sekunde bei der_Activity MOWING im letzten Interval
- - statistics_lastDayTrack - berechnete gefahrene Strecke in Meter bei_Activity MOWING des letzten Tages
- - statistics_lastDayArea - berechnete übermähte Fläche in Quadratmeter bei der Activity MOWING des letzten Tages
- - statistics_currentWeekTrack - berechnete gefahrene Strecke in Meter bei_Activity MOWING
- - statistics_currentWeekArea - berechnete übermähte Fläche in Quadratmeter bei der Activity MOWING der laufenden Woche
- - statistics_lastWeekTrack - berechnete gefahrene Strecke in Meter bei_Activity MOWING der letzten Woche
- - statistics_lastWeekArea - berechnete übermähte Fläche in Quadratmeter bei der Activity MOWING der letzten Woche
- status_connected - Status der Verbindung zwischen dem Automower und der Husqvarna Cloud, (1 => true, 0 => false)
- status_statusTimestamp - Lokalzeit der letzten Änderung der Daten in der API
- - status_statusTimestampDiff - Zeitdifferenz zwichen den beiden letzten Änderungen im Inhalt der Daten aus der API
+ - status_statusTimestampDiff - Zeitdifferenz zwischen den beiden letzten Änderungen im Inhalt der Daten aus der API
- status_statusTimestampOld - Lokalzeit der vorletzten Änderung der Daten in der API
- system_name - Name des Automowers
- - system_serialNumber - Seriennummer des Automowers
diff --git a/fhem/FHEM/75_AutomowerConnectDevice.pm b/fhem/FHEM/75_AutomowerConnectDevice.pm
index 73990d5ae..5bbd0745f 100644
--- a/fhem/FHEM/75_AutomowerConnectDevice.pm
+++ b/fhem/FHEM/75_AutomowerConnectDevice.pm
@@ -193,6 +193,17 @@ sub Define{
arrayName => '',
maxLength => 0,
callFn => ''
+ },
+ statistics => {
+ currentSpeed => 0,
+ currentDayTrack => 0,
+ currentDayArea => 0,
+ lastDayTrack => 0,
+ lastDayArea => 0,
+ currentWeekTrack => 0,
+ currentWeekArea => 0,
+ lastWeekTrack => 0,
+ lastWeekArea => 0
}
}
);
@@ -332,12 +343,7 @@ sub Notify {
$timestamp = FmtDateTime($tstamp/1000);
readingsBulkUpdateIfChanged($hash, "planner_nextStart", $tstamp ? $timestamp : '-' );
$pref = 'statistics';
- readingsBulkUpdateIfChanged($hash, $pref."_numberOfChargingCycles", $hash->{helper}->{mower}{attributes}{$pref}{numberOfChargingCycles} );
- readingsBulkUpdateIfChanged($hash, $pref."_totalCuttingTime", $hash->{helper}->{mower}{attributes}{$pref}{totalCuttingTime} );
- readingsBulkUpdateIfChanged($hash, $pref."_totalChargingTime", $hash->{helper}->{mower}{attributes}{$pref}{totalChargingTime} );
- readingsBulkUpdateIfChanged($hash, $pref."_totalSearchingTime", $hash->{helper}->{mower}{attributes}{$pref}{totalSearchingTime} );
readingsBulkUpdateIfChanged($hash, $pref."_numberOfCollisions", $hash->{helper}->{mower}{attributes}{$pref}{numberOfCollisions} );
- readingsBulkUpdateIfChanged($hash, $pref."_totalRunningTime", $hash->{helper}->{mower}{attributes}{$pref}{totalRunningTime} );
$pref = 'settings';
readingsBulkUpdateIfChanged($hash, $pref."_headlight", $hash->{helper}->{mower}{attributes}{$pref}{headlight}{mode} );
readingsBulkUpdateIfChanged($hash, $pref."_cuttingHeight", $hash->{helper}->{mower}{attributes}{$pref}{cuttingHeight} );
@@ -348,7 +354,8 @@ sub Notify {
readingsBulkUpdateIfChanged($hash, $pref."_TimestampOld", FmtDateTime( $hash->{helper}{mowerold}{attributes}{metadata}{statusTimestamp}/1000 ));
$pref = 'positions';
readingsBulkUpdateIfChanged($hash, $pref."_lastLonLat", $hash->{helper}{mower}{attributes}{$pref}[0]{longitude} . ' ' . $hash->{helper}{mower}{attributes}{$pref}[0]{latitude} );
- readingsBulkUpdateIfChanged($hash, 'state', 'connected' );
+ readingsBulkUpdate($hash, 'state', 'connected',1);
+ readingsEndUpdate($hash, 1);
my @time = localtime();
my $secs = ( $time[2] * 3600 ) + ( $time[1] * 60 ) + $time[0];
@@ -356,23 +363,24 @@ sub Notify {
# do at midnight
if ( $secs <= $interval ) {
- readingsBulkUpdateIfChanged( $hash, 'statistics_lastDayTrack', ReadingsNum( $name, 'statistics_currentDayTrack', 0 ));
- readingsBulkUpdateIfChanged( $hash, 'statistics_lastDayArea', ReadingsNum( $name, 'statistics_currentDayArea', 0 ));
- readingsBulkUpdateIfChanged( $hash, 'statistics_currentWeekTrack', ReadingsNum( $name, 'statistics_currentWeekTrack', 0 ) + ReadingsNum( $name, 'statistics_currentDayTrack', 0 ));
- readingsBulkUpdateIfChanged( $hash, 'statistics_currentWeekArea', ReadingsNum( $name, 'statistics_currentWeekArea', 0 ) + ReadingsNum( $name, 'statistics_currentDayArea', 0 ));
- readingsBulkUpdateIfChanged( $hash, 'statistics_currentDayTrack', 0, 0);
- readingsBulkUpdateIfChanged( $hash, 'statistics_currentDayArea', 0, 0);
- # do on mondays
- if ( $time[6] == 1 && $secs <= $interval ) {
+ $hash->{helper}{statistics}{lastDayTrack} = $hash->{helper}{statistics}{currentDayTrack};
+ $hash->{helper}{statistics}{lastDayArea} = $hash->{helper}{statistics}{currentDayArea};
+ $hash->{helper}{statistics}{currentWeekTrack} += $hash->{helper}{statistics}{currentDayTrack};
+ $hash->{helper}{statistics}{currentWeekArea} += $hash->{helper}{statistics}{currentDayArea};
+ $hash->{helper}{statistics}{currentDayTrack} = 0;
+ $hash->{helper}{statistics}{currentDayArea} = 0;
+ # do on mondays
+ if ( $time[6] == 1 && $secs <= $interval ) {
- readingsBulkUpdateIfChanged( $hash, 'statistics_lastWeekTrack', ReadingsNum( $name, 'statistics_currentWeekTrack', 0 ));
- readingsBulkUpdateIfChanged( $hash, 'statistics_lastWeekArea', ReadingsNum( $name, 'statistics_currentWeekArea', 0 ));
- readingsBulkUpdateIfChanged( $hash, 'statistics_currentWeekTrack', 0, 0);
- readingsBulkUpdateIfChanged( $hash, 'statistics_currentWeekArea', 0, 0);
+ $hash->{helper}{statistics}{lastWeekTrack} = $hash->{helper}{statistics}{currentWeekTrack};
+ $hash->{helper}{statistics}{lastWeekArea} = $hash->{helper}{statistics}{currentWeekArea};
+ $hash->{helper}{statistics}{currentWeekTrack} = 0;
+ $hash->{helper}{statistics}{currentWeekArea} = 0;
}
}
- readingsEndUpdate($hash, 1);
+ readingsSingleUpdate($hash, 'state', 'connected',1);
+
}
return undef;
@@ -520,18 +528,29 @@ sub Get {
my $ret = '' . FW_detailFn( undef, $name, undef, undef) . '';
return $ret;
- } elsif ( $setName eq 'listErrorCodes' ) {
+ } elsif ( $setName eq 'errorCodes' ) {
my $ret = listErrorCodes($hash);
return $ret;
- } elsif ( $setName eq 'listInternalData' ) {
+ } elsif ( $setName eq 'InternalData' ) {
my $ret = listInternalData($hash);
return $ret;
+
+ } elsif ( $setName eq 'MowerData' ) {
+
+ my $ret = listMowerData($hash);
+ return $ret;
+
+ } elsif ( $setName eq 'StatisticsData' ) {
+
+ my $ret = listStatisticsData($hash);
+ return $ret;
+
} else {
-
- return "Unknown argument $setName, choose one of listInternalData:noArg listErrorCodes:noArg ";
+
+ return "Unknown argument $setName, choose one of StatisticsData:noArg MowerData:noArg InternalData:noArg errorCodes:noArg ";
}
}
@@ -962,8 +981,8 @@ sub ChargingStationPosition {
my $ym = 0;
map { $ym += $_->{latitude} } @{$hash->{helper}{cspos}};
$ym = $ym/$n;
- $hash->{helper}{chargingStation}{longitude} = int($xm * 10000000 + 0.5) / 10000000;
- $hash->{helper}{chargingStation}{latitude} = int($ym * 10000000 + 0.5) / 10000000;
+ $hash->{helper}{chargingStation}{longitude} = sprintf("%.8f",$xm);
+ $hash->{helper}{chargingStation}{latitude} = sprintf("%.8f",$ym);
return undef;
}
@@ -971,6 +990,7 @@ sub ChargingStationPosition {
sub AreaStatistics {
my ($hash) = @_;
my $name = $hash->{NAME};
+ my $activity = 'MOWING';
my $i = $hash->{helper}{MOWING}{cnt};
my $k = 0;
my @xyarr = @{$hash->{helper}{areapos}};# areapos
@@ -984,19 +1004,18 @@ sub AreaStatistics {
my $vm = 0;
for ( $k = 0; $k <= $i-1; $k++) {
- $lsum += ((($xyarr[ $k ]{longitude} - $xyarr[ $k+1 ]{longitude}) * $sclon)**2 + (($xyarr[ $k ]{latitude} - $xyarr[ $k+1 ]{latitude}) * $sclat)**2)**0.5;
+ $lsum += ((($xyarr[ $k ]{longitude} - $xyarr[ $k+1 ]{longitude}) * $sclon)**2 + (($xyarr[ $k ]{latitude} - $xyarr[ $k+1 ]{latitude}) * $sclat)**2)**0.5; # m
}
- $asum = $lsum * AttrVal($name,'mowerCuttingWidth',0.24);
+ $asum = $lsum * AttrVal($name,'mowerCuttingWidth',0.24); # qm
my $td = $xyarr[ 0 ]{storedTimestamp} - $xyarr[ $k ]{storedTimestamp};
- $vm = int($lsum / $td * 1000000 + 0.5)/1000 if ($td);
- $lsum += int( ReadingsNum( $name, 'statistics_currentDayTrack', 0 ) );
- $asum += int( ReadingsNum( $name, 'statistics_currentDayArea', 0 ) );
- readingsBeginUpdate($hash);
- readingsBulkUpdateIfChanged($hash,'statistics_currentDayTrack', int($lsum)); # m
- readingsBulkUpdateIfChanged($hash,'statistics_currentDayArea', int($asum)); # qm
- readingsBulkUpdateIfChanged($hash,'statistics_lastIntervalMowerSpeed', $vm); # m/s
- readingsBulkUpdateIfChanged($hash,'statistics_lastIntervalNumberOfWayPoints', $i-1); # m/s
- readingsEndUpdate($hash,1);
+ $vm = sprintf( '%.6f', $lsum / $td ) * 1000 if ($td); # m/s
+ $hash->{helper}{$activity}{speed} = $vm;
+ $hash->{helper}{$activity}{track} = $lsum;
+ $hash->{helper}{$activity}{area} = $asum;
+ $hash->{helper}{statistics}{currentSpeed} = $vm;
+ $hash->{helper}{statistics}{currentDayTrack} += $lsum;
+ $hash->{helper}{statistics}{currentDayArea} += $asum;
+ $hash->{helper}{statistics}{currentSpeed} = $vm;
return undef;
}
@@ -1096,6 +1115,89 @@ sub posMinMax {
return undef;
}
+#########################
+sub listStatisticsData {
+ my ( $hash ) = @_;
+ my $name = $hash->{NAME};
+ my $cnt = 0;
+ my $ret = '';
+ $ret .= '';
+ $ret .= 'Statistics Data';
+
+ $ret .= '';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{numberOfChargingCycles} | ' . $hash->{helper}{mower}{attributes}{statistics}{numberOfChargingCycles} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{numberOfCollisions} | ' . $hash->{helper}{mower}{attributes}{statistics}{numberOfCollisions} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{totalChargingTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{totalChargingTime} . ' | s |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{totalCuttingTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{totalCuttingTime} . ' | s |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{totalRunningTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{totalRunningTime} . '1 | s |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{totalSearchingTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{totalSearchingTime} . ' | s |
';
+
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{currentSpeed} | ' . $hash->{helper}{statistics}{currentSpeed} . ' | m/s |
';
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{currentDayTrack} | ' . $hash->{helper}{statistics}{currentDayTrack} . ' | m |
';
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{currentDayArea} | ' . $hash->{helper}{statistics}{currentDayArea} . ' | qm |
';
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{lastDayTrack} | ' . $hash->{helper}{statistics}{lastDayTrack} . ' | m |
';
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{lastDayArea} | ' . $hash->{helper}{statistics}{lastDayArea} . ' | qm |
';
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{currentWeekTrack} | ' . $hash->{helper}{statistics}{currentWeekTrack} . ' | m |
';
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{currentWeekArea} | ' . $hash->{helper}{statistics}{currentWeekArea} . ' | qm |
';
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{lastWeekTrack} | ' . $hash->{helper}{statistics}{lastWeekTrack} . ' | m |
';
+ $cnt++;$ret .= '| $hash->{helper}{statistics}{lastWeekArea} | ' . $hash->{helper}{statistics}{lastWeekArea} . ' | qm |
';
+
+ $ret .= '
';
+ $ret .= '1 totalRunningTime = totalCuttingTime + totalSearchingTime';
+ $ret .= '';
+
+ return $ret;
+}
+
+#########################
+sub listMowerData {
+ my ( $hash ) = @_;
+ my $name = $hash->{NAME};
+ my $cnt = 0;
+ my $ret = '';
+ $ret .= '
';
+ $ret .= 'Mower Data';
+
+ $ret .= '';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{type} | ' . $hash->{helper}{mower}{type} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{id} | ' . $hash->{helper}{mower}{id} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{system}{name} | ' . $hash->{helper}{mower}{attributes}{system}{name} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{system}{model} | ' . $hash->{helper}{mower}{attributes}{system}{model} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{system}{serialNumber} | ' . $hash->{helper}{mower}{attributes}{system}{serialNumber} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{battery}{batteryPercent} | ' . $hash->{helper}{mower}{attributes}{battery}{batteryPercent} . ' | % |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{mower}{mode} | ' . $hash->{helper}{mower}{attributes}{mower}{mode} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{mower}{activity} | ' . $hash->{helper}{mower}{attributes}{mower}{activity} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{mower}{state} | ' . $hash->{helper}{mower}{attributes}{mower}{state} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{mower}{errorCode} | ' . $hash->{helper}{mower}{attributes}{mower}{errorCode} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{mower}{errorCodeTimestamp} | ' . $hash->{helper}{mower}{attributes}{mower}{errorCodeTimestamp} . ' | ms |
';
+
+ my $calendarjson = eval { JSON::XS->new->pretty(1)->encode ($hash->{helper}{mower}{attributes}{calendar}{tasks}) };
+
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{calendar}{tasks} | ' . ($@ ? $@ : $calendarjson) . ' |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{planner}{nextStartTimestamp} | ' . $hash->{helper}{mower}{attributes}{planner}{nextStartTimestamp} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{planner}{override}{action} | ' . $hash->{helper}{mower}{attributes}{planner}{override}{action} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{planner}{restrictedReason} | ' . $hash->{helper}{mower}{attributes}{planner}{restrictedReason} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{metadata}{connected} | ' . $hash->{helper}{mower}{attributes}{metadata}{connected} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{metadata}{statusTimestamp} | ' . $hash->{helper}{mower}{attributes}{metadata}{statusTimestamp} . ' | ms |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{positions}[0]{longitude} | ' . $hash->{helper}{mower}{attributes}{positions}[0]{longitude} . ' | decimal degree |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{positions}[0]{latitude} | ' . $hash->{helper}{mower}{attributes}{positions}[0]{latitude} . ' | decimal degree |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{settings}{cuttingHeight} | ' . $hash->{helper}{mower}{attributes}{settings}{cuttingHeight} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{settings}{headlight}{mode} | ' . $hash->{helper}{mower}{attributes}{settings}{headlight}{mode} . ' | |
';
+# $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{cuttingBladeUsageTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{cuttingBladeUsageTime} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{numberOfChargingCycles} | ' . $hash->{helper}{mower}{attributes}{statistics}{numberOfChargingCycles} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{numberOfCollisions} | ' . $hash->{helper}{mower}{attributes}{statistics}{numberOfCollisions} . ' | |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{totalChargingTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{totalChargingTime} . ' | s |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{totalCuttingTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{totalCuttingTime} . ' | s |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{totalRunningTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{totalRunningTime} . '1 | s |
';
+ $cnt++;$ret .= '| $hash->{helper}{mower}{attributes}{statistics}{totalSearchingTime} | ' . $hash->{helper}{mower}{attributes}{statistics}{totalSearchingTime} . ' | s |
';
+
+ $ret .= '
';
+ $ret .= '1 totalRunningTime = totalCuttingTime + totalSearchingTime';
+ $ret .= '';
+
+ return $ret;
+}
+
#########################
sub listInternalData {
my ( $hash ) = @_;
@@ -1233,34 +1335,43 @@ sub listErrorCodes {
- Park
set <name> Park <number of minutes>
- Parks mower in charging station for <number of minutes>
+ Parks mower in charging station for <number of minutes>
+
- ParkUntilFurtherNotice
set <name> ParkUntilFurtherNotice
Parks mower in charging station until further notice
+
- ParkUntilNextSchedule
set <name> ParkUntilNextSchedule
Parks mower in charging station and starts with next planned start
+
- Pause
set <name> Pause
Pauses mower immediately at current position
+
- ResumeSchedule
set <name> ResumeSchedule
Starts immediately if in planned intervall, otherwise with next scheduled start>
+
- Start
set <name> Start <number of minutes>
Starts immediately for <number of minutes>
+
- chargingStationPositionToAttribute
set <name> chargingStationPositionToAttribute
Sets the calculated charging station coordinates to the corresponding attributes.
+
- cuttingHeight
set <name> cuttingHeight <1..9>
Sets the cutting height. NOTE: Do not use for 550 EPOS and Ceora.
+
- headlight
set <name> headlight <ALWAYS_OFF|ALWAYS_ON|EVENIG_ONLY|EVENING_AND_NIGHT>
- - mowerScheduleToAttrbute
- set <name> mowerScheduleToAttrbute
+ - mowerScheduleToAttribute
+ set <name> mowerScheduleToAttribute
Writes the schedule in to the attribute moverSchedule.
+
- sendScheduleFromAttributeToMower
set <name> sendScheduleFromAttributeToMower
Sends the schedule to the mower. NOTE: Do not use for 550 EPOS and Ceora.
@@ -1276,15 +1387,25 @@ sub listErrorCodes {
Get
- html
- get <name> html
+ get <name> html
Returns the mower area image as html code. For use in uiTable, TabletUI, Floorplan, readingsGroup, weblink etc.
- - listInternalData
- get <name> listInternalData
+ - InternalData
+ get <name> InternalData
Lists some device internal data
- - listErrorCodes
- get <name> listErrorCodes
+ - MowerData
+ get <name> MowerData
+ Lists all mower data with its hash path exept positon array. The hash path can be used for generating userReadings. The trigger is connected.
+ Example: created reading serialnumber with hash path $hash->{helper}{mower}{attributes}{system}{serialNumber}
+ attr <name> userReadings serialnumber:connected {$defs{$name}->{helper}{mower}{attributes}{system}{serialNumber}}
+
+ - StatisticsData
+ get <name> StatisticsData
+ Lists statistics data with its hash path. The hash path can be used for generating userReadings. The trigger is connected.
+
+ - errorCodes
+ get <name> errorCodes
Lists API response status codes and mower error codes
@@ -1377,40 +1498,22 @@ sub listErrorCodes {
- mower_errorCode - last error code
- mower_errorCodeTimestamp - last error code time stamp
- mower_errorDescription - error description
- - mower_id - ID of the mower
- mower_mode - current working mode "MAIN_AREA" | "SECONDARY_AREA" | "HOME" | "DEMO" | "UNKNOWN"
- mower_state - current status "UNKNOWN" | "NOT_APPLICABLE" | "PAUSED" | "IN_OPERATION" | "WAIT_UPDATING" | "WAIT_POWER_UP" | "RESTRICTED" | "OFF" | "STOPPED" | "ERROR" | "FATAL_ERROR" |"ERROR_AT_POWER_UP"
- planner_nextStart - next start time
- planner_restrictedReason - reason for parking NONE, WEEK_SCHEDULE, PARK_OVERRIDE, SENSOR, DAILY_LIMIT, FOTA, FROST
- planner_overrideAction - reason for override a planned action NOT_ACTIVE, FORCE_PARK, FORCE_MOW
- - positions_lastLonLat - last known position (longitude latitude)
- - state - status of connection FHEM to Husqvarna Cloud API and device state(e.g. defined, connected, error)
+ - state - status of connection FHEM to Husqvarna Cloud API and device state (e.g. defined, connected, error)
- status_statusTimestampOld - local time of second last change of the API content
- settings_cuttingHeight - actual cutting height from API
- settings_headlight - actual headlight mode from API
- statistics_newGeoDataSets - number of new data sets between the last two different time stamps
- - statistics_numberOfChargingCycles - number of charging cycles
- statistics_numberOfCollisions - number of collisions
- - statistics_totalChargingTime - total charging time in hours
- - statistics_totalCuttingTime - total cutting time in hours
- - statistics_totalRunningTime - total running time in hours
- - statistics_totalSearchingTime - total searching time in hours
- - statistics_currentDayTrack - calculated mowed track length in meter during mower_activity MOWING since midnight
- - statistics_currentDayArea - calculated mowed area in square meter during mower_activity MOWING since midnight
- - statistics_lastIntervalNumberOfWayPoints - last Intervals Number of way points
- - statistics_currentMowerSpeed - calculated mower speed in meter per second during mower_activity MOWING for the last interval
- - statistics_lastDayTrack - calculated mowed track length in meter during mower_activity MOWING for yesterday
- - statistics_lastDayArea - calculated mowed area in square meter during mower_activity MOWING for yesterday
- - statistics_currentWeekTrack - calculated mowed track length in meter during mower_activity MOWING of the current week
- - statistics_currentWeekArea - calculated mowed area in square meter during mower_activity MOWING of the current week
- - statistics_lastWeekTrack - calculated mowed track length in meter during mower_activity MOWING of the last week
- - statistics_lastWeekArea - calculated mowed area in square meter during mower_activity MOWING of the last week
- status_connected - state of connetion between mower and Husqvarna Cloud, (1 => true, 0 => false)
- status_statusTimestamp - local time of last change of the API content
- status_statusTimestampDiff - time difference in seconds between the last and second last change of the API content
- status_statusTimestampOld - local time of second last change of the API content
- system_name - name of the mower
- - system_serialNumber - serial number of the mower
@@ -1463,34 +1566,44 @@ sub listErrorCodes {
- Park
set <name> Park <number of minutes>
- Parkt den Mäher in der Ladestation (LS) für <number of minutes>
+ Parkt den Mäher in der Ladestation (LS) für <number of minutes>
+
- ParkUntilFurtherNotice
set <name> ParkUntilFurtherNotice
Parkt den Mäher bis auf Weiteres in der LS
+
- ParkUntilNextSchedule
set <name> ParkUntilNextSchedule
Parkt den Mäher bis auf Weiteres in der LS und startet zum nächsten geplanten Zeitpunkt
+
- Pause
set <name> Pause
Pausiert den Mäher sofort am aktuellen Standort
+
- ResumeSchedule
set <name> ResumeSchedule
Startet im geplanten Interval den Mäher sofort, sonst zum nächsten geplanten Zeitpunkt
+
- Start
set <name> Start <number of minutes>
Startet sofort für <number of minutes>
+
- chargingStationPositionToAttribute
set <name> chargingStationPositionToAttribute
Setzt die berechneten Koordinaten der LS in das entsprechende Attribut.
+
- cuttingHeight
set <name> cuttingHeight <1..9>
Setzt die Schnitthöhe. HINWEIS: Nicht für 550 EPOS und Ceora geeignet.
+
- headlight
set <name> headlight <ALWAYS_OFF|ALWAYS_ON|EVENIG_ONLY|EVENING_AND_NIGHT>
Setzt den Scheinwerfermode
- - mowerScheduleToAttrbute
- set <name> mowerScheduleToAttrbute
+
+ - mowerScheduleToAttribute
+ set <name> mowerScheduleToAttribute
Schreibt den Mähplan ins Attribut moverSchedule.
+
- sendScheduleFromAttributeToMower
set <name> sendScheduleFromAttributeToMower
Sendet den Mähplan zum Mäher. HINWEIS: Nicht für 550 EPOS und Ceora geeignet.
@@ -1506,13 +1619,23 @@ sub listErrorCodes {
get <name> html
Gibt das Bild des Mäherbereiches html kodiert zurück, zur Verwendung in uiTable, TabletUI, Floorplan, readingsGroup, weblink usw.
- - listErrorCodes
- get <name> listErrorCodes
+ - errorCodes
+ get <name> errorCodes
Listet die Statuscode der API-Anfrage und die Fehlercodes des Mähroboters auf.
- - listInternalData
- get <name> listErrorCodes
+ - InternalData
+ get <name> InternalData
Listet einige Daten des FHEM-Gerätes auf.
+
+ - MowerData
+ get <name> MowerData
+ Listet alle Daten des Mähers einschließlich Hashpfad auf ausgenommen das Positonsarray. Der Hashpfad kann zur Erzeugung von userReadings genutzt werden, getriggert wird durch connected.
+ Beispiel: erzeugen des Reading serialnumber mit dem Hashpfad $hash->{helper}{mower}{attributes}{system}{serialNumber}
+ attr <name> userReadings serialnumber:connected {$defs{$name}->{helper}{mower}{attributes}{system}{serialNumber}}
+
+ - StatisticsData
+ get <name> StatisticsData
+ Listet statistische Daten mit ihrem Hashpfad auf. Der Hashpfad kann zur Erzeugung von userReadings genutzt werden, getriggert wird durch connected
@@ -1614,39 +1737,21 @@ sub listErrorCodes {
mower_errorCode - last error code
mower_errorCodeTimestamp - last error code time stamp
mower_errorDescription - error description
- mower_id - ID des Automowers
mower_mode - aktueller Arbeitsmodus "MAIN_AREA" | "SECONDARY_AREA" | "HOME" | "DEMO" | "UNKNOWN"
mower_state - aktueller Status "UNKNOWN" | "NOT_APPLICABLE" | "PAUSED" | "IN_OPERATION" | "WAIT_UPDATING" | "WAIT_POWER_UP" | "RESTRICTED" | "OFF" | "STOPPED" | "ERROR" | "FATAL_ERROR" |"ERROR_AT_POWER_UP"
planner_nextStart - nächste Startzeit
planner_restrictedReason - Grund für Parken NONE, WEEK_SCHEDULE, PARK_OVERRIDE, SENSOR, DAILY_LIMIT, FOTA, FROST
planner_overrideAction - Grund für vorrangige Aktion NOT_ACTIVE, FORCE_PARK, FORCE_MOW
- positions_lastLonLat - letzte bekannte Position (Längengrad Breitengrad)
state - Status der Verbindung des FHEM-Gerätes zur Husqvarna Cloud API (defined, connected, error).
settings_cuttingHeight - aktuelle Schnitthöhe aus der API
settings_headlight - aktueller Scheinwerfermode aus der API
statistics_newGeoDataSets - Anzahl der neuen Datensätze zwischen den letzten zwei unterschiedlichen Zeitstempeln
- statistics_numberOfChargingCycles - Anzahl der Ladezyklen
statistics_numberOfCollisions - Anzahl der Kollisionen
- statistics_totalChargingTime - Gesamtladezeit in Stunden
- statistics_totalCuttingTime - Gesamtschneidezeit in Stunden
- statistics_totalRunningTime - Gesamtlaufzeit in Stunden
- statistics_totalSearchingTime - Gesamtsuchzeit in Stunden
- statistics_currentDayTrack - berechnete gefahrene Strecke in Meter bei_Activity MOWING seit Mitternacht
- statistics_currentDayArea - berechnete übermähte Fläche in Quadratmeter bei der Activity MOWING seit Mitternacht
- statistics_lastIntervalNumberOfWayPoints - Anzahl der Wegpunkte im letzten Interval
- statistics_currentMowerSpeed - berechnet Geschwindigkeit in Meter pro Sekunde bei der_Activity MOWING im letzten Interval
- statistics_lastDayTrack - berechnete gefahrene Strecke in Meter bei_Activity MOWING des letzten Tages
- statistics_lastDayArea - berechnete übermähte Fläche in Quadratmeter bei der Activity MOWING des letzten Tages
- statistics_currentWeekTrack - berechnete gefahrene Strecke in Meter bei_Activity MOWING
- statistics_currentWeekArea - berechnete übermähte Fläche in Quadratmeter bei der Activity MOWING der laufenden Woche
- statistics_lastWeekTrack - berechnete gefahrene Strecke in Meter bei_Activity MOWING der letzten Woche
- statistics_lastWeekArea - berechnete übermähte Fläche in Quadratmeter bei der Activity MOWING der letzten Woche
status_connected - Status der Verbindung zwischen dem Automower und der Husqvarna Cloud, (1 => true, 0 => false)
status_statusTimestamp - Lokalzeit der letzten Änderung der Daten in der API
status_statusTimestampDiff - Zeitdifferenz zwichen den beiden letzten Änderungen im Inhalt der Daten aus der API
status_statusTimestampOld - Lokalzeit der vorletzten Änderung der Daten in der API
system_name - Name des Automowers
- system_serialNumber - Seriennummer des Automowers