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.openhab.binding.powermax.internal.state.PowermaxArmMode;
16 import org.openhab.binding.powermax.internal.state.PowermaxPanelSettings;
17 import org.openhab.binding.powermax.internal.state.PowermaxState;
18 import org.openhab.binding.powermax.internal.state.PowermaxZoneSettings;
21 * A class for STATUS message handling
23 * @author Laurent Garnier - Initial contribution
25 public class PowermaxStatusMessage extends PowermaxBaseMessage {
27 private static final String[] EVENT_TYPE_TABLE = new String[] { "None", "Tamper Alarm", "Tamper Restore", "Open",
28 "Closed", "Violated (Motion)", "Panic Alarm", "RF Jamming", "Tamper Open", "Communication Failure",
29 "Line Failure", "Fuse", "Not Active", "Low Battery", "AC Failure", "Fire Alarm", "Emergency",
30 "Siren Tamper", "Siren Tamper Restore", "Siren Low Battery", "Siren AC Fail" };
36 * the received message as a buffer of bytes
38 public PowermaxStatusMessage(byte[] message) {
43 public PowermaxState handleMessage(PowermaxCommManager commManager) {
44 super.handleMessage(commManager);
46 if (commManager == null) {
50 PowermaxPanelSettings panelSettings = commManager.getPanelSettings();
51 PowermaxState updatedState = commManager.createNewState();
53 byte[] message = getRawData();
54 byte eventType = message[3];
56 if (eventType == 0x02) {
57 int zoneStatus = (message[4] & 0x000000FF) | ((message[5] << 8) & 0x0000FF00)
58 | ((message[6] << 16) & 0x00FF0000) | ((message[7] << 24) & 0xFF000000);
59 int batteryStatus = (message[8] & 0x000000FF) | ((message[9] << 8) & 0x0000FF00)
60 | ((message[10] << 16) & 0x00FF0000) | ((message[11] << 24) & 0xFF000000);
62 for (int i = 1; i <= panelSettings.getNbZones(); i++) {
63 updatedState.setSensorTripped(i, ((zoneStatus >> (i - 1)) & 0x1) > 0);
64 updatedState.setSensorLowBattery(i, ((batteryStatus >> (i - 1)) & 0x1) > 0);
66 } else if (eventType == 0x04) {
67 byte sysStatus = message[4];
68 byte sysFlags = message[5];
69 byte eventZone = message[6];
70 byte zoneEType = message[7];
71 int x10Status = (message[10] & 0x000000FF) | ((message[11] << 8) & 0x0000FF00);
73 String zoneETypeStr = ((zoneEType & 0x000000FF) < EVENT_TYPE_TABLE.length)
74 ? EVENT_TYPE_TABLE[zoneEType & 0x000000FF]
77 if (zoneEType == 0x03) {
78 updatedState.setSensorTripped(eventZone, Boolean.TRUE);
79 updatedState.setSensorLastTripped(eventZone, System.currentTimeMillis());
80 } else if (zoneEType == 0x04) {
81 updatedState.setSensorTripped(eventZone, Boolean.FALSE);
82 } else if (zoneEType == 0x05) {
83 PowermaxZoneSettings zone = panelSettings.getZoneSettings(eventZone);
84 if ((zone != null) && zone.getSensorType().equalsIgnoreCase("unknown")) {
85 zone.setSensorType("Motion");
87 updatedState.setSensorTripped(eventZone, Boolean.TRUE);
88 updatedState.setSensorLastTripped(eventZone, System.currentTimeMillis());
92 for (int i = 0; i < panelSettings.getNbPGMX10Devices(); i++) {
93 updatedState.setPGMX10DeviceStatus(i, ((x10Status >> i) & 0x1) > 0);
96 String sysStatusStr = "";
97 if ((sysFlags & 0x1) == 1) {
98 sysStatusStr = sysStatusStr + "Ready, ";
99 updatedState.setReady(true);
101 sysStatusStr = sysStatusStr + "Not ready, ";
102 updatedState.setReady(false);
104 if (((sysFlags >> 1) & 0x1) == 1) {
105 sysStatusStr = sysStatusStr + "Alert in memory, ";
106 updatedState.setAlertInMemory(true);
108 updatedState.setAlertInMemory(false);
110 if (((sysFlags >> 2) & 0x1) == 1) {
111 sysStatusStr = sysStatusStr + "Trouble, ";
112 updatedState.setTrouble(true);
114 updatedState.setTrouble(false);
116 if (((sysFlags >> 3) & 0x1) == 1) {
117 sysStatusStr = sysStatusStr + "Bypass on, ";
118 updatedState.setBypass(true);
120 updatedState.setBypass(false);
121 for (int i = 1; i <= panelSettings.getNbZones(); i++) {
122 updatedState.setSensorBypassed(i, false);
125 if (((sysFlags >> 4) & 0x1) == 1) {
126 sysStatusStr = sysStatusStr + "Last 10 seconds, ";
128 if (((sysFlags >> 5) & 0x1) == 1) {
129 sysStatusStr = sysStatusStr + zoneETypeStr;
130 if (eventZone == 0xFF) {
131 sysStatusStr = sysStatusStr + " from Panel, ";
132 } else if (eventZone > 0) {
133 sysStatusStr = sysStatusStr + String.format(" in Zone %d, ", eventZone);
135 sysStatusStr = sysStatusStr + ", ";
138 if (((sysFlags >> 6) & 0x1) == 1) {
139 sysStatusStr = sysStatusStr + "Status changed, ";
141 if (((sysFlags >> 7) & 0x1) == 1) {
142 sysStatusStr = sysStatusStr + "Alarm event, ";
143 updatedState.setAlarmActive(true);
145 updatedState.setAlarmActive(false);
147 sysStatusStr = sysStatusStr.substring(0, sysStatusStr.length() - 2);
150 PowermaxArmMode armMode = PowermaxArmMode.fromCode(sysStatus & 0x000000FF);
151 statusStr = armMode.getName();
152 } catch (IllegalArgumentException e) {
153 statusStr = "UNKNOWN";
155 updatedState.setArmMode(statusStr);
156 updatedState.setStatusStr(statusStr + ", " + sysStatusStr);
158 for (int i = 1; i <= panelSettings.getNbZones(); i++) {
159 PowermaxZoneSettings zone = panelSettings.getZoneSettings(i);
161 // mode: armed or not: 4=armed home; 5=armed away
162 int mode = sysStatus & 0x0000000F;
163 // Zone is shown as armed if
164 // the sensor type always triggers an alarm
165 // or the system is armed away (mode = 5)
166 // or the system is armed home (mode = 4) and the zone is not interior(-follow)
167 boolean armed = (!zone.getType().equalsIgnoreCase("Non-Alarm") && (zone.isAlwaysInAlarm()
168 || (mode == 0x5) || ((mode == 0x4) && !zone.getType().equalsIgnoreCase("Interior-Follow")
169 && !zone.getType().equalsIgnoreCase("Interior"))));
170 updatedState.setSensorArmed(i, armed);
173 } else if (eventType == 0x06) {
174 int zoneBypass = (message[8] & 0x000000FF) | ((message[9] << 8) & 0x0000FF00)
175 | ((message[10] << 16) & 0x00FF0000) | ((message[11] << 24) & 0xFF000000);
177 for (int i = 1; i <= panelSettings.getNbZones(); i++) {
178 updatedState.setSensorBypassed(i, ((zoneBypass >> (i - 1)) & 0x1) > 0);
186 public String toString() {
187 String str = super.toString();
189 byte[] message = getRawData();
190 byte eventType = message[3];
192 str += "\n - event type = " + String.format("%02X", eventType);
193 if (eventType == 0x02) {
194 int zoneStatus = (message[4] & 0x000000FF) | ((message[5] << 8) & 0x0000FF00)
195 | ((message[6] << 16) & 0x00FF0000) | ((message[7] << 24) & 0xFF000000);
196 int batteryStatus = (message[8] & 0x000000FF) | ((message[9] << 8) & 0x0000FF00)
197 | ((message[10] << 16) & 0x00FF0000) | ((message[11] << 24) & 0xFF000000);
199 str += "\n - zone status = " + String.format("%08X", zoneStatus);
200 str += "\n - battery status = " + String.format("%08X", batteryStatus);
201 } else if (eventType == 0x04) {
202 byte sysStatus = message[4];
203 byte sysFlags = message[5];
204 byte eventZone = message[6];
205 byte zoneEType = message[7];
206 int x10Status = (message[10] & 0x000000FF) | ((message[11] << 8) & 0x0000FF00);
208 String zoneETypeStr = ((zoneEType & 0x000000FF) < EVENT_TYPE_TABLE.length)
209 ? EVENT_TYPE_TABLE[zoneEType & 0x000000FF]
212 str += "\n - system status = " + String.format("%02X", sysStatus);
213 str += "\n - system flags = " + String.format("%02X", sysFlags);
214 str += "\n - event zone = " + eventZone;
215 str += String.format("\n - zone event type = %02X (%s)", zoneEType, zoneETypeStr);
216 str += "\n - X10 status = " + String.format("%04X", x10Status);
217 } else if (eventType == 0x06) {
218 int zoneBypass = (message[8] & 0x000000FF) | ((message[9] << 8) & 0x0000FF00)
219 | ((message[10] << 16) & 0x00FF0000) | ((message[11] << 24) & 0xFF000000);
221 str += "\n - zone bypass = " + String.format("%08X", zoneBypass);