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.velux.internal.bridge.slip;
15 import java.util.Random;
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.openhab.binding.velux.internal.bridge.common.RunScene;
19 import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
20 import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
21 import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
22 import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
27 * Protocol specific bridge communication supported by the Velux bridge:
30 * Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
33 * As 3rd level class it defines informations how to send query and receive answer through the
34 * {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
35 * as described by the interface {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeCommunicationProtocol
36 * SlipBridgeCommunicationProtocol}.
38 * Methods in addition to the mentioned interface:
40 * <LI>{@link #setSceneId} to define the scene to be executed.</LI>
44 * @see SlipBridgeCommunicationProtocol
46 * @author Guenther Schreiner - Initial contribution.
49 class SCrunScene extends RunScene implements SlipBridgeCommunicationProtocol {
50 private final Logger logger = LoggerFactory.getLogger(SCrunScene.class);
52 private static final String DESCRIPTION = "Run Scene";
53 private static final Command COMMAND = Command.GW_ACTIVATE_SCENE_REQ;
56 * ===========================================================
57 * Message Content Parameters
60 private int reqSessionID = 0;
61 private int reqCommandOriginator = 8; // SAAC
62 private int reqPriorityLevel = 5; // Comfort Level 2
63 private int reqSceneID = -1; // SceneID as one unsigned byte number
64 private int reqVelocity = 0; // The product group operates by its default velocity.
67 * ===========================================================
71 private byte[] requestData = new byte[0];
74 * ===========================================================
78 private boolean success = false;
79 private boolean finished = false;
82 * ===========================================================
89 * Initializes the session id {@link #reqSessionID} with a random start value.
92 logger.debug("SCrunScene(Constructor) called.");
93 Random rand = new Random();
94 reqSessionID = rand.nextInt(0x0fff);
95 logger.debug("SCrunScene(): starting sessions with the random number {}.", reqSessionID);
99 * ===========================================================
100 * Methods required for interface {@link BridgeCommunicationProtocol}.
104 public String name() {
109 public CommandNumber getRequestCommand() {
112 logger.trace("getRequestCommand() returns {} ({}).", COMMAND.name(), COMMAND.getCommand());
113 return COMMAND.getCommand();
117 public byte[] getRequestDataAsArrayOfBytes() {
118 Packet request = new Packet(new byte[6]);
119 reqSessionID = (reqSessionID + 1) & 0xffff;
120 request.setTwoByteValue(0, reqSessionID);
121 request.setOneByteValue(2, reqCommandOriginator);
122 request.setOneByteValue(3, reqPriorityLevel);
123 request.setOneByteValue(4, reqSceneID);
124 request.setOneByteValue(5, reqVelocity);
125 requestData = request.toByteArray();
126 logger.trace("getRequestCommand(): SessionID={}.", reqSessionID);
127 logger.trace("getRequestCommand(): CommandOriginator={}.", reqCommandOriginator);
128 logger.trace("getRequestCommand(): PriorityLevel={}.", reqPriorityLevel);
129 logger.trace("getRequestCommand(): SceneID={}.", reqSceneID);
130 logger.trace("getRequestCommand(): Velocity={}.", reqVelocity);
131 logger.debug("getRequestCommand() returns {} ({}) with SceneID {}.", COMMAND.name(), COMMAND.getCommand(),
137 public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
138 KLF200Response.introLogging(logger, responseCommand, thisResponseData);
141 Packet responseData = new Packet(thisResponseData);
142 switch (Command.get(responseCommand)) {
143 case GW_ACTIVATE_SCENE_CFM:
144 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 3)) {
148 int cfmStatus = responseData.getOneByteValue(0);
149 int cfmSessionID = responseData.getTwoByteValue(1);
152 logger.trace("setResponse(): returned status: OK - Request accepted.");
153 if (!KLF200Response.check4matchingSessionID(logger, cfmSessionID, reqSessionID)) {
155 } else if (!isSequentialEnforced) {
157 "setResponse(): skipping wait for more packets as sequential processing is not enforced.");
164 logger.trace("setResponse(): returned status: Error – Invalid parameter.");
168 logger.trace("setResponse(): returned status: Error – Request rejected.");
172 logger.warn("setResponse({}): returned status={} (Reserved/unknown).",
173 Command.get(responseCommand).toString(), cfmStatus);
178 case GW_COMMAND_RUN_STATUS_NTF:
179 logger.trace("setResponse(): received GW_COMMAND_RUN_STATUS_NTF, continuing.");
180 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 13)) {
181 logger.trace("setResponse(): GW_COMMAND_RUN_STATUS_NTF received with invalid length.");
185 // Extracting information items
186 int ntfSessionID = responseData.getTwoByteValue(0);
187 int ntfStatusID = responseData.getOneByteValue(2);
188 int ntfIndex = responseData.getOneByteValue(3);
189 int ntfNodeParameter = responseData.getOneByteValue(4);
190 int ntfParameterValue = responseData.getTwoByteValue(5);
191 int ntfRunStatus = responseData.getOneByteValue(7);
192 int ntfStatusReply = responseData.getOneByteValue(8);
193 int ntfInformationCode = responseData.getFourByteValue(9);
195 logger.trace("setResponse(): SessionID={}.", ntfSessionID);
196 logger.trace("setResponse(): StatusID={}.", ntfStatusID);
197 logger.trace("setResponse(): Index={}.", ntfIndex);
198 logger.trace("setResponse(): NodeParameter={}.", ntfNodeParameter);
199 logger.trace("setResponse(): ParameterValue={}.", ntfParameterValue);
200 logger.trace("setResponse(): RunStatus={}.", ntfRunStatus);
201 logger.trace("setResponse(): StatusReply={}.", ntfStatusReply);
202 logger.trace("setResponse(): InformationCode={}.", ntfInformationCode);
204 if (!isSequentialEnforced) {
206 "setResponse(): skipping wait for more packets as sequential processing is not enforced.");
212 case GW_COMMAND_REMAINING_TIME_NTF:
213 logger.trace("setResponse(): received GW_COMMAND_REMAINING_TIME_NTF, continuing.");
214 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 6)) {
215 logger.trace("setResponse(): GW_COMMAND_REMAINING_TIME_NTF received with invalid length.");
219 // Extracting information items
220 ntfSessionID = responseData.getTwoByteValue(0);
221 ntfIndex = responseData.getOneByteValue(2);
222 ntfNodeParameter = responseData.getOneByteValue(3);
223 int ntfSeconds = responseData.getTwoByteValue(4);
225 logger.trace("setResponse(): SessionID={}.", ntfSessionID);
226 logger.trace("setResponse(): Index={}.", ntfIndex);
227 logger.trace("setResponse(): NodeParameter={}.", ntfNodeParameter);
228 logger.trace("setResponse(): Seconds={}.", ntfSeconds);
230 if (!isSequentialEnforced) {
232 "setResponse(): skipping wait for more packets as sequential processing is not enforced.");
238 case GW_SESSION_FINISHED_NTF:
239 logger.trace("setResponse(): received GW_SESSION_FINISHED_NTF.");
240 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 2)) {
241 logger.trace("setResponse(): GW_SESSION_FINISHED_NTF received with invalid length.");
245 // Extracting information items
246 ntfSessionID = responseData.getTwoByteValue(0);
248 logger.trace("setResponse(): SessionID={}.", ntfSessionID);
255 KLF200Response.errorLogging(logger, responseCommand);
258 KLF200Response.outroLogging(logger, success, finished);
262 public boolean isCommunicationFinished() {
267 public boolean isCommunicationSuccessful() {
272 * ===========================================================
273 * Methods in addition to the interface {@link BridgeCommunicationProtocol}
274 * and the abstract class {@link RunScene}
278 public SCrunScene setSceneId(int sceneId) {
279 logger.trace("setProductId({}) called.", sceneId);
280 this.reqSceneID = sceneId;
285 public SCrunScene setVelocity(int velocity) {
286 logger.trace("setVelocity({}) called.", velocity);
287 this.reqVelocity = velocity;