2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.powermax.internal.message;
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;
23 * A base class for handling a message with the Visonic alarm system
25 * @author Laurent Garnier - Initial contribution
28 public class PowermaxBaseMessage {
30 private final Logger logger = LoggerFactory.getLogger(PowermaxBaseMessage.class);
32 private final byte[] rawData;
34 private @Nullable PowermaxSendType sendType;
35 private @Nullable PowermaxReceiveType receiveType;
36 private Object messageType;
41 * @param message the message as a buffer of bytes
43 public PowermaxBaseMessage(byte[] message) {
44 this.rawData = message;
45 this.messageType = "UNKNOWN";
52 * @param sendType the type of a message to be sent
54 public PowermaxBaseMessage(PowermaxSendType sendType) {
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
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];
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];
76 rawData[index++] = sendType.getMessage()[i];
79 rawData[index++] = 0x00;
80 rawData[index++] = 0x0A;
85 * Extract information from the buffer of bytes and set class attributes
87 private void decodeMessage() {
88 code = rawData[1] & 0x000000FF;
89 PowermaxReceiveType localReceiveType;
91 localReceiveType = PowermaxReceiveType.fromCode((byte) code);
92 } catch (IllegalArgumentException e) {
93 localReceiveType = null;
95 receiveType = localReceiveType;
97 PowermaxSendType localSendType = sendType;
98 messageType = localSendType != null ? localSendType : localReceiveType != null ? localReceiveType : "UNKNOWN";
102 * Work to be done when receiving a message from the Visonic alarm system
104 * @return a new state containing all changes driven by the message
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);
112 if (logger.isDebugEnabled()) {
113 logger.debug("{}message will be handled by class {}:", (receiveType == null) ? "Unsupported " : "",
114 this.getClass().getSimpleName());
116 debug("Raw data", rawData);
117 debug("Message type", code, messageType.toString());
120 PowermaxState newState = handleMessageInternal(commManager);
125 protected @Nullable PowermaxState handleMessageInternal(@Nullable PowermaxCommManager commManager) {
130 * @return the raw data of the message (buffer of bytes)
132 public byte[] getRawData() {
137 * @return the identifying code of the message (second byte in the buffer)
139 public int getCode() {
144 * @return the type of the message to be sent
146 public @Nullable PowermaxSendType getSendType() {
150 public void setSendType(@Nullable PowermaxSendType sendType) {
151 this.sendType = sendType;
155 * @return the type of the received message
157 public @Nullable PowermaxReceiveType getReceiveType() {
162 * @return true if the received message requires the sending of an ACK
164 public boolean isAckRequired() {
165 PowermaxReceiveType localReceiveType = receiveType;
166 return localReceiveType == null || localReceiveType.isAckRequired();
171 public void debug(String name, String info, @Nullable String decoded) {
172 if (!logger.isDebugEnabled()) {
176 String decodedStr = "";
178 if (decoded != null && !decoded.isBlank()) {
179 decodedStr = " - " + decoded;
182 logger.debug("| {} = {}{}", name, info, decodedStr);
185 public void debug(String name, String info) {
186 debug(name, info, null);
189 public void debug(String name, byte[] data, @Nullable String decoded) {
190 String hex = "0x" + HexUtils.bytesToHex(data);
191 debug(name, hex, decoded);
194 public void debug(String name, byte[] data) {
195 debug(name, data, null);
198 public void debug(String name, int data, @Nullable String decoded) {
199 String hex = String.format("0x%02X", data);
200 debug(name, hex, decoded);
203 public void debug(String name, int data) {
204 debug(name, data, null);
208 * Instantiate a class for handling a received message The class depends on the message.
210 * @param message the received message as a buffer of bytes
212 * @return a new class instance
214 public static PowermaxBaseMessage getMessageHandler(byte[] message) {
215 PowermaxBaseMessage msgHandler;
217 PowermaxReceiveType msgType = PowermaxReceiveType.fromCode(message[1]);
220 msgHandler = new PowermaxAckMessage(message);
223 msgHandler = new PowermaxTimeoutMessage(message);
226 msgHandler = new PowermaxDeniedMessage(message);
229 msgHandler = new PowermaxDownloadRetryMessage(message);
233 msgHandler = new PowermaxSettingsMessage(message);
236 msgHandler = new PowermaxInfoMessage(message);
239 msgHandler = new PowermaxEventLogMessage(message);
242 msgHandler = new PowermaxZonesNameMessage(message);
245 msgHandler = new PowermaxStatusMessage(message);
248 msgHandler = new PowermaxZonesTypeMessage(message);
251 msgHandler = new PowermaxPanelMessage(message);
254 msgHandler = new PowermaxPowerlinkMessage(message);
257 msgHandler = new PowermaxPowerMasterMessage(message);
260 msgHandler = new PowermaxBaseMessage(message);
263 } catch (IllegalArgumentException e) {
264 msgHandler = new PowermaxBaseMessage(message);