@@ -84,31 +84,8 @@ public ProfileTypeUID getProfileTypeUID() {
8484 return PROFILE_TYPE_UID ;
8585 }
8686
87- @ Override
88- public void onCommandFromItem (Command command ) {
89- logger .debug ("onCommandFromItem: {}" , command );
90-
91- // pass through command if profile has not been configured properly
92- if (!isValidConfiguration ) {
93- callback .handleCommand (command );
94- return ;
95- }
96-
97- if (command instanceof UpDownType ) {
98- if (command == UpDownType .UP ) {
99- moveTo (0 );
100- } else if (command == UpDownType .DOWN ) {
101- moveTo (100 );
102- }
103- } else if (command instanceof StopMoveType ) {
104- stop (true );
105- } else {
106- moveTo (((PercentType ) command ).intValue ());
107- }
108- }
109-
11087 private boolean isMoving () {
111- return ( !movingSince .equals (Instant .MIN ) );
88+ return !movingSince .equals (Instant .MIN );
11289 }
11390
11491 private void moveTo (int targetPos ) {
@@ -148,68 +125,83 @@ private void moveTo(int targetPos) {
148125 * (posOffset > 0 ? (double ) configuration .downtime * 1000 : (double ) configuration .uptime * 1000 ));
149126 logger .debug ("moveTo() computed movement offset: {} / {} / {} ms" , posOffset , newCmd , time );
150127
151- boolean alreadyMovingRightDirection = false ;
128+ this . targetPosition = targetPos ;
152129 if (isMoving ()) {
153- position = curPos ; // Update "starting" position if already in motion since the last move did not finish
154-
155- if (direction == newCmd ) {
156- alreadyMovingRightDirection = true ;
130+ stopStopTimer ();
131+ if (this .direction != newCmd ) {
132+ logger .debug ("moveTo() reversing direction: {}, timer set in {} ms" , direction , time );
133+ position = curPos ; // Update "starting" position if already in motion since the last move did not finish
134+ this .direction = newCmd ; // Update direction to the new command
135+ this .movingSince = Instant .now ();
136+ callback .handleCommand (direction );
137+ } else {
138+ logger .debug ("moveTo() already moving in right direction: {}, timer set in {} ms" , direction , time );
157139 }
158- }
159-
160- this .targetPosition = targetPos ;
161- this .direction = newCmd ;
162- this .movingSince = Instant .now ();
163-
164- stopTimers ();
165- this .stopTimer = scheduler .schedule (stopTimeoutTask , time , TimeUnit .MILLISECONDS );
166- this .updateTimer = scheduler .scheduleWithFixedDelay (updateTimeoutTask , 0 , POSITION_UPDATE_PERIOD_MILLISECONDS ,
167- TimeUnit .MILLISECONDS );
168-
169- if (!alreadyMovingRightDirection ) {
140+ startStopTimer (time );
141+ } else {
170142 logger .debug ("moveTo() sending command for movement: {}, timer set in {} ms" , direction , time );
143+ this .movingSince = Instant .now ();
144+ startUpdateTimer ();
145+ startStopTimer (time );
146+ this .direction = newCmd ; // Update direction to the new command
171147 callback .handleCommand (direction );
172- } else {
173- logger .debug ("moveTo() updating timing but already moving in right direction: {}, timer set in {} ms" ,
174- direction , time );
175148 }
176149 }
177150
178- private void stopTimers () {
179- ScheduledFuture <?> lStopTimer = stopTimer ;
180- if (lStopTimer != null ) {
181- lStopTimer .cancel (true );
182- this .stopTimer = null ;
151+ private synchronized void startUpdateTimer () {
152+ ScheduledFuture <?> lUpdateTimer = updateTimer ;
153+ if (lUpdateTimer == null || lUpdateTimer .isDone ()) {
154+ logger .trace ("startUpdateTimer() actually" );
155+ this .updateTimer = scheduler .scheduleWithFixedDelay (updateTimeoutTask , 0 ,
156+ POSITION_UPDATE_PERIOD_MILLISECONDS , TimeUnit .MILLISECONDS );
183157 }
158+ }
184159
160+ private synchronized void stopUpdateTimer () {
161+ logger .trace ("stopUpdateTimer() called, isMoving: {}" , isMoving ());
185162 ScheduledFuture <?> lUpdateTimer = updateTimer ;
186163 if (lUpdateTimer != null ) {
187164 lUpdateTimer .cancel (true );
188165 this .updateTimer = null ;
189166 }
190167 }
191168
192- private void stop ( boolean updatePosition ) {
193- callback . handleCommand ( StopMoveType . STOP );
194-
195- if ( updatePosition ) {
196- this . position = currentPosition ( );
169+ private synchronized void startStopTimer ( long time ) {
170+ logger . trace ( "startStopTimer() called with time: {}" , time );
171+ ScheduledFuture <?> lStopTimer = stopTimer ;
172+ if ( lStopTimer != null ) {
173+ lStopTimer . cancel ( true );
197174 }
198- this .movingSince = Instant .MIN ;
199- this .targetPosition = -1 ; // reset target position
200175
201- stopTimers ();
176+ this .stopTimer = scheduler .schedule (stopTimeoutTask , time , TimeUnit .MILLISECONDS );
177+ }
202178
203- if (updatePosition ) {
204- callback .sendUpdate (new PercentType (position ));
179+ private synchronized void stopStopTimer () {
180+ logger .trace ("stopStopTimer() called, isMoving: {}" , isMoving ());
181+ ScheduledFuture <?> lStopTimer = stopTimer ;
182+ if (lStopTimer != null ) {
183+ lStopTimer .cancel (true );
184+ this .stopTimer = null ;
205185 }
206186 }
207187
188+ private void stop (boolean handlerInitiated ) {
189+ logger .trace ("stop() called, isMoving: {}, handlerInitiated: {}" , isMoving (), handlerInitiated );
190+ if (!handlerInitiated ) {
191+ callback .handleCommand (StopMoveType .STOP );
192+ }
193+
194+ this .position = currentPosition ();
195+ stopUpdateTimer ();
196+ stopStopTimer ();
197+
198+ callback .sendUpdate (new PercentType (position ));
199+ this .movingSince = Instant .MIN ;
200+ this .targetPosition = -1 ; // reset target position
201+ }
202+
208203 private int currentPosition () {
209204 if (isMoving ()) {
210- logger .trace ("currentPosition() while moving" );
211-
212- // movingSince is always set if moving
213205 long millis = movingSince .until (Instant .now (), ChronoUnit .MILLIS );
214206 double delta = 0 ;
215207
@@ -229,7 +221,7 @@ private int currentPosition() {
229221 private Runnable stopTimeoutTask = new Runnable () {
230222 @ Override
231223 public void run () {
232-
224+ stopUpdateTimer ();
233225 if (targetPosition == 0 || targetPosition == 100 ) {
234226 // Don't send stop command to re-sync position using the motor end stop
235227 logger .debug ("arrived at end position, not stopping for calibration" );
@@ -239,71 +231,112 @@ public void run() {
239231 }
240232
241233 logger .trace ("stopTimeoutTask() position: {}" , targetPosition );
242- stopTimers ();
243-
234+ position = currentPosition ();
235+ callback . sendUpdate ( new PercentType ( position ));
244236 movingSince = Instant .MIN ;
245- position = targetPosition ;
246237 targetPosition = -1 ;
247- callback .sendUpdate (new PercentType (position ));
248238 }
249239 };
250240
251241 // Runnable task to update the item on position while the roller shutter is moving
252242 private Runnable updateTimeoutTask = new Runnable () {
253243 @ Override
254244 public void run () {
245+ logger .trace ("updateTimeoutTask() called, isMoving: {}, currentPosition: {}" , isMoving (),
246+ currentPosition ());
255247 if (isMoving ()) {
256248 int pos = currentPosition ();
257- if (pos < 0 || pos > 100 ) {
258- return ;
249+ if ((pos <= 0 && direction == UpDownType .UP ) || (pos >= 100 && direction == UpDownType .DOWN )) {
250+ logger .debug ("updateTimeoutTask() reached end position, stopping update timer" );
251+ stopUpdateTimer ();
259252 }
253+ pos = Math .max (0 , Math .min (100 , pos ));
260254 callback .sendUpdate (new PercentType (pos ));
261- logger .trace ("updateTimeoutTask(): {}" , pos );
262255 }
263256 }
264257 };
265258
259+ @ Override
260+ public void onCommandFromItem (Command command ) {
261+ logger .debug ("onCommandFromItem: {}" , command );
262+
263+ // pass through command if profile has not been configured properly
264+ if (!isValidConfiguration ) {
265+ callback .handleCommand (command );
266+ return ;
267+ }
268+
269+ if (command instanceof UpDownType ) {
270+ if (command == UpDownType .UP ) {
271+ moveTo (0 );
272+ } else if (command == UpDownType .DOWN ) {
273+ moveTo (100 );
274+ }
275+ } else if (command instanceof StopMoveType ) {
276+ stop (false );
277+ } else {
278+ moveTo (((PercentType ) command ).intValue ());
279+ }
280+ }
281+
266282 // Handle restoreOnStartup update of the item position
283+ // Note, this will also be called when the profile sendUpdate, no harm in setting the position to the current value
267284 @ Override
268285 public void onStateUpdateFromItem (State state ) {
269- logger .debug ("onStateUpdateFromItem() called with state: {}" , state );
270- if (state instanceof PercentType ) {
271- int pos = ((PercentType ) state ).intValue ();
286+ if (!isValidConfiguration ) {
287+ return ;
288+ }
289+
290+ if (isMoving ()) {
291+ logger .debug ("onStateUpdateFromItem() called while moving, ignoring state update: {}" , state );
292+ return ;
293+ }
294+
295+ logger .debug ("onStateUpdateFromItem() called with state: {}, isMoving: {}" , state , isMoving ());
296+ if (state instanceof PercentType percentType ) {
297+ int pos = percentType .intValue ();
272298 if (pos < 0 || pos > 100 ) {
273299 logger .warn ("onStateUpdateFromItem() position is invalid: {}" , pos );
274300 return ;
275301 }
276302 this .position = pos ;
277303 } else {
278- logger .warn ("onStateUpdateFromItem() received unexpected state type: {}" , state .getClass ());
304+ logger .warn ("onStateUpdateFromItem() received unexpected state type: {} - {} " , state .getClass (), state );
279305 }
280306 }
281307
282308 @ Override
283- public void onCommandFromHandler (Command command ) {
309+ public synchronized void onCommandFromHandler (Command command ) {
310+ if (!isValidConfiguration ) {
311+ return ;
312+ }
313+
284314 logger .debug ("onCommandFromHandler() called with command: {}" , command );
315+ if (command instanceof StopMoveType ) {
316+ stop (true );
317+ } else if (command instanceof UpDownType upDownType ) {
318+ stopStopTimer (); // manual control
319+ targetPosition = -1 ;
320+ if (isMoving ()) {
321+ // update timer is already running
322+ if (upDownType != direction ) {
323+ logger .trace ("reverse direction from {} to {}" , direction , upDownType );
324+ this .position = currentPosition ();
325+ this .direction = upDownType ;
326+ this .movingSince = Instant .now ();
327+ } else {
328+ logger .trace ("continue in current direction: {}" , upDownType );
329+ }
330+ callback .sendUpdate (new PercentType (position ));
331+ } else {
332+ this .direction = upDownType ; // update direction to the new command if we are not already moving
333+ this .movingSince = Instant .now (); // reset movingSince to now if we are not already moving
334+ startUpdateTimer ();
335+ }
336+ }
285337 }
286338
287339 @ Override
288340 public void onStateUpdateFromHandler (State state ) {
289- logger .debug ("onStateUpdateFromHandler() called with state: {}" , state );
290- if (state instanceof PercentType ) {
291- int pos = ((PercentType ) state ).intValue ();
292- if (pos < 0 || pos > 100 ) {
293- logger .warn ("onStateUpdateFromHandler() position is invalid: {}" , pos );
294- return ;
295- }
296- this .position = pos ;
297- callback .sendUpdate (new PercentType (position ));
298-
299- if (isMoving ()) {
300- if (this .direction == UpDownType .UP && position <= targetPosition ||
301- this .direction == UpDownType .DOWN && position >= targetPosition ) {
302- stop (false );
303- }
304- }
305- } else {
306- logger .warn ("onStateUpdateFromHandler() received unexpected state type: {}" , state .getClass ());
307- }
308341 }
309342}
0 commit comments