]> git.basschouten.com Git - openhab-addons.git/blob
6f234824204b47acd2a3163735f8e836d8380794
[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 org.eclipse.jdt.annotation.NonNullByDefault;
16 import org.openhab.binding.velux.internal.bridge.common.GetProducts;
17 import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
18 import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
19 import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
20 import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
21 import org.openhab.binding.velux.internal.things.VeluxProduct;
22 import org.openhab.binding.velux.internal.things.VeluxProduct.ProductBridgeIndex;
23 import org.openhab.binding.velux.internal.things.VeluxProductName;
24 import org.openhab.binding.velux.internal.things.VeluxProductSerialNo;
25 import org.openhab.binding.velux.internal.things.VeluxProductType;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 /**
30  * Protocol specific bridge communication supported by the Velux bridge:
31  * <B>Retrieve Products</B>
32  * <P>
33  * Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
34  * itself.
35  * <P>
36  * As 3rd level class it defines informations how to send query and receive answer through the
37  * {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
38  * as described by the {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeCommunicationProtocol
39  * SlipBridgeCommunicationProtocol}.
40  * <P>
41  * Methods in addition to the mentioned interface:
42  * <UL>
43  * <LI>{@link #getProducts()} to retrieve the currently registered products.</LI>
44  * </UL>
45  *
46  * @see GetProducts
47  * @see SlipBridgeCommunicationProtocol
48  *
49  * @author Guenther Schreiner - Initial contribution.
50  */
51 @NonNullByDefault
52 class SCgetProducts extends GetProducts implements SlipBridgeCommunicationProtocol {
53     private final Logger logger = LoggerFactory.getLogger(SCgetProducts.class);
54
55     private static final String DESCRIPTION = "Retrieve Products";
56     private static final Command COMMAND = Command.GW_GET_ALL_NODES_INFORMATION_REQ;
57
58     /*
59      * ===========================================================
60      * Message Objects
61      */
62
63     private byte[] requestData = new byte[0];
64
65     /*
66      * ===========================================================
67      * Result Objects
68      */
69
70     private boolean success = false;
71     private boolean finished = false;
72
73     private VeluxProduct[] productArray = new VeluxProduct[0];
74     private int totalNumberOfProducts = 0;
75     private int nextProductArrayItem = 0;
76
77     /*
78      * ===========================================================
79      * Methods required for interface {@link BridgeCommunicationProtocol}.
80      */
81
82     @Override
83     public String name() {
84         return DESCRIPTION;
85     }
86
87     @Override
88     public CommandNumber getRequestCommand() {
89         success = false;
90         finished = false;
91         logger.debug("getRequestCommand() returns {} ({}).", COMMAND.name(), COMMAND.getCommand());
92         return COMMAND.getCommand();
93     }
94
95     @Override
96     public byte[] getRequestDataAsArrayOfBytes() {
97         requestData = new byte[0];
98         return requestData;
99     }
100
101     @Override
102     public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
103         KLF200Response.introLogging(logger, responseCommand, thisResponseData);
104         success = false;
105         finished = false;
106         Packet responseData = new Packet(thisResponseData);
107         switch (Command.get(responseCommand)) {
108             case GW_GET_ALL_NODES_INFORMATION_CFM:
109                 logger.trace("setResponse(): got GW_GET_ALL_NODES_INFORMATION_CFM.");
110                 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 2)) {
111                     finished = true;
112                     break;
113                 }
114                 int cfmStatus = responseData.getOneByteValue(0);
115                 int cfmTotalNumberOfNodes = responseData.getOneByteValue(1);
116                 logger.trace("setResponse(): status={}.", cfmStatus);
117                 logger.trace("setResponse(): TotalNumberOfNodes={}.", cfmTotalNumberOfNodes);
118
119                 // Initialize storage area
120                 productArray = new VeluxProduct[0];
121                 nextProductArrayItem = 0;
122                 switch (cfmStatus) {
123                     case 0:
124                         logger.trace("setResponse(): returned status: OK - Request accepted.");
125                         totalNumberOfProducts = cfmTotalNumberOfNodes;
126                         productArray = new VeluxProduct[totalNumberOfProducts];
127                         break;
128                     case 1:
129                         logger.trace("setResponse(): returned status: Error – System table empty.");
130                         finished = true;
131                         break;
132                     default:
133                         finished = true;
134                         logger.warn("setResponse({}): returned status={} (Reserved/unknown).",
135                                 Command.get(responseCommand).toString(), cfmStatus);
136                         break;
137                 }
138                 break;
139             case GW_GET_ALL_NODES_INFORMATION_NTF:
140                 logger.trace("setResponse(): got GW_GET_ALL_NODES_INFORMATION_NTF.");
141                 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 124)) {
142                     finished = true;
143                     break;
144                 }
145                 if (productArray.length == 0) {
146                     logger.warn("setResponse({}): sequence of answers unexpected.",
147                             Command.get(responseCommand).toString());
148                     finished = true;
149                     break;
150                 }
151                 // Extracting information items
152                 int ntfNodeID = responseData.getOneByteValue(0);
153                 logger.trace("setResponse(): ntfNodeID={}.", ntfNodeID);
154                 int ntfOrder = responseData.getTwoByteValue(1);
155                 logger.trace("setResponse(): ntfOrder={}.", ntfOrder);
156                 int ntfPlacement = responseData.getOneByteValue(3);
157                 logger.trace("setResponse(): ntfPlacement={}.", ntfPlacement);
158                 String ntfName = responseData.getString(4, 64);
159                 logger.trace("setResponse(): ntfName={}.", ntfName);
160                 int ntfVelocity = responseData.getOneByteValue(68);
161                 logger.trace("setResponse(): ntfVelocity={}.", ntfVelocity);
162                 int ntfNodeTypeSubType = responseData.getTwoByteValue(69);
163                 logger.trace("setResponse(): ntfNodeTypeSubType={} ({}).", ntfNodeTypeSubType,
164                         VeluxProductType.get(ntfNodeTypeSubType));
165                 logger.trace("setResponse(): derived product description={}.",
166                         VeluxProductType.toString(ntfNodeTypeSubType));
167                 int ntfProductGroup = responseData.getOneByteValue(71);
168                 logger.trace("setResponse(): ntfProductGroup={}.", ntfProductGroup);
169                 int ntfProductType = responseData.getOneByteValue(72);
170                 logger.trace("setResponse(): ntfProductType={}.", ntfProductType);
171                 int ntfNodeVariation = responseData.getOneByteValue(73);
172                 logger.trace("setResponse(): ntfNodeVariation={}.", ntfNodeVariation);
173                 int ntfPowerMode = responseData.getOneByteValue(74);
174                 logger.trace("setResponse(): ntfPowerMode={}.", ntfPowerMode);
175                 int ntfBuildNumber = responseData.getOneByteValue(75);
176                 logger.trace("setResponse(): ntfBuildNumber={}.", ntfBuildNumber);
177                 byte[] ntfSerialNumber = responseData.getByteArray(76, 8);
178                 logger.trace("setResponse(): ntfSerialNumber={}.", ntfSerialNumber);
179                 int ntfState = responseData.getOneByteValue(84);
180                 logger.trace("setResponse(): ntfState={}.", ntfState);
181                 int ntfCurrentPosition = responseData.getTwoByteValue(85);
182                 logger.trace("setResponse(): ntfCurrentPosition={}.", ntfCurrentPosition);
183                 int ntfTarget = responseData.getTwoByteValue(87);
184                 logger.trace("setResponse(): ntfTarget={}.", ntfTarget);
185                 int ntfFP1CurrentPosition = responseData.getTwoByteValue(89);
186                 logger.trace("setResponse(): ntfFP1CurrentPosition={}.", ntfFP1CurrentPosition);
187                 int ntfFP2CurrentPosition = responseData.getTwoByteValue(91);
188                 logger.trace("setResponse(): ntfFP2CurrentPosition={}.", ntfFP2CurrentPosition);
189                 int ntfFP3CurrentPosition = responseData.getTwoByteValue(93);
190                 logger.trace("setResponse(): ntfFP3CurrentPosition={}.", ntfFP3CurrentPosition);
191                 int ntfFP4CurrentPosition = responseData.getTwoByteValue(95);
192                 logger.trace("setResponse(): ntfFP4CurrentPosition={}.", ntfFP4CurrentPosition);
193                 int ntfRemainingTime = responseData.getTwoByteValue(97);
194                 logger.trace("setResponse(): ntfRemainingTime={}.", ntfRemainingTime);
195                 int ntfTimeStamp = responseData.getFourByteValue(99);
196                 logger.trace("setResponse(): ntfTimeStamp={}.", ntfTimeStamp);
197                 int ntfNbrOfAlias = responseData.getOneByteValue(103);
198                 logger.trace("setResponse(): ntfNbrOfAlias={}.", ntfNbrOfAlias);
199                 int ntfAliasOne = responseData.getFourByteValue(104);
200                 logger.trace("setResponse(): ntfAliasOne={}.", ntfAliasOne);
201                 int ntfAliasTwo = responseData.getFourByteValue(108);
202                 logger.trace("setResponse(): ntfAliasTwo={}.", ntfAliasTwo);
203                 int ntfAliasThree = responseData.getFourByteValue(112);
204                 logger.trace("setResponse(): ntfAliasThree={}.", ntfAliasThree);
205                 int ntfAliasFour = responseData.getFourByteValue(116);
206                 logger.trace("setResponse(): ntfAliasFour={}.", ntfAliasFour);
207                 int ntfAliasFive = responseData.getFourByteValue(120);
208                 logger.trace("setResponse(): ntfAliasFive={}.", ntfAliasFive);
209
210                 if ((ntfName.length() == 0) || ntfName.startsWith("_")) {
211                     ntfName = "#".concat(String.valueOf(ntfNodeID));
212                     logger.debug("setResponse(): device provided invalid name, using '{}' instead.", ntfName);
213                 }
214
215                 String commonSerialNumber = VeluxProductSerialNo.toString(ntfSerialNumber);
216                 if (VeluxProductSerialNo.isInvalid(ntfSerialNumber)) {
217                     commonSerialNumber = new String(ntfName);
218                     logger.debug("setResponse(): device provided invalid serial number, using name '{}' instead.",
219                             commonSerialNumber);
220                 }
221
222                 VeluxProduct product = new VeluxProduct(new VeluxProductName(ntfName),
223                         VeluxProductType.get(ntfNodeTypeSubType), new ProductBridgeIndex(ntfNodeID), ntfOrder,
224                         ntfPlacement, ntfVelocity, ntfNodeVariation, ntfPowerMode, commonSerialNumber, ntfState,
225                         ntfCurrentPosition, ntfTarget, ntfRemainingTime, ntfTimeStamp);
226                 if (nextProductArrayItem < totalNumberOfProducts) {
227                     productArray[nextProductArrayItem++] = product;
228                 } else {
229                     logger.warn("setResponse(): expected {} products, received one more, ignoring it.",
230                             totalNumberOfProducts);
231                 }
232                 success = true;
233                 break;
234
235             case GW_GET_ALL_NODES_INFORMATION_FINISHED_NTF:
236                 logger.trace("setResponse(): got GW_GET_ALL_NODES_INFORMATION_FINISHED_NTF.");
237                 logger.debug("setResponse(): finished-packet received.");
238                 success = true;
239                 finished = true;
240                 break;
241
242             default:
243                 KLF200Response.errorLogging(logger, responseCommand);
244                 finished = true;
245         }
246         KLF200Response.outroLogging(logger, success, finished);
247     }
248
249     @Override
250     public boolean isCommunicationFinished() {
251         return finished;
252     }
253
254     @Override
255     public boolean isCommunicationSuccessful() {
256         return success;
257     }
258
259     /*
260      * ===========================================================
261      * Methods in addition to the interface {@link BridgeCommunicationProtocol}
262      * and the abstract class {@link GetProducts}
263      */
264
265     @Override
266     public VeluxProduct[] getProducts() {
267         if (success && finished) {
268             logger.trace("getProducts(): returning array of {} products.", productArray.length);
269             return productArray;
270         } else {
271             logger.trace("getProducts(): returning null.");
272             return new VeluxProduct[0];
273         }
274     }
275 }