@@ -70,7 +70,8 @@ public TimeweightedAverageStateProfile(ProfileCallback callback, ProfileContext
7070 scheduleDuration = DurationUtils .parse (config .duration );
7171 } catch (IllegalArgumentException e ) {
7272 scheduleDuration = DEFAULT_TIMEOUT ;
73- logger .warn ("Invalid duration configuration {} for item {}" , config .duration , itemName );
73+ logger .warn ("Invalid duration configuration {} for item {}. Fallback to {}" , config .duration , itemName ,
74+ DEFAULT_TIMEOUT );
7475 }
7576 }
7677
@@ -131,15 +132,24 @@ private boolean deltaExceeded(State state) {
131132 }
132133
133134 private void deliver () {
134- TreeMap <Instant , State > delivery = new TreeMap <>();
135+ TreeMap <Instant , State > delivery = prepareDelivery ();
136+ if (delivery .size () <= 1 ) {
137+ logger .debug ("Cannot calculate time-weighted average for item {} with {} elements" , itemName ,
138+ delivery .size ());
139+ } else {
140+ callback .sendUpdate (getState (average (delivery )));
141+ }
142+ }
143+
144+ private TreeMap <Instant , State > prepareDelivery () {
145+ TreeMap <Instant , State > delivery ;
135146 synchronized (timeframe ) {
136147 resetJob ();
137- delivery = ( TreeMap <Instant , State >) timeframe . clone ( );
148+ delivery = new TreeMap <>( timeframe );
138149 // add termination element
139150 delivery .put (Instant .now (), DecimalType .ZERO );
140151 // clear time frame and put latest reported state as start point of the next calculation
141152 timeframe .clear ();
142-
143153 State localState = latestState ;
144154 if (localState != null ) {
145155 if (streamingInTimeframe ) {
@@ -149,17 +159,11 @@ private void deliver() {
149159 startJob ();
150160 } else {
151161 // no new states received during this time frame
152- logger .debug ("no new states received, wait for next state update" );
162+ logger .debug ("No new states for {} received, wait for next state update" , itemName );
153163 }
154164 }
155165 }
156-
157- if (delivery .size () <= 1 ) {
158- logger .debug ("Cannot calculate time-weighted average for item {} with {} elements" , itemName ,
159- delivery .size ());
160- } else {
161- callback .sendUpdate (getState (average (delivery )));
162- }
166+ return delivery ;
163167 }
164168
165169 private void startJob () {
@@ -173,37 +177,34 @@ private void resetJob() {
173177 ScheduledFuture <?> localTwaJob = twaJob ;
174178 if (localTwaJob != null ) {
175179 localTwaJob .cancel (false );
180+ twaJob = null ;
176181 }
177- twaJob = null ;
178182 }
179183
180184 private double state2Double (State state ) {
181185 DecimalType as = state .as (DecimalType .class );
182186 if (as == null ) {
183- logger .error ("Cannot convert state {} of item {} to DecimalType for average calculation" , state , itemName );
187+ // may happen if state delivery contains NULL or UNDEF states
188+ logger .warn ("Cannot convert state {} of item {} to DecimalType for average calculation" , state , itemName );
184189 return 0 ;
185190 }
186191 return as .doubleValue ();
187192 }
188193
189194 public double average (TreeMap <Instant , State > values ) {
190- Instant iterationTimestamp = null ;
191- State iterationValue = DecimalType .ZERO ;
195+ Instant previousTimestamp = null ;
196+ State previousValue = DecimalType .ZERO ;
192197 double totalWeightedValue = 0 ;
193198 long totalDurationMs = 0 ;
194199
195200 for (Map .Entry <Instant , State > entry : values .entrySet ()) {
196- if (iterationTimestamp == null ) {
197- iterationTimestamp = entry .getKey ();
198- iterationValue = entry .getValue ();
199- } else {
200- Instant end = entry .getKey ();
201- long durationMs = Duration .between (iterationTimestamp , end ).toMillis ();
202- totalWeightedValue += state2Double (iterationValue ) * durationMs ;
201+ if (previousTimestamp != null ) {
202+ long durationMs = Duration .between (previousTimestamp , entry .getKey ()).toMillis ();
203+ totalWeightedValue += state2Double (previousValue ) * durationMs ;
203204 totalDurationMs += durationMs ;
204- iterationTimestamp = end ;
205- iterationValue = entry .getValue ();
206205 }
206+ previousTimestamp = entry .getKey ();
207+ previousValue = entry .getValue ();
207208 }
208209 double average = (totalDurationMs > 0 ) ? totalWeightedValue / totalDurationMs : 0 ;
209210 logger .debug ("Average {} is {} for {} updates" , itemName , average , values .size ());
0 commit comments