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