]> git.basschouten.com Git - openhab-addons.git/blob
f7ea122b35a2f16e6920ed7a43de42d3d25f0880
[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.powermax.internal.message;
14
15 import org.eclipse.jdt.annotation.NonNullByDefault;
16 import org.eclipse.jdt.annotation.Nullable;
17 import org.openhab.binding.powermax.internal.state.PowermaxState;
18 import org.openhab.core.util.HexUtils;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21
22 /**
23  * A base class for handling a message with the Visonic alarm system
24  *
25  * @author Laurent Garnier - Initial contribution
26  */
27 @NonNullByDefault
28 public class PowermaxBaseMessage {
29
30     private final Logger logger = LoggerFactory.getLogger(PowermaxBaseMessage.class);
31
32     private final byte[] rawData;
33     private int code;
34     private @Nullable PowermaxSendType sendType;
35     private @Nullable PowermaxReceiveType receiveType;
36     private Object messageType;
37
38     /**
39      * Constructor.
40      *
41      * @param message the message as a buffer of bytes
42      */
43     public PowermaxBaseMessage(byte[] message) {
44         this.rawData = message;
45         this.messageType = "UNKNOWN";
46         decodeMessage();
47     }
48
49     /**
50      * Constructor.
51      *
52      * @param sendType the type of a message to be sent
53      */
54     public PowermaxBaseMessage(PowermaxSendType sendType) {
55         this(sendType, null);
56     }
57
58     /**
59      * Constructor.
60      *
61      * @param sendType the type of a message to be sent
62      * @param param the dynamic part of a message to be sent; null if no dynamic part
63      */
64     public PowermaxBaseMessage(PowermaxSendType sendType, byte @Nullable [] param) {
65         this.sendType = sendType;
66         this.messageType = "UNKNOWN";
67         this.rawData = new byte[sendType.getMessage().length + 3];
68         int index = 0;
69         rawData[index++] = 0x0D;
70         for (int i = 0; i < sendType.getMessage().length; i++) {
71             Integer paramPosition = sendType.getParamPosition();
72             if ((param != null) && (paramPosition != null) && (i >= paramPosition)
73                     && (i < (paramPosition + param.length))) {
74                 rawData[index++] = param[i - paramPosition];
75             } else {
76                 rawData[index++] = sendType.getMessage()[i];
77             }
78         }
79         rawData[index++] = 0x00;
80         rawData[index++] = 0x0A;
81         decodeMessage();
82     }
83
84     /**
85      * Extract information from the buffer of bytes and set class attributes
86      */
87     private void decodeMessage() {
88         code = rawData[1] & 0x000000FF;
89         PowermaxReceiveType localReceiveType;
90         try {
91             localReceiveType = PowermaxReceiveType.fromCode((byte) code);
92         } catch (IllegalArgumentException e) {
93             localReceiveType = null;
94         }
95         receiveType = localReceiveType;
96
97         PowermaxSendType localSendType = sendType;
98         messageType = localSendType != null ? localSendType : localReceiveType != null ? localReceiveType : "UNKNOWN";
99     }
100
101     /**
102      * Work to be done when receiving a message from the Visonic alarm system
103      *
104      * @return a new state containing all changes driven by the message
105      */
106     public final @Nullable PowermaxState handleMessage(@Nullable PowermaxCommManager commManager) {
107         // Send an ACK if needed
108         if (isAckRequired() && commManager != null) {
109             commManager.sendAck(this, (byte) 0x02);
110         }
111
112         if (logger.isDebugEnabled()) {
113             logger.debug("{}message will be handled by class {}:", (receiveType == null) ? "Unsupported " : "",
114                     this.getClass().getSimpleName());
115
116             debug("Raw data", rawData);
117             debug("Message type", code, messageType.toString());
118         }
119
120         PowermaxState newState = handleMessageInternal(commManager);
121
122         return newState;
123     }
124
125     protected @Nullable PowermaxState handleMessageInternal(@Nullable PowermaxCommManager commManager) {
126         return null;
127     }
128
129     /**
130      * @return the raw data of the message (buffer of bytes)
131      */
132     public byte[] getRawData() {
133         return rawData;
134     }
135
136     /**
137      * @return the identifying code of the message (second byte in the buffer)
138      */
139     public int getCode() {
140         return code;
141     }
142
143     /**
144      * @return the type of the message to be sent
145      */
146     public @Nullable PowermaxSendType getSendType() {
147         return sendType;
148     }
149
150     public void setSendType(@Nullable PowermaxSendType sendType) {
151         this.sendType = sendType;
152     }
153
154     /**
155      * @return the type of the received message
156      */
157     public @Nullable PowermaxReceiveType getReceiveType() {
158         return receiveType;
159     }
160
161     /**
162      * @return true if the received message requires the sending of an ACK
163      */
164     public boolean isAckRequired() {
165         PowermaxReceiveType localReceiveType = receiveType;
166         return localReceiveType == null || localReceiveType.isAckRequired();
167     }
168
169     // Debugging helpers
170
171     public void debug(String name, String info, @Nullable String decoded) {
172         if (!logger.isDebugEnabled()) {
173             return;
174         }
175
176         String decodedStr = "";
177
178         if (decoded != null && !decoded.isBlank()) {
179             decodedStr = " - " + decoded;
180         }
181
182         logger.debug("| {} = {}{}", name, info, decodedStr);
183     }
184
185     public void debug(String name, String info) {
186         debug(name, info, null);
187     }
188
189     public void debug(String name, byte[] data, @Nullable String decoded) {
190         String hex = "0x" + HexUtils.bytesToHex(data);
191         debug(name, hex, decoded);
192     }
193
194     public void debug(String name, byte[] data) {
195         debug(name, data, null);
196     }
197
198     public void debug(String name, int data, @Nullable String decoded) {
199         String hex = String.format("0x%02X", data);
200         debug(name, hex, decoded);
201     }
202
203     public void debug(String name, int data) {
204         debug(name, data, null);
205     }
206
207     /**
208      * Instantiate a class for handling a received message The class depends on the message.
209      *
210      * @param message the received message as a buffer of bytes
211      *
212      * @return a new class instance
213      */
214     public static PowermaxBaseMessage getMessageHandler(byte[] message) {
215         PowermaxBaseMessage msgHandler;
216         try {
217             PowermaxReceiveType msgType = PowermaxReceiveType.fromCode(message[1]);
218             switch (msgType) {
219                 case ACK:
220                     msgHandler = new PowermaxAckMessage(message);
221                     break;
222                 case TIMEOUT:
223                     msgHandler = new PowermaxTimeoutMessage(message);
224                     break;
225                 case DENIED:
226                     msgHandler = new PowermaxDeniedMessage(message);
227                     break;
228                 case DOWNLOAD_RETRY:
229                     msgHandler = new PowermaxDownloadRetryMessage(message);
230                     break;
231                 case SETTINGS:
232                 case SETTINGS_ITEM:
233                     msgHandler = new PowermaxSettingsMessage(message);
234                     break;
235                 case INFO:
236                     msgHandler = new PowermaxInfoMessage(message);
237                     break;
238                 case EVENT_LOG:
239                     msgHandler = new PowermaxEventLogMessage(message);
240                     break;
241                 case ZONESNAME:
242                     msgHandler = new PowermaxZonesNameMessage(message);
243                     break;
244                 case STATUS:
245                     msgHandler = new PowermaxStatusMessage(message);
246                     break;
247                 case ZONESTYPE:
248                     msgHandler = new PowermaxZonesTypeMessage(message);
249                     break;
250                 case PANEL:
251                     msgHandler = new PowermaxPanelMessage(message);
252                     break;
253                 case POWERLINK:
254                     msgHandler = new PowermaxPowerlinkMessage(message);
255                     break;
256                 case POWERMASTER:
257                     msgHandler = new PowermaxPowerMasterMessage(message);
258                     break;
259                 default:
260                     msgHandler = new PowermaxBaseMessage(message);
261                     break;
262             }
263         } catch (IllegalArgumentException e) {
264             msgHandler = new PowermaxBaseMessage(message);
265         }
266         return msgHandler;
267     }
268 }