2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.nikohomecontrol.internal.protocol.nhc1;
15 import static org.openhab.binding.nikohomecontrol.internal.protocol.NikoHomeControlConstants.*;
17 import java.util.concurrent.ScheduledExecutorService;
18 import java.util.concurrent.ScheduledFuture;
19 import java.util.concurrent.TimeUnit;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.nikohomecontrol.internal.protocol.NhcAction;
24 import org.openhab.binding.nikohomecontrol.internal.protocol.NikoHomeControlCommunication;
25 import org.openhab.binding.nikohomecontrol.internal.protocol.NikoHomeControlConstants.ActionType;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
30 * The {@link NhcAction1} class represents the action Niko Home Control I communication object. It contains all fields
31 * representing a Niko Home Control action and has methods to trigger the action in Niko Home Control and receive action
34 * @author Mark Herwege - Initial Contribution
37 public class NhcAction1 extends NhcAction {
39 private final Logger logger = LoggerFactory.getLogger(NhcAction1.class);
42 private interface Action {
46 private ScheduledExecutorService scheduler;
48 private volatile @Nullable Action rollershutterTask;
49 private volatile @Nullable ScheduledFuture<?> rollershutterStopTask;
50 private volatile @Nullable ScheduledFuture<?> rollershutterMovingFlagTask;
52 private volatile boolean filterEvent = false; // flag to filter first event from rollershutter on percent move to
53 // avoid wrong position update
54 private volatile boolean rollershutterMoving = false; // flag to indicate if rollershutter is currently moving
55 private volatile boolean waitForEvent = false; // flag to wait for position update rollershutter before doing next
58 NhcAction1(String id, String name, ActionType type, @Nullable String location, NikoHomeControlCommunication nhcComm,
59 ScheduledExecutorService scheduler) {
60 super(id, name, type, location, nhcComm);
61 this.scheduler = scheduler;
65 * Sets state of action. This is the version for Niko Home Control I.
67 * @param newState - The allowed values depend on the action type.
68 * switch action: 0 or 100
69 * dimmer action: between 0 and 100
70 * rollershutter action: between 0 and 100
73 public void setState(int newState) {
74 if (getType() == ActionType.ROLLERSHUTTER) {
77 logger.debug("filtered event {} for {}", newState, id);
81 cancelRollershutterStop();
83 if (((newState == 0) || (newState == 100)) && (newState != state)) {
84 long duration = rollershutterMoveTime(state, newState);
85 setRollershutterMovingTrue(duration);
87 setRollershutterMovingFalse();
91 logger.debug("received requested rollershutter {} position event {}", id, newState);
92 executeRollershutterTask();
100 * Sends action to Niko Home Control. This version is used for Niko Home Control I.
102 * @param command - The allowed values depend on the action type.
105 public void execute(String command) {
106 logger.debug("execute action {} of type {} for {}", command, type, id);
113 if (command.equals(NHCON)) {
118 nhcComm.executeAction(id, value);
121 if (command.equals(NHCON)) {
123 } else if (command.equals(NHCOFF)) {
128 nhcComm.executeAction(id, value);
131 executeRollershutter(command);
136 private void executeRollershutter(String command) {
137 if (logger.isTraceEnabled()) {
138 logger.trace("handleRollerShutterCommand: rollershutter {} command {}", id, command);
139 logger.trace("handleRollerShutterCommand: rollershutter {}, current position {}", id, state);
142 // first stop all current movement of rollershutter and wait until exact position is known
143 if (rollershutterMoving) {
144 if (logger.isTraceEnabled()) {
145 logger.trace("handleRollerShutterCommand: rollershutter {} moving, therefore stop", id);
147 rollershutterPositionStop();
150 // task to be executed once exact position received from Niko Home Control
151 rollershutterTask = () -> {
152 if (logger.isTraceEnabled()) {
153 logger.trace("handleRollerShutterCommand: rollershutter {} task running", id);
156 int currentValue = state;
158 if (command.equals(NHCDOWN)) {
159 executeRollershutterDown();
160 } else if (command.equals(NHCUP)) {
161 executeRollershutterUp();
162 } else if (command.equals(NHCSTOP)) {
163 executeRollershutterStop();
165 int newValue = Integer.parseInt(command);
166 if (logger.isTraceEnabled()) {
167 logger.trace("handleRollerShutterCommand: rollershutter {} percent command, current {}, new {}", id,
168 currentValue, newValue);
170 if (currentValue == newValue) {
173 if ((newValue > 0) && (newValue < 100)) {
174 scheduleRollershutterStop(currentValue, newValue);
176 if (newValue < currentValue) {
177 executeRollershutterUp();
178 } else if (newValue > currentValue) {
179 executeRollershutterDown();
184 // execute immediately if not waiting for exact position
186 if (logger.isTraceEnabled()) {
187 logger.trace("handleRollerShutterCommand: rollershutter {} task executing immediately", id);
189 executeRollershutterTask();
193 private void executeRollershutterStop() {
194 nhcComm.executeAction(id, "253");
197 private void executeRollershutterDown() {
198 nhcComm.executeAction(id, "254");
201 private void executeRollershutterUp() {
202 nhcComm.executeAction(id, "255");
206 * Method used to stop rollershutter when moving. This will then result in an exact position to be received, so next
207 * percentage movements could be done accurately.
209 private void rollershutterPositionStop() {
210 if (logger.isTraceEnabled()) {
211 logger.trace("rollershutterPositionStop: rollershutter {} executing", id);
213 cancelRollershutterStop();
214 rollershutterTask = null;
217 executeRollershutterStop();
220 private void executeRollershutterTask() {
221 if (logger.isTraceEnabled()) {
222 logger.trace("executeRollershutterTask: rollershutter {} task triggered", id);
224 waitForEvent = false;
226 Action action = rollershutterTask;
227 if (action != null) {
229 rollershutterTask = null;
234 * Method used to schedule a rollershutter stop when moving. This allows stopping the rollershutter at a percent
237 * @param currentValue current percent position
238 * @param newValue new percent position
241 private void scheduleRollershutterStop(int currentValue, int newValue) {
242 // filter first event for a rollershutter coming from Niko Home Control if moving to an intermediate
243 // position to avoid updating state to full open or full close
246 long duration = rollershutterMoveTime(currentValue, newValue);
247 setRollershutterMovingTrue(duration);
249 if (logger.isTraceEnabled()) {
250 logger.trace("scheduleRollershutterStop: schedule rollershutter {} stop in {}ms", id, duration);
252 rollershutterStopTask = scheduler.schedule(() -> {
253 logger.trace("scheduleRollershutterStop: run rollershutter {} stop", id);
254 executeRollershutterStop();
255 }, duration, TimeUnit.MILLISECONDS);
258 private void cancelRollershutterStop() {
259 ScheduledFuture<?> stopTask = rollershutterStopTask;
260 if (stopTask != null) {
261 if (logger.isTraceEnabled()) {
262 logger.trace("cancelRollershutterStop: cancel rollershutter {} stop", id);
264 stopTask.cancel(true);
266 rollershutterStopTask = null;
271 private void setRollershutterMovingTrue(long duration) {
272 if (logger.isTraceEnabled()) {
273 logger.trace("setRollershutterMovingTrue: rollershutter {} moving", id);
275 rollershutterMoving = true;
276 rollershutterMovingFlagTask = scheduler.schedule(() -> {
277 if (logger.isTraceEnabled()) {
278 logger.trace("setRollershutterMovingTrue: rollershutter {} stopped moving", id);
280 rollershutterMoving = false;
281 }, duration, TimeUnit.MILLISECONDS);
284 private void setRollershutterMovingFalse() {
285 if (logger.isTraceEnabled()) {
286 logger.trace("setRollershutterMovingFalse: rollershutter {} not moving", id);
288 rollershutterMoving = false;
289 ScheduledFuture<?> future = rollershutterMovingFlagTask;
290 if (future != null) {
292 rollershutterMovingFlagTask = null;
296 private long rollershutterMoveTime(int currentValue, int newValue) {
297 int totalTime = (newValue > currentValue) ? getOpenTime() : getCloseTime();
298 long duration = Math.abs(newValue - currentValue) * totalTime * 10;
299 if (logger.isTraceEnabled()) {
300 logger.trace("rollershutterMoveTime: rollershutter {} move time {}", id, duration);