diff --git a/fhem/CHANGED b/fhem/CHANGED
index 5cdeacae1..9e2cd449e 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
+ - change: 74_AutomowerConnect: fix ws buffer handling if multiple JSON
+ data sets received, calculate nextStarttime if no planner event
+ add websocket statistics
- feature: 76_SolarForecast: Major release 1.50.0
- change: 49_SSCam: set compatible version to 9.2.3
- feature: 76_SolarForecast: version 1.47.5
diff --git a/fhem/FHEM/74_AutomowerConnect.pm b/fhem/FHEM/74_AutomowerConnect.pm
index 199223892..17dbd6933 100644
--- a/fhem/FHEM/74_AutomowerConnect.pm
+++ b/fhem/FHEM/74_AutomowerConnect.pm
@@ -83,6 +83,7 @@ sub Initialize() {
'numberOfWayPointsToDisplay ' .
'addPollingMinInterval ' .
'addPositionPolling:1,0 ' .
+ 'calculateReadings:nextStart ' .
$::readingFnAttributes;
$::data{FWEXT}{AutomowerConnect}{SCRIPT} = 'automowerconnect.js';
@@ -486,6 +487,10 @@ __END__
}'
+
calculateReadings
+ attr <name> calculateReadings <nextStart>
+ Calcutates nextStart if not provided by planner event.
+
addPollingMinInterval
attr <name> addPollingMinInterval <interval in seconds>
Set minimum intervall for additional polling triggered by any websocket event, default 0 (no polling). Gets periodically mower data. Make sure to be within API limits (10000 calls per month).
@@ -1014,6 +1019,10 @@ __END__
}'
+ calculateReadings
+ attr <name> calculateReadings <nextStart>
+ Berechnet nextStart wenn der Wert nicht per Plannerevent geliefert wird.
+
addPollingMinInterval
attr <name> addPollingMinInterval <interval in seconds>
Setzt das Mindestintervall für zusätzliches Polling der API nach einem websocket event, default 0 (kein Polling). Liest periodisch zusätzlich Mäherdaten von der API. Es muss sichergestellt werden, das die API Begrenzung (10000 Anfragen pro Monat) eingehalten wird.
diff --git a/fhem/lib/FHEM/Devices/AMConnect/Common.pm b/fhem/lib/FHEM/Devices/AMConnect/Common.pm
index d581d9e17..57dab4010 100644
--- a/fhem/lib/FHEM/Devices/AMConnect/Common.pm
+++ b/fhem/lib/FHEM/Devices/AMConnect/Common.pm
@@ -35,6 +35,7 @@ use Time::Local;
use DevIo;
use Storable qw(dclone retrieve store);
use DateTime;
+use List::Util qw( min );
my $EMPTY = q{};
my $missingModul = $EMPTY;
## no critic (ProhibitConditionalUseStatements)
@@ -335,16 +336,32 @@ EOF
hullArea => 0
},
wsbuf => {
- events_changed => 0,
- event_duplicates => 0,
+ sum_changed => 0,
+ sum_duplicates => 0,
'position-event-v2' => $EMPTY,
'mower-event-v2' => $EMPTY,
'battery-event-v2' => $EMPTY,
'planner-event-v2' => $EMPTY,
'cuttingHeight-event-v2'=> $EMPTY,
- 'headLights-event-v2' => $EMPTY,
+ 'headlights-event-v2' => $EMPTY,
'calendar-event-v2' => $EMPTY,
- 'message-event-v2' => $EMPTY
+ 'message-event-v2' => $EMPTY,
+ position_changed => 0,
+ mower_changed => 0,
+ battery_changed => 0,
+ planner_changed => 0,
+ cuttingHeight_changed => 0,
+ headlights_changed => 0,
+ calendar_changed => 0,
+ message_changed => 0,
+ position_duplicates => 0,
+ mower_duplicates => 0,
+ battery_duplicates => 0,
+ planner_duplicates => 0,
+ cuttingHeight_duplicates=> 0,
+ headlights_duplicates => 0,
+ calendar_duplicates => 0,
+ message_duplicates => 0
}
}
);
@@ -2595,9 +2612,17 @@ sub fillReadings {
readingsBulkUpdateIfChanged( $hash, $pref.'_restrictedReason', $hash->{helper}{mower}{attributes}{$pref}{restrictedReason} );
readingsBulkUpdateIfChanged( $hash, $pref.'_overrideAction', $hash->{helper}{mower}{attributes}{$pref}{override}{action} ) if ( $hash->{helper}{mower}{attributes}{$pref}{override}{action} );
- $tstamp = $hash->{helper}{mower}{attributes}{$pref}{nextStartTimestamp};
- $timestamp = FmtDateTimeGMT( $tstamp/1000 );
- readingsBulkUpdateIfChanged($hash, $pref.'_nextStart', $tstamp ? $timestamp : '-' );
+ if ( AttrVal( $name, 'calculateReadings', $EMPTY ) =~ /nextStart/ ) {
+
+ readingsBulkUpdateIfChanged( $hash, $pref.'_nextStart', calculateNextStart( $hash ) );
+
+ } else {
+
+ $tstamp = $hash->{helper}{mower}{attributes}{$pref}{nextStartTimestamp};
+ $timestamp = FmtDateTimeGMT( $tstamp/1000 );
+ readingsBulkUpdateIfChanged( $hash, $pref.'_nextStart', $tstamp ? $timestamp : '-' );
+
+ }
$pref = 'statistics';
my $noCol = $hash->{helper}{statistics}{currentDayCollisions};
@@ -2984,6 +3009,22 @@ sub listInternalData { ## no critic (ProhibitExcessComplexity [complexity core m
$ret .= 'NOT_APPLICABLE with error time stamp | lasterror/positions | ' . $ernr . ' | - |
';
$ret .= '';
+ $ret .= '';
+ $ret .= 'Websocket Events';
+
+ $ret .= '';
+ my @evt = qw(battery calendar cuttingHeight headlights message mower planner position sum);
+
+ for my $key (@evt) {
+
+ my $hc = $hash->{helper}{wsbuf}{$key . '_changed'};
+ my $hd = $hash->{helper}{wsbuf}{$key . '_duplicates'};
+ $ret .= ' ' . $key . ' | ' . $hc . ' | ' . $hd . ' | ' . ( $hc + $hd ) . ' |
';
+
+ }
+
+ $ret .= '
';
+
$ret .= '';
$ret .= 'Rest API Data';
@@ -3000,11 +3041,11 @@ sub listInternalData { ## no critic (ProhibitExcessComplexity [complexity core m
$ret .= ' Token Expires | ' . FmtDateTime( ReadingsVal($name, '.expires', '0') ) . ' |
';
$ret .= ' Access Token | ' . ReadingsVal($name, '.access_token', '0') . ' |
';
-$ret .= '
';
+ $ret .= '';
$ret .= '';
$ret .= 'Default mapDesignAttributes';
-my $mapdesign = $hash->{helper}{mapdesign};
+ my $mapdesign = $hash->{helper}{mapdesign};
$mapdesign =~ s/\n/
/g;
$ret .= '' . $mapdesign . ' |
';
@@ -3188,6 +3229,37 @@ sub makeStatusTimeStamp {
}
+#########################
+sub calculateNextStart {
+ my ( $hash ) = @_;
+ return "-" if ( $hash->{helper}{mower}{attributes}{mower}{mode} !~ /MAIN_AREA/ ) || $hash->{helper}{mower}{attributes}{mower}{state} =~ /IN_OPERATION/;
+
+ my $nt = gettimeofday();
+ my @lt = gmtime( $nt );
+ my $wday = $lt[ 6 ];
+ my $mn = $nt - ( $lt[ 2 ] * 3600 + $lt[ 1 ] * 60 + $lt[ 0 ] ); # Midnight
+ my @days = qw( sunday monday tuesday wednesday thursday friday saturday sunday monday tuesday wednesday thursday friday saturday );
+ my @cal = @{ $hash->{helper}{mower}{attributes}{calendar}{tasks} };
+ my @times =();
+
+ for ( my $i = 0; $i < @cal; $i++ ) {
+
+ my $calt = $mn + $cal [ $i ]->{start} * 60;
+
+ for ( my $wd = $lt [ 6 ]; $wd < $lt [ 6 ] + 7 ; $wd++ ) {
+
+ my $nx = $calt + 86400 * ( $wd - $lt [ 6 ] );
+ push @times, $nx if ( $cal [ $i ]->{$days [ $wd ]} && $nx > $nt );
+
+ }
+
+ }
+
+ # my $nextTime = POSIX::strftime( "%F %H:%M:00", localtime( min( @times ) ) );
+ my $nextTime = FmtDateTimeGMT( min( @times ) );
+ return $nextTime;
+}
+
##############################################################
#
# WEBSOCKET
@@ -3283,14 +3355,19 @@ sub wsRead { ## no critic (ProhibitExcessComplexity [complexity core maintenanc
my ( @bufj ) = split('\}\{', $buforig ); # split in case buffer contains more than one event string
- if ( @bufj > 1 ) {
+ if ( @bufj > 1 ) { # complete JSON strings due to splitting
- for ( my $i = 0; $i < @bufj; $i++ ) { # complete JSON strings due to splitting
+ my $i = 0;
+ $bufj[$i] = $bufj[$i].'}';
- $bufj[$i] = $i % 2 ? '{'.$bufj[$i] : $bufj[$i].'}';
+ for ( my $i = 1; $i < @bufj - 1; $i++ ) {
+
+ $bufj[$i] = '{'.$bufj[$i].'}';
}
+ $bufj[$i] = '{'.$bufj[$i];
+
}
for my $buf (@bufj) { # process each buffer part
@@ -3303,7 +3380,7 @@ sub wsRead { ## no critic (ProhibitExcessComplexity [complexity core maintenanc
if ( $buf ne $hash->{helper}{wsbuf}{$evt} ) { # handle changed events
$hash->{helper}{wsbuf}{$evt} = $buf;
- $hash->{helper}{wsbuf}{events_changed}++ ;
+ $hash->{helper}{wsbuf}{sum_changed}++ ;
$hash->{helper}{wsbuf}{$evn.'_changed'}++ ;
my $result = eval { JSON::XS->new->decode( $buf ) };
@@ -3413,7 +3490,7 @@ sub wsRead { ## no critic (ProhibitExcessComplexity [complexity core maintenanc
}
# headlights-event-v2
- elsif ( $result->{type} =~ /^hea/ ) { #no headlight event 430x
+ elsif ( $result->{type} =~ /^hea/ ) { #no headlights event 430x
$hash->{helper}{mower}{attributes}{settings}{headlight}{mode} = $result->{attributes}{headlight}{mode};
@@ -3449,7 +3526,7 @@ sub wsRead { ## no critic (ProhibitExcessComplexity [complexity core maintenanc
} else { # handle duplicates
- $hash->{helper}{wsbuf}{event_duplicates}++;
+ $hash->{helper}{wsbuf}{sum_duplicates}++;
$hash->{helper}{wsbuf}{$evn.'_duplicates'}++ ;
} # end handle duplicates/changed