2 * Copyright (c) 2010-2020 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.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;
22 * A base class for handling a message with the Visonic alarm system
24 * @author Laurent Garnier - Initial contribution
26 public class PowermaxBaseMessage {
28 private final Logger logger = LoggerFactory.getLogger(PowermaxBaseMessage.class);
30 private byte[] rawData;
32 private PowermaxSendType sendType;
33 private PowermaxReceiveType receiveType;
34 private Object messageType;
39 * @param message the message as a buffer of bytes
41 public PowermaxBaseMessage(byte[] message) {
43 this.messageType = "UNKNOWN";
44 decodeMessage(message);
50 * @param sendType the type of a message to be sent
52 public PowermaxBaseMessage(PowermaxSendType sendType) {
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
62 public PowermaxBaseMessage(PowermaxSendType sendType, byte[] param) {
63 this.sendType = sendType;
64 this.messageType = "UNKNOWN";
65 byte[] message = new byte[sendType.getMessage().length + 3];
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()];
73 message[index++] = sendType.getMessage()[i];
76 message[index++] = 0x00;
77 message[index++] = 0x0A;
78 decodeMessage(message);
82 * Extract information from the buffer of bytes and set class attributes
84 * @param data the message as a buffer of bytes
86 private void decodeMessage(byte[] data) {
88 code = rawData[1] & 0x000000FF;
90 receiveType = PowermaxReceiveType.fromCode((byte) code);
91 } catch (IllegalArgumentException e) {
95 messageType = sendType != null ? sendType : receiveType != null ? receiveType : "UNKNOWN";
99 * Work to be done when receiving a message from the Visonic alarm system
101 * @return a new state containing all changes driven by the message
103 public final PowermaxState handleMessage(PowermaxCommManager commManager) {
104 // Send an ACK if needed
105 if (isAckRequired() && commManager != null) {
106 commManager.sendAck(this, (byte) 0x02);
109 if (logger.isDebugEnabled()) {
110 logger.debug("{}message will be handled by class {}:", (receiveType == null) ? "Unsupported " : "",
111 this.getClass().getSimpleName());
113 debug("Raw data", rawData);
114 debug("Message type", code, messageType.toString());
117 PowermaxState newState = handleMessageInternal(commManager);
122 protected PowermaxState handleMessageInternal(PowermaxCommManager commManager) {
127 * @return the raw data of the message (buffer of bytes)
129 public byte[] getRawData() {
134 * @return the identifying code of the message (second byte in the buffer)
136 public int getCode() {
141 * @return the type of the message to be sent
143 public PowermaxSendType getSendType() {
147 public void setSendType(PowermaxSendType sendType) {
148 this.sendType = sendType;
152 * @return the type of the received message
154 public PowermaxReceiveType getReceiveType() {
159 * @return true if the received message requires the sending of an ACK
161 public boolean isAckRequired() {
162 return receiveType == null || receiveType.isAckRequired();
167 public void debug(String name, String info, @Nullable String decoded) {
168 if (!logger.isDebugEnabled()) {
172 String decodedStr = "";
174 if (decoded != null && !decoded.isBlank()) {
175 decodedStr = " - " + decoded;
178 logger.debug("| {} = {}{}", name, info, decodedStr);
181 public void debug(String name, String info) {
182 debug(name, info, null);
185 public void debug(String name, byte[] data, @Nullable String decoded) {
186 String hex = "0x" + HexUtils.bytesToHex(data);
187 debug(name, hex, decoded);
190 public void debug(String name, byte[] data) {
191 debug(name, data, null);
194 public void debug(String name, int data, @Nullable String decoded) {
195 String hex = String.format("0x%02X", data);
196 debug(name, hex, decoded);
199 public void debug(String name, int data) {
200 debug(name, data, null);
204 * Instantiate a class for handling a received message The class depends on the message.
206 * @param message the received message as a buffer of bytes
208 * @return a new class instance
210 public static PowermaxBaseMessage getMessageHandler(byte[] message) {
211 PowermaxBaseMessage msgHandler;
213 PowermaxReceiveType msgType = PowermaxReceiveType.fromCode(message[1]);
216 msgHandler = new PowermaxAckMessage(message);
219 msgHandler = new PowermaxTimeoutMessage(message);
222 msgHandler = new PowermaxDeniedMessage(message);
225 msgHandler = new PowermaxDownloadRetryMessage(message);
229 msgHandler = new PowermaxSettingsMessage(message);
232 msgHandler = new PowermaxInfoMessage(message);
235 msgHandler = new PowermaxEventLogMessage(message);
238 msgHandler = new PowermaxZonesNameMessage(message);
241 msgHandler = new PowermaxStatusMessage(message);
244 msgHandler = new PowermaxZonesTypeMessage(message);
247 msgHandler = new PowermaxPanelMessage(message);
250 msgHandler = new PowermaxPowerlinkMessage(message);
253 msgHandler = new PowermaxPowerMasterMessage(message);
256 msgHandler = new PowermaxBaseMessage(message);
259 } catch (IllegalArgumentException e) {
260 msgHandler = new PowermaxBaseMessage(message);