]> git.basschouten.com Git - openhab-addons.git/blob
4c32f6d350a41e4af655f5494fa5acd68252b2d2
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.velux.internal.bridge.slip;
14
15 import java.util.Random;
16
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;
25
26 /**
27  * Protocol specific bridge communication supported by the Velux bridge:
28  * <B>Run Scene</B>
29  * <P>
30  * Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
31  * itself.
32  * <P>
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}.
37  * <P>
38  * Methods in addition to the mentioned interface:
39  * <UL>
40  * <LI>{@link #setSceneId} to define the scene to be executed.</LI>
41  * </UL>
42  *
43  * @see RunScene
44  * @see SlipBridgeCommunicationProtocol
45  *
46  * @author Guenther Schreiner - Initial contribution.
47  */
48 @NonNullByDefault
49 class SCrunScene extends RunScene implements SlipBridgeCommunicationProtocol {
50     private final Logger logger = LoggerFactory.getLogger(SCrunScene.class);
51
52     private static final String DESCRIPTION = "Run Scene";
53     private static final Command COMMAND = Command.GW_ACTIVATE_SCENE_REQ;
54
55     /*
56      * ===========================================================
57      * Message Content Parameters
58      */
59
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.
65
66     /*
67      * ===========================================================
68      * Message Objects
69      */
70
71     private byte[] requestData = new byte[0];
72
73     /*
74      * ===========================================================
75      * Result Objects
76      */
77
78     private boolean success = false;
79     private boolean finished = false;
80
81     /*
82      * ===========================================================
83      * Constructor Method
84      */
85
86     /**
87      * Constructor.
88      * <P>
89      * Initializes the session id {@link #reqSessionID} with a random start value.
90      */
91     public SCrunScene() {
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);
96     }
97
98     /*
99      * ===========================================================
100      * Methods required for interface {@link BridgeCommunicationProtocol}.
101      */
102
103     @Override
104     public String name() {
105         return DESCRIPTION;
106     }
107
108     @Override
109     public CommandNumber getRequestCommand() {
110         success = false;
111         finished = false;
112         logger.trace("getRequestCommand() returns {} ({}).", COMMAND.name(), COMMAND.getCommand());
113         return COMMAND.getCommand();
114     }
115
116     @Override
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(),
132                 reqSceneID);
133         return requestData;
134     }
135
136     @Override
137     public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
138         KLF200Response.introLogging(logger, responseCommand, thisResponseData);
139         success = false;
140         finished = false;
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)) {
145                     finished = true;
146                     break;
147                 }
148                 int cfmStatus = responseData.getOneByteValue(0);
149                 int cfmSessionID = responseData.getTwoByteValue(1);
150                 switch (cfmStatus) {
151                     case 0:
152                         logger.trace("setResponse(): returned status: OK - Request accepted.");
153                         if (!KLF200Response.check4matchingSessionID(logger, cfmSessionID, reqSessionID)) {
154                             finished = true;
155                         } else if (!isSequentialEnforced) {
156                             logger.trace(
157                                     "setResponse(): skipping wait for more packets as sequential processing is not enforced.");
158                             success = true;
159                             finished = true;
160                         }
161                         break;
162                     case 1:
163                         finished = true;
164                         logger.trace("setResponse(): returned status: Error – Invalid parameter.");
165                         break;
166                     case 2:
167                         finished = true;
168                         logger.trace("setResponse(): returned status: Error – Request rejected.");
169                         break;
170                     default:
171                         finished = true;
172                         logger.warn("setResponse({}): returned status={} (Reserved/unknown).",
173                                 Command.get(responseCommand).toString(), cfmStatus);
174                         break;
175                 }
176                 break;
177
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.");
182                     finished = true;
183                     break;
184                 }
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);
194
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);
203
204                 if (!isSequentialEnforced) {
205                     logger.trace(
206                             "setResponse(): skipping wait for more packets as sequential processing is not enforced.");
207                     success = true;
208                     finished = true;
209                 }
210                 break;
211
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.");
216                     finished = true;
217                     break;
218                 }
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);
224
225                 logger.trace("setResponse(): SessionID={}.", ntfSessionID);
226                 logger.trace("setResponse(): Index={}.", ntfIndex);
227                 logger.trace("setResponse(): NodeParameter={}.", ntfNodeParameter);
228                 logger.trace("setResponse(): Seconds={}.", ntfSeconds);
229
230                 if (!isSequentialEnforced) {
231                     logger.trace(
232                             "setResponse(): skipping wait for more packets as sequential processing is not enforced.");
233                     success = true;
234                     finished = true;
235                 }
236                 break;
237
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.");
242                     finished = true;
243                     break;
244                 }
245                 // Extracting information items
246                 ntfSessionID = responseData.getTwoByteValue(0);
247
248                 logger.trace("setResponse(): SessionID={}.", ntfSessionID);
249
250                 success = true;
251                 finished = true;
252                 break;
253
254             default:
255                 KLF200Response.errorLogging(logger, responseCommand);
256                 finished = true;
257         }
258         KLF200Response.outroLogging(logger, success, finished);
259     }
260
261     @Override
262     public boolean isCommunicationFinished() {
263         return finished;
264     }
265
266     @Override
267     public boolean isCommunicationSuccessful() {
268         return success;
269     }
270
271     /*
272      * ===========================================================
273      * Methods in addition to the interface {@link BridgeCommunicationProtocol}
274      * and the abstract class {@link RunScene}
275      */
276
277     @Override
278     public SCrunScene setSceneId(int sceneId) {
279         logger.trace("setProductId({}) called.", sceneId);
280         this.reqSceneID = sceneId;
281         return this;
282     }
283
284     @Override
285     public SCrunScene setVelocity(int velocity) {
286         logger.trace("setVelocity({}) called.", velocity);
287         this.reqVelocity = velocity;
288         return this;
289     }
290 }