]> git.basschouten.com Git - openhab-addons.git/blob
305a7ef719e997d3f88e7b65ec0f1231b31ab217
[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.SetProductLimitation;
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.openhab.binding.velux.internal.things.VeluxProductPosition;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28  * Protocol specific bridge communication supported by the Velux bridge:
29  * <B>Modify Product Limitations</B>
30  * <P>
31  * Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
32  * itself.
33  * <P>
34  * As 3rd level class it defines informations how to send query and receive answer through the
35  * {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
36  * as described by the interface {@link SlipBridgeCommunicationProtocol}.
37  * <P>
38  * Methods in addition to the mentioned interface:
39  * <UL>
40  * <LI>{@link #setActuatorIdAndMinimumLimitation} to set the lower limitation of one specific product.</LI>
41  * <LI>{@link #setActuatorIdAndMaximumLimitation} to set the higher limitation of one specific product.</LI>
42  * <LI>{@link #setActuatorIdAndResetLimitation} to reset any limitation of one specific product.</LI>
43  * </UL>
44  *
45  * @see SetProductLimitation
46  * @see SlipBridgeCommunicationProtocol
47  *
48  * @author Guenther Schreiner - Initial contribution.
49  */
50 @NonNullByDefault
51 class SCsetLimitation extends SetProductLimitation implements SlipBridgeCommunicationProtocol {
52     private final Logger logger = LoggerFactory.getLogger(SCsetLimitation.class);
53
54     private static final String DESCRIPTION = "Modify Actuator Limitation";
55     private static final Command COMMAND = Command.GW_SET_LIMITATION_REQ;
56
57     /*
58      * ===========================================================
59      * Message Content Parameters
60      */
61
62     private int reqSessionID = 0;
63     private int reqCommandOriginator = 8; // SAAC
64     private int reqPriorityLevel = 5; // Comfort Level 2
65     private int reqIndexArrayCount = 1; // One node will be addressed
66     private int reqIndexArray01 = 1; // This is the node
67     private int reqParameterID = 0; // MP = Main parameter
68     private int reqLimitationValueMin = VeluxProductPosition.VPP_VELUX_IGNORE; // will be set lateron
69     private int reqLimitationValueMax = VeluxProductPosition.VPP_VELUX_IGNORE; // will be set lateron
70     private int reqLimitationTime = 0; // 0 = 30 seconds, 1 = 60 seconds, ..., 253 = unlimited, 254 = clear entry for
71                                        // the Master, 255 = clear all
72
73     /*
74      * ===========================================================
75      * Message Objects
76      */
77
78     private byte[] requestData = new byte[0];
79
80     /*
81      * ===========================================================
82      * Result Objects
83      */
84
85     private boolean success = false;
86     private boolean finished = false;
87
88     /*
89      * ===========================================================
90      * Constructor Method
91      */
92
93     public SCsetLimitation() {
94         logger.debug("SCsetLimitation(Constructor) called.");
95         Random rand = new Random();
96         reqSessionID = rand.nextInt(0x0fff);
97         logger.debug("SCsetLimitation(): starting sessions with the random number {}.", reqSessionID);
98     }
99
100     /*
101      * ===========================================================
102      * Methods required for interface {@link BridgeCommunicationProtocol}.
103      */
104
105     @Override
106     public String name() {
107         return DESCRIPTION;
108     }
109
110     @Override
111     public CommandNumber getRequestCommand() {
112         success = false;
113         finished = false;
114         logger.debug("getRequestCommand() returns {} ({}).", COMMAND.name(), COMMAND.getCommand());
115         return COMMAND.getCommand();
116     }
117
118     @Override
119     public byte[] getRequestDataAsArrayOfBytes() {
120         Packet request = new Packet(new byte[31]);
121         reqSessionID = (reqSessionID + 1) & 0xffff;
122         request.setTwoByteValue(0, reqSessionID);
123         request.setOneByteValue(2, reqCommandOriginator);
124         request.setOneByteValue(3, reqPriorityLevel);
125         request.setOneByteValue(4, reqIndexArrayCount);
126         request.setOneByteValue(5, reqIndexArray01);
127         request.setOneByteValue(25, reqParameterID);
128         request.setTwoByteValue(26, reqLimitationValueMin);
129         request.setTwoByteValue(28, reqLimitationValueMax);
130         request.setOneByteValue(30, reqLimitationTime);
131         logger.trace("getRequestDataAsArrayOfBytes(): ntfSessionID={}.", reqSessionID);
132         logger.trace("getRequestDataAsArrayOfBytes(): reqCommandOriginator={}.", reqCommandOriginator);
133         logger.trace("getRequestDataAsArrayOfBytes(): reqPriorityLevel={}.", reqPriorityLevel);
134         logger.trace("getRequestDataAsArrayOfBytes(): reqIndexArrayCount={}.", reqIndexArrayCount);
135         logger.trace("getRequestDataAsArrayOfBytes(): reqIndexArray01={}.", reqIndexArray01);
136         logger.trace("getRequestDataAsArrayOfBytes(): reqParameterID={}.", reqParameterID);
137         logger.trace("getRequestDataAsArrayOfBytes(): reqLimitationValueMin={}.", reqLimitationValueMin);
138         logger.trace("getRequestDataAsArrayOfBytes(): reqLimitationValueMax={}.", reqLimitationValueMax);
139         logger.trace("getRequestDataAsArrayOfBytes(): reqLimitationTime={}.", reqLimitationTime);
140         requestData = request.toByteArray();
141         logger.trace("getRequestDataAsArrayOfBytes() data is {}.", new Packet(requestData).toString());
142         return requestData;
143     }
144
145     @Override
146     public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
147         KLF200Response.introLogging(logger, responseCommand, thisResponseData);
148         success = false;
149         finished = false;
150         Packet responseData = new Packet(thisResponseData);
151         switch (Command.get(responseCommand)) {
152             case GW_SET_LIMITATION_CFM:
153                 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 3)) {
154                     finished = true;
155                     break;
156                 }
157                 int cfmSessionID = responseData.getTwoByteValue(0);
158                 int cfmStatus = responseData.getOneByteValue(2);
159                 switch (cfmStatus) {
160                     case 0:
161                         logger.info("setResponse(): returned status: Error – Command rejected.");
162                         finished = true;
163                         break;
164                     case 1:
165                         logger.debug("setResponse(): returned status: OK - Command is accepted.");
166                         if (!KLF200Response.check4matchingSessionID(logger, cfmSessionID, reqSessionID)) {
167                             finished = true;
168                         }
169                         break;
170                     default:
171                         logger.warn("setResponse(): returned status={} (not defined).", cfmStatus);
172                         finished = true;
173                         break;
174                 }
175                 break;
176
177             case GW_LIMITATION_STATUS_NTF:
178                 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 10)) {
179                     break;
180                 }
181                 // Extracting information items
182                 int ntfSessionID = responseData.getTwoByteValue(0);
183                 int ntfNodeID = responseData.getOneByteValue(2);
184                 int ntfParameterID = responseData.getOneByteValue(3);
185                 int ntfMinValue = responseData.getTwoByteValue(4);
186                 int ntfMaxValue = responseData.getTwoByteValue(6);
187                 int ntfLimitationOriginator = responseData.getOneByteValue(8);
188                 int ntfLimitationTime = responseData.getOneByteValue(9);
189                 logger.trace("setResponse(): nodeId={}.", ntfNodeID);
190                 logger.trace("setResponse(): ntfParameterID={}.", ntfParameterID);
191                 logger.trace("setResponse(): ntfMinValue={}.", ntfMinValue);
192                 logger.trace("setResponse(): ntfMaxValue={}.", ntfMaxValue);
193                 logger.trace("setResponse(): ntfLimitationOriginator={}.", ntfLimitationOriginator);
194                 logger.trace("setResponse(): ntfLimitationTime={}.", ntfLimitationTime);
195
196                 if (!KLF200Response.check4matchingSessionID(logger, ntfSessionID, reqSessionID)) {
197                     finished = true;
198                     break;
199                 }
200                 success = true;
201                 if (!isSequentialEnforced) {
202                     logger.trace(
203                             "setResponse(): skipping wait for more packets as sequential processing is not enforced.");
204                     finished = true;
205                 }
206                 break;
207
208             case GW_COMMAND_RUN_STATUS_NTF:
209                 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 13)) {
210                     finished = true;
211                     break;
212                 }
213                 ntfSessionID = responseData.getTwoByteValue(0);
214                 int ntfStatusiD = responseData.getOneByteValue(2);
215                 int ntfIndex = responseData.getOneByteValue(3);
216                 int ntfNodeParameter = responseData.getOneByteValue(4);
217                 int ntfParameterValue = responseData.getTwoByteValue(5);
218                 int ntfRunStatus = responseData.getOneByteValue(7);
219                 int ntfStatusReply = responseData.getOneByteValue(8);
220                 int ntfInformationCode = responseData.getFourByteValue(9);
221                 // Extracting information items
222                 logger.trace("setResponse(): ntfSessionID={} (requested {}).", ntfSessionID, reqSessionID);
223                 logger.trace("setResponse(): ntfStatusiD={}.", ntfStatusiD);
224                 logger.trace("setResponse(): ntfIndex={}.", ntfIndex);
225                 logger.trace("setResponse(): ntfNodeParameter={}.", ntfNodeParameter);
226                 logger.trace("setResponse(): ntfParameterValue={}.", ntfParameterValue);
227                 logger.trace("setResponse(): ntfRunStatus={}.", ntfRunStatus);
228                 logger.trace("setResponse(): ntfStatusReply={}.", ntfStatusReply);
229                 logger.trace("setResponse(): ntfInformationCode={}.", ntfInformationCode);
230
231                 if (!KLF200Response.check4matchingSessionID(logger, ntfSessionID, reqSessionID)) {
232                     finished = true;
233                 }
234                 switch (ntfRunStatus) {
235                     case 0:
236                         logger.debug("setResponse(): returned ntfRunStatus: EXECUTION_COMPLETED.");
237                         success = true;
238                         break;
239                     case 1:
240                         logger.info("setResponse(): returned ntfRunStatus: EXECUTION_FAILED.");
241                         finished = true;
242                         break;
243                     case 2:
244                         logger.debug("setResponse(): returned ntfRunStatus: EXECUTION_ACTIVE.");
245                         break;
246                     default:
247                         logger.warn("setResponse(): returned ntfRunStatus={} (not defined).", ntfRunStatus);
248                         finished = true;
249                         break;
250                 }
251                 if (!isSequentialEnforced) {
252                     logger.trace(
253                             "setResponse(): skipping wait for more packets as sequential processing is not enforced.");
254                     success = true;
255                     finished = true;
256                 }
257                 break;
258
259             case GW_SESSION_FINISHED_NTF:
260                 finished = true;
261                 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 2)) {
262                     break;
263                 }
264                 int finishedNtfSessionID = responseData.getTwoByteValue(0);
265                 if (!KLF200Response.check4matchingSessionID(logger, finishedNtfSessionID, reqSessionID)) {
266                     break;
267                 }
268                 logger.debug("setResponse(): finishedNtfSessionID={}.", finishedNtfSessionID);
269                 success = true;
270                 break;
271
272             default:
273                 KLF200Response.errorLogging(logger, responseCommand);
274         }
275         KLF200Response.outroLogging(logger, success, finished);
276     }
277
278     @Override
279     public boolean isCommunicationFinished() {
280         return finished;
281     }
282
283     @Override
284     public boolean isCommunicationSuccessful() {
285         return success;
286     }
287
288     /*
289      * ===========================================================
290      * Methods in addition to the interface {@link BridgeCommunicationProtocol}
291      * and the abstract class {@link SetProductLimitation}
292      */
293
294     @Override
295     public void setActuatorIdAndMinimumLimitation(int nodeId, int limitation) {
296         logger.trace("setActuatorIdAndLimitationTypeAndLimitation({},{}) called.", nodeId, limitation);
297         reqIndexArray01 = nodeId;
298         reqLimitationValueMin = limitation;
299         reqLimitationValueMax = VeluxProductPosition.VPP_VELUX_IGNORE;
300         return;
301     }
302
303     @Override
304     public void setActuatorIdAndMaximumLimitation(int nodeId, int limitation) {
305         logger.trace("setActuatorIdAndLimitationTypeAndLimitation({},{}) called.", nodeId, limitation);
306         reqIndexArray01 = nodeId;
307         reqLimitationValueMin = VeluxProductPosition.VPP_VELUX_IGNORE;
308         reqLimitationValueMax = limitation;
309         return;
310     }
311
312     public void setActuatorIdAndResetLimitation(int nodeId) {
313         logger.trace("setActuatorIdAndResetLimitation({}) called.", nodeId);
314         reqIndexArray01 = nodeId;
315         reqLimitationValueMin = VeluxProductPosition.VPP_VELUX_IGNORE;
316         reqLimitationValueMax = VeluxProductPosition.VPP_VELUX_IGNORE;
317         return;
318     }
319 }