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