]> git.basschouten.com Git - openhab-addons.git/blob
f097fdd3798894cf4676a027ea1b0482d1ff6310
[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.GetProduct;
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 Product</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 #setProductId(int)} to define the one specific product.</LI>
45  * <LI>{@link #getProduct} to retrieve one specific product.</LI>
46  * </UL>
47  *
48  * @see GetProduct
49  * @see SlipBridgeCommunicationProtocol
50  *
51  * @author Guenther Schreiner - Initial contribution.
52  */
53 @NonNullByDefault
54 public class SCgetProduct extends GetProduct implements SlipBridgeCommunicationProtocol {
55     private final Logger logger = LoggerFactory.getLogger(SCgetProduct.class);
56
57     private static final String DESCRIPTION = "Retrieve Product";
58     private static final Command COMMAND = Command.GW_GET_NODE_INFORMATION_REQ;
59
60     /*
61      * ===========================================================
62      * Message Content Parameters
63      */
64
65     private int reqNodeID;
66
67     /*
68      * ===========================================================
69      * Message Objects
70      */
71
72     private byte[] requestData = new byte[0];
73
74     /*
75      * ===========================================================
76      * Result Objects
77      */
78
79     private boolean success = false;
80     private boolean finished = false;
81
82     private VeluxProduct product = VeluxProduct.UNKNOWN;
83
84     /*
85      * ===========================================================
86      * Methods required for interface {@link BridgeCommunicationProtocol}.
87      */
88
89     @Override
90     public String name() {
91         return DESCRIPTION;
92     }
93
94     @Override
95     public CommandNumber getRequestCommand() {
96         success = false;
97         finished = false;
98         logger.debug("getRequestCommand() returns {} ({}).", COMMAND.name(), COMMAND.getCommand());
99         return COMMAND.getCommand();
100     }
101
102     @Override
103     public byte[] getRequestDataAsArrayOfBytes() {
104         logger.trace("getRequestDataAsArrayOfBytes() returns data for retrieving node with id {}.", reqNodeID);
105         Packet request = new Packet(new byte[1]);
106         request.setOneByteValue(0, reqNodeID);
107         requestData = request.toByteArray();
108         return requestData;
109     }
110
111     @Override
112     public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
113         KLF200Response.introLogging(logger, responseCommand, thisResponseData);
114         success = false;
115         finished = false;
116         Packet responseData = new Packet(thisResponseData);
117         switch (Command.get(responseCommand)) {
118             case GW_GET_NODE_INFORMATION_CFM:
119                 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 2)) {
120                     finished = true;
121                     break;
122                 }
123                 int cfmStatus = responseData.getOneByteValue(0);
124                 int cfmNodeID = responseData.getOneByteValue(1);
125                 switch (cfmStatus) {
126                     case 0:
127                         logger.trace("setResponse(): returned status: OK - Request accepted.");
128                         if (!KLF200Response.check4matchingNodeID(logger, reqNodeID, cfmNodeID)) {
129                             finished = true;
130                         }
131                         break;
132                     case 1:
133                         finished = true;
134                         logger.trace("setResponse(): returned status: Error – Request rejected.");
135                         break;
136                     case 2:
137                         finished = true;
138                         logger.trace("setResponse(): returned status: Error – Invalid node index.");
139                         break;
140                     default:
141                         finished = true;
142                         logger.warn("setResponse({}): returned status={} (Reserved/unknown).",
143                                 Command.get(responseCommand).toString(), cfmStatus);
144                         break;
145                 }
146                 break;
147
148             case GW_GET_NODE_INFORMATION_NTF:
149                 finished = true;
150                 if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 124)) {
151                     break;
152                 }
153                 // Extracting information items
154                 int ntfNodeID = responseData.getOneByteValue(0);
155                 int ntfOrder = responseData.getTwoByteValue(1);
156                 int ntfPlacement = responseData.getOneByteValue(3);
157                 String ntfName = responseData.getString(4, 64);
158                 int ntfVelocity = responseData.getOneByteValue(68);
159                 int ntfNodeTypeSubType = responseData.getTwoByteValue(69);
160                 int ntfProductGroup = responseData.getTwoByteValue(71);
161                 int ntfProductType = responseData.getOneByteValue(72);
162                 int ntfNodeVariation = responseData.getOneByteValue(73);
163                 int ntfPowerMode = responseData.getOneByteValue(74);
164                 int ntfBuildNumber = responseData.getOneByteValue(75);
165                 byte[] ntfSerialNumber = responseData.getByteArray(76, 8);
166                 int ntfState = responseData.getOneByteValue(84);
167                 int ntfCurrentPosition = responseData.getTwoByteValue(85);
168                 int ntfTarget = responseData.getTwoByteValue(87);
169                 FunctionalParameters ntfFunctionalParameters = FunctionalParameters.readArray(responseData, 89);
170                 int ntfRemainingTime = responseData.getFourByteValue(97);
171                 int ntfTimeStamp = responseData.getFourByteValue(99);
172                 int ntfNbrOfAlias = responseData.getOneByteValue(103);
173                 int ntfAliasOne = responseData.getFourByteValue(104);
174                 int ntfAliasTwo = responseData.getFourByteValue(108);
175                 int ntfAliasThree = responseData.getFourByteValue(112);
176                 int ntfAliasFour = responseData.getFourByteValue(116);
177                 int ntfAliasFive = responseData.getFourByteValue(120);
178
179                 if (logger.isTraceEnabled()) {
180                     logger.trace("setResponse(): ntfNodeID={}.", ntfNodeID);
181                     logger.trace("setResponse(): ntfOrder={}.", ntfOrder);
182                     logger.trace("setResponse(): ntfPlacement={}.", ntfPlacement);
183                     logger.trace("setResponse(): ntfName={}.", ntfName);
184                     logger.trace("setResponse(): ntfVelocity={}.", ntfVelocity);
185                     logger.trace("setResponse(): ntfNodeTypeSubType={} ({}).", ntfNodeTypeSubType,
186                             VeluxProductType.get(ntfNodeTypeSubType));
187                     logger.trace("setResponse(): derived product description={}.",
188                             VeluxProductType.toString(ntfNodeTypeSubType));
189                     logger.trace("setResponse(): ntfProductGroup={}.", ntfProductGroup);
190                     logger.trace("setResponse(): ntfProductType={}.", ntfProductType);
191                     logger.trace("setResponse(): ntfNodeVariation={}.", ntfNodeVariation);
192                     logger.trace("setResponse(): ntfPowerMode={}.", ntfPowerMode);
193                     logger.trace("setResponse(): ntfBuildNumber={}.", ntfBuildNumber);
194                     logger.trace("setResponse(): ntfSerialNumber={}.", VeluxProductSerialNo.toString(ntfSerialNumber));
195                     logger.trace("setResponse(): ntfState={}.", ntfState);
196                     logger.trace("setResponse(): ntfCurrentPosition={}.", String.format("0x%04X", ntfCurrentPosition));
197                     logger.trace("setResponse(): ntfTarget={}.", String.format("0x%04X", ntfTarget));
198                     logger.trace("setResponse(): ntfFunctionalParameters={} (returns null).", ntfFunctionalParameters);
199                     logger.trace("setResponse(): ntfRemainingTime={}.", ntfRemainingTime);
200                     logger.trace("setResponse(): ntfTimeStamp={}.", ntfTimeStamp);
201                     logger.trace("setResponse(): ntfNbrOfAlias={}.", ntfNbrOfAlias);
202                     logger.trace("setResponse(): ntfAliasOne={}.", ntfAliasOne);
203                     logger.trace("setResponse(): ntfAliasTwo={}.", ntfAliasTwo);
204                     logger.trace("setResponse(): ntfAliasThree={}.", ntfAliasThree);
205                     logger.trace("setResponse(): ntfAliasFour={}.", ntfAliasFour);
206                     logger.trace("setResponse(): ntfAliasFive={}.", ntfAliasFive);
207                 }
208
209                 if (!KLF200Response.check4matchingNodeID(logger, reqNodeID, ntfNodeID)) {
210                     break;
211                 }
212
213                 if ((ntfName.length() == 0) || ntfName.startsWith("_")) {
214                     ntfName = "#".concat(String.valueOf(ntfNodeID));
215                     logger.debug("setResponse(): device provided invalid name, using '{}' instead.", ntfName);
216                 }
217
218                 String ntfSerialNumberString = VeluxProductSerialNo.toString(ntfSerialNumber);
219                 if (VeluxProductSerialNo.isInvalid(ntfSerialNumber)) {
220                     ntfSerialNumberString = new String(ntfName);
221                     logger.debug("setResponse(): device provided invalid serial number, using name '{}' instead.",
222                             ntfSerialNumberString);
223                 }
224
225                 // this BCP returns wrong functional parameters on some (e.g. Somfy) devices so return null instead
226                 ntfFunctionalParameters = null;
227
228                 // create notification product with the returned values
229                 product = new VeluxProduct(new VeluxProductName(ntfName), VeluxProductType.get(ntfNodeTypeSubType),
230                         ActuatorType.get(ntfNodeTypeSubType), new ProductBridgeIndex(ntfNodeID), ntfOrder, ntfPlacement,
231                         ntfVelocity, ntfNodeVariation, ntfPowerMode, ntfSerialNumberString, ntfState,
232                         ntfCurrentPosition, ntfTarget, ntfFunctionalParameters, ntfRemainingTime, ntfTimeStamp,
233                         COMMAND);
234
235                 success = true;
236                 break;
237
238             default:
239                 KLF200Response.errorLogging(logger, responseCommand);
240         }
241         KLF200Response.outroLogging(logger, success, finished);
242     }
243
244     @Override
245     public boolean isCommunicationFinished() {
246         return finished;
247     }
248
249     @Override
250     public boolean isCommunicationSuccessful() {
251         return success;
252     }
253
254     /*
255      * ===========================================================
256      * Methods in addition to the interface {@link BridgeCommunicationProtocol}
257      * and the abstract class {@link GetProduct}
258      */
259
260     @Override
261     public void setProductId(int nodeId) {
262         logger.trace("setProductId({}) called.", nodeId);
263         reqNodeID = nodeId;
264     }
265
266     @Override
267     public VeluxProduct getProduct() {
268         logger.trace("getProduct(): returning {}.", product);
269         return product;
270     }
271 }