2 * Copyright (c) 2010-2022 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.RunProductCommand;
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:
28 * <B>Send Command to Actuator</B>
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 #setNodeAndMainParameter} to define the node and intended parameter value.</LI>
43 * @see RunProductCommand
44 * @see SlipBridgeCommunicationProtocol
46 * @author Guenther Schreiner - Initial contribution.
49 class SCrunProductCommand extends RunProductCommand implements SlipBridgeCommunicationProtocol {
50 private final Logger logger = LoggerFactory.getLogger(SCrunProductCommand.class);
52 private static final String DESCRIPTION = "Send Command to Actuator";
53 private static final Command COMMAND = Command.GW_COMMAND_SEND_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 reqParameterActive = 0; // Main Parameter
64 private int reqFPI1 = 0; // Functional Parameter Indicator 1 set of bits
65 private int reqFPI2 = 0; // Functional Parameter Indicator 2 set of bits
66 private int reqMainParameter = 0; // for FunctionalParameterValueArray
67 private int reqIndexArrayCount = 1; // One node will be addressed
68 private int reqIndexArray01 = 1; // This is the node
69 private int reqPriorityLevelLock = 0; // Do not set a new lock on priority level
70 private int reqPL03 = 0; // unused
71 private int reqPL47 = 0; // unused
72 private int reqLockTime = 0; // 30 seconds
75 * ===========================================================
79 private byte[] requestData = new byte[0];
82 * ===========================================================
86 private boolean success = false;
87 private boolean finished = false;
90 * ===========================================================
94 public SCrunProductCommand() {
95 logger.debug("SCgetProduct(Constructor) called.");
96 Random rand = new Random();
97 reqSessionID = rand.nextInt(0x0fff);
98 logger.debug("SCgetProduct(): starting sessions with the random number {}.", reqSessionID);
102 * ===========================================================
103 * Methods required for interface {@link BridgeCommunicationProtocol}.
107 public String name() {
112 public CommandNumber getRequestCommand() {
115 logger.debug("getRequestCommand() returns {}.", COMMAND.getCommand());
116 return COMMAND.getCommand();
120 public byte[] getRequestDataAsArrayOfBytes() {
121 Packet request = new Packet(new byte[66]);
122 reqSessionID = (reqSessionID + 1) & 0xffff;
123 request.setTwoByteValue(0, reqSessionID);
124 request.setOneByteValue(2, reqCommandOriginator);
125 request.setOneByteValue(3, reqPriorityLevel);
126 request.setOneByteValue(4, reqParameterActive);
127 request.setOneByteValue(5, reqFPI1);
128 request.setOneByteValue(6, reqFPI2);
129 request.setTwoByteValue(7, reqMainParameter);
130 request.setOneByteValue(41, reqIndexArrayCount);
131 request.setOneByteValue(42, reqIndexArray01);
132 request.setOneByteValue(62, reqPriorityLevelLock);
133 request.setOneByteValue(63, reqPL03);
134 request.setOneByteValue(64, reqPL47);
135 request.setOneByteValue(65, reqLockTime);
136 logger.trace("getRequestDataAsArrayOfBytes(): ntfSessionID={}.", reqSessionID);
137 logger.trace("getRequestDataAsArrayOfBytes(): reqCommandOriginator={}.", reqCommandOriginator);
138 logger.trace("getRequestDataAsArrayOfBytes(): reqPriorityLevel={}.", reqPriorityLevel);
139 logger.trace("getRequestDataAsArrayOfBytes(): reqParameterActive={}.", reqParameterActive);
140 logger.trace("getRequestDataAsArrayOfBytes(): reqFPI1={}.", reqFPI1);
141 logger.trace("getRequestDataAsArrayOfBytes(): reqFPI2={}.", reqFPI2);
142 logger.trace("getRequestDataAsArrayOfBytes(): reqMainParameter={}.", reqMainParameter);
143 logger.trace("getRequestDataAsArrayOfBytes(): reqIndexArrayCount={}.", reqIndexArrayCount);
144 logger.trace("getRequestDataAsArrayOfBytes(): reqIndexArray01={}.", reqIndexArray01);
145 logger.trace("getRequestDataAsArrayOfBytes(): reqPriorityLevelLock={}.", reqPriorityLevelLock);
146 logger.trace("getRequestDataAsArrayOfBytes(): reqPL03={}.", reqPL03);
147 logger.trace("getRequestDataAsArrayOfBytes(): reqPL47={}.", reqPL47);
148 logger.trace("getRequestDataAsArrayOfBytes(): reqLockTime={}.", reqLockTime);
149 requestData = request.toByteArray();
150 logger.trace("getRequestDataAsArrayOfBytes() data is {}.", new Packet(requestData).toString());
155 public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
156 KLF200Response.introLogging(logger, responseCommand, thisResponseData);
159 Packet responseData = new Packet(thisResponseData);
160 switch (Command.get(responseCommand)) {
161 case GW_COMMAND_SEND_CFM:
162 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 3)) {
166 int cfmSessionID = responseData.getTwoByteValue(0);
167 int cfmStatus = responseData.getOneByteValue(2);
170 logger.info("setResponse(): returned status: Error – Command rejected.");
174 logger.debug("setResponse(): returned status: OK - Command is accepted.");
175 if (!KLF200Response.check4matchingSessionID(logger, cfmSessionID, reqSessionID)) {
177 } else if (!isSequentialEnforced) {
179 "setResponse(): skipping wait for more packets as sequential processing is not enforced.");
185 logger.warn("setResponse(): returned status={} (not defined).", cfmStatus);
191 case GW_COMMAND_RUN_STATUS_NTF:
192 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 13)) {
196 int ntfSessionID = responseData.getTwoByteValue(0);
197 int ntfStatusiD = responseData.getOneByteValue(2);
198 int ntfIndex = responseData.getOneByteValue(3);
199 int ntfNodeParameter = responseData.getOneByteValue(4);
200 int ntfParameterValue = responseData.getTwoByteValue(5);
201 int ntfRunStatus = responseData.getOneByteValue(7);
202 int ntfStatusReply = responseData.getOneByteValue(8);
203 int ntfInformationCode = responseData.getFourByteValue(9);
204 // Extracting information items
205 logger.debug("setResponse(): ntfSessionID={} (requested {}).", ntfSessionID, reqSessionID);
206 logger.debug("setResponse(): ntfStatusiD={}.", ntfStatusiD);
207 logger.debug("setResponse(): ntfIndex={}.", ntfIndex);
208 logger.debug("setResponse(): ntfNodeParameter={}.", ntfNodeParameter);
209 logger.debug("setResponse(): ntfParameterValue={}.", ntfParameterValue);
210 logger.debug("setResponse(): ntfRunStatus={}.", ntfRunStatus);
211 logger.debug("setResponse(): ntfStatusReply={}.", ntfStatusReply);
212 logger.debug("setResponse(): ntfInformationCode={}.", ntfInformationCode);
214 if (!KLF200Response.check4matchingSessionID(logger, ntfSessionID, reqSessionID)) {
217 switch (ntfRunStatus) {
219 logger.debug("setResponse(): returned ntfRunStatus: EXECUTION_COMPLETED.");
223 logger.info("setResponse(): returned ntfRunStatus: EXECUTION_FAILED.");
227 logger.debug("setResponse(): returned ntfRunStatus: EXECUTION_ACTIVE.");
230 logger.warn("setResponse(): returned ntfRunStatus={} (not defined).", ntfRunStatus);
234 if (!isSequentialEnforced) {
236 "setResponse(): skipping wait for more packets as sequential processing is not enforced.");
242 case GW_COMMAND_REMAINING_TIME_NTF:
243 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 6)) {
247 int timeNtfSessionID = responseData.getTwoByteValue(0);
248 int timeNtfIndex = responseData.getOneByteValue(2);
249 int timeNtfNodeParameter = responseData.getOneByteValue(3);
250 int timeNtfSeconds = responseData.getTwoByteValue(4);
252 if (!KLF200Response.check4matchingSessionID(logger, timeNtfSessionID, reqSessionID)) {
256 // Extracting information items
257 logger.debug("setResponse(): timeNtfSessionID={}.", timeNtfSessionID);
258 logger.debug("setResponse(): timeNtfIndex={}.", timeNtfIndex);
259 logger.debug("setResponse(): timeNtfNodeParameter={}.", timeNtfNodeParameter);
260 logger.debug("setResponse(): timeNtfSeconds={}.", timeNtfSeconds);
261 if (!isSequentialEnforced) {
263 "setResponse(): skipping wait for more packets as sequential processing is not enforced.");
269 case GW_SESSION_FINISHED_NTF:
271 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 2)) {
274 int finishedNtfSessionID = responseData.getTwoByteValue(0);
275 if (!KLF200Response.check4matchingSessionID(logger, finishedNtfSessionID, reqSessionID)) {
278 logger.debug("setResponse(): finishedNtfSessionID={}.", finishedNtfSessionID);
283 KLF200Response.errorLogging(logger, responseCommand);
286 KLF200Response.outroLogging(logger, success, finished);
290 public boolean isCommunicationFinished() {
295 public boolean isCommunicationSuccessful() {
300 * ===========================================================
301 * Methods in addition to the interface {@link BridgeCommunicationProtocol}
302 * and the abstract class {@link RunProductCommand}
306 public SCrunProductCommand setNodeAndMainParameter(int nodeId, int value) {
307 logger.debug("setNodeAndMainParameter({}) called.", nodeId);
308 this.reqIndexArray01 = nodeId;
309 this.reqMainParameter = value;