Skip to content

Commit 48794ff

Browse files
committed
Update to allow a postUpdate of the position
Update to emulate a command send from the binding itself Signed-off-by: Jeff James <jeff@james-online.com>
1 parent dcd0ce6 commit 48794ff

2 files changed

Lines changed: 130 additions & 94 deletions

File tree

bundles/org.openhab.transform.rollershutterposition/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,6 @@ This is useful when latencies in the system limit prevent very small movements a
1717
Rollershutter <itemName> { channel="<channelUID>"[profile="transform:ROLLERSHUTTERPOSITION", uptime=<uptime>, downtime=<downtime>, precision=<minimun percent movement>]}
1818
```
1919

20+
## Setting a known position
21+
22+
When this profile initially starts, it assumes the position of the rollershutter is in position 0. However, you can post and update to the item and the profile will update the known position. This is useful if a restart of openHAB occurs and you want to update the position to the last known position.

bundles/org.openhab.transform.rollershutterposition/src/main/java/org/openhab/transform/rollershutterposition/internal/RollerShutterPositionProfile.java

Lines changed: 127 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)