]> git.basschouten.com Git - openhab-addons.git/blob
0a259a682204b53e0fbdf33ac0e87fdd96de42ab
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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.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;
25
26 /**
27  * Protocol specific bridge communication supported by the Velux bridge:
28  * <B>Send Command to Actuator</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 #setNodeAndMainParameter} to define the node and intended parameter value.</LI>
41  * </UL>
42  *
43  * @see RunProductCommand
44  * @see SlipBridgeCommunicationProtocol
45  *
46  * @author Guenther Schreiner - Initial contribution.
47  */
48 @NonNullByDefault
49 class SCrunProductCommand extends RunProductCommand implements SlipBridgeCommunicationProtocol {
50     private final Logger logger = LoggerFactory.getLogger(SCrunProductCommand.class);
51
52     private static final String DESCRIPTION = "Send Command to Actuator";
53     private static final Command COMMAND = Command.GW_COMMAND_SEND_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 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
73
74     /*
75      * ===========================================================
76      * Message Objects
77      */
78
79     private byte[] requestData = new byte[0];
80
81     /*
82      * ===========================================================
83      * Result Objects
84      */
85
86     private boolean success = false;
87     private boolean finished = false;
88
89     /*
90      * ===========================================================
91      * Constructor Method
92      */
93
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);
99     }
100
101     /*
102      * ===========================================================
103      * Methods required for interface {@link BridgeCommunicationProtocol}.
104      */
105
106     @Override
107     public String name() {
108         return DESCRIPTION;
109     }
110
111     @Override
112     public CommandNumber getRequestCommand() {
113         success = false;
114         finished = false;
115         logger.debug("getRequestCommand() returns {}.", COMMAND.getCommand());
116         return COMMAND.getCommand();
117     }
118
119     @Override
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());
151         return requestData;
152     }
153
154     @Override
155     public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
156         KLF200Response.introLogging(logger, responseCommand, thisResponseData);
157         success = false;
158         finished = false;
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)) {
163                     finished = true;
164                     break;
165                 }
166                 int cfmSessionID = responseData.getTwoByteValue(0);
167                 int cfmStatus = responseData.getOneByteValue(2);
168                 switch (cfmStatus) {
169                     case 0:
170                         logger.info("setResponse(): returned status: Error – Command rejected.");
171                         finished = true;
172                         break;
173                     case 1:
174                         logger.debug("setResponse(): returned status: OK - Command is accepted.");
175                         if (!KLF200Response.check4matchingSessionID(logger, cfmSessionID, reqSessionID)) {
176                             finished = true;
177                         } else if (!isSequentialEnforced) {
178                             logger.trace(
179                                     "setResponse(): skipping wait for more packets as sequential processing is not enforced.");
180                             finished = true;
181                             success = true;
182                         }
183                         break;
184                     default:
185                         logger.warn("setResponse(): returned status={} (not defined).", cfmStatus);
186                         finished = true;
187                         break;
188                 }
189                 break;
190
191             case GW_COMMAND_RUN_STATUS_NTF:
192                 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 13)) {
193                     finished = true;
194                     break;
195                 }
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);
213
214                 if (!KLF200Response.check4matchingSessionID(logger, ntfSessionID, reqSessionID)) {
215                     finished = true;
216                 }
217                 switch (ntfRunStatus) {
218                     case 0:
219                         logger.debug("setResponse(): returned ntfRunStatus: EXECUTION_COMPLETED.");
220                         success = true;
221                         break;
222                     case 1:
223                         logger.info("setResponse(): returned ntfRunStatus: EXECUTION_FAILED.");
224                         finished = true;
225                         break;
226                     case 2:
227                         logger.debug("setResponse(): returned ntfRunStatus: EXECUTION_ACTIVE.");
228                         break;
229                     default:
230                         logger.warn("setResponse(): returned ntfRunStatus={} (not defined).", ntfRunStatus);
231                         finished = true;
232                         break;
233                 }
234                 if (!isSequentialEnforced) {
235                     logger.trace(
236                             "setResponse(): skipping wait for more packets as sequential processing is not enforced.");
237                     success = true;
238                     finished = true;
239                 }
240                 break;
241
242             case GW_COMMAND_REMAINING_TIME_NTF:
243                 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 6)) {
244                     finished = true;
245                     break;
246                 }
247                 int timeNtfSessionID = responseData.getTwoByteValue(0);
248                 int timeNtfIndex = responseData.getOneByteValue(2);
249                 int timeNtfNodeParameter = responseData.getOneByteValue(3);
250                 int timeNtfSeconds = responseData.getTwoByteValue(4);
251
252                 if (!KLF200Response.check4matchingSessionID(logger, timeNtfSessionID, reqSessionID)) {
253                     finished = true;
254                 }
255
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) {
262                     logger.trace(
263                             "setResponse(): skipping wait for more packets as sequential processing is not enforced.");
264                     success = true;
265                     finished = true;
266                 }
267                 break;
268
269             case GW_SESSION_FINISHED_NTF:
270                 finished = true;
271                 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 2)) {
272                     break;
273                 }
274                 int finishedNtfSessionID = responseData.getTwoByteValue(0);
275                 if (!KLF200Response.check4matchingSessionID(logger, finishedNtfSessionID, reqSessionID)) {
276                     break;
277                 }
278                 logger.debug("setResponse(): finishedNtfSessionID={}.", finishedNtfSessionID);
279                 success = true;
280                 break;
281
282             default:
283                 KLF200Response.errorLogging(logger, responseCommand);
284                 finished = true;
285         }
286         KLF200Response.outroLogging(logger, success, finished);
287     }
288
289     @Override
290     public boolean isCommunicationFinished() {
291         return finished;
292     }
293
294     @Override
295     public boolean isCommunicationSuccessful() {
296         return success;
297     }
298
299     /*
300      * ===========================================================
301      * Methods in addition to the interface {@link BridgeCommunicationProtocol}
302      * and the abstract class {@link RunProductCommand}
303      */
304
305     @Override
306     public SCrunProductCommand setNodeAndMainParameter(int nodeId, int value) {
307         logger.debug("setNodeAndMainParameter({}) called.", nodeId);
308         this.reqIndexArray01 = nodeId;
309         this.reqMainParameter = value;
310         return this;
311     }
312 }