]> git.basschouten.com Git - openhab-addons.git/blob
d30bf0951e309abb462375e19c5e64410cac5edd
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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 java.math.BigInteger;
16 import java.util.ArrayList;
17 import java.util.List;
18
19 import org.openhab.binding.powermax.internal.state.PowermaxArmMode;
20 import org.openhab.binding.powermax.internal.state.PowermaxPanelSettings;
21 import org.openhab.binding.powermax.internal.state.PowermaxState;
22 import org.openhab.binding.powermax.internal.state.PowermaxZoneSettings;
23
24 /**
25  * A class for STATUS message handling
26  *
27  * @author Laurent Garnier - Initial contribution
28  */
29 public class PowermaxStatusMessage extends PowermaxBaseMessage {
30
31     private static byte[] zoneBytes(byte zones1, byte zones9, byte zones17, byte zones25) {
32         return new byte[] { zones25, zones17, zones9, zones1 };
33     }
34
35     private static boolean[] zoneBits(byte[] zoneBytes) {
36         boolean[] zones = new boolean[32];
37         char[] binary = new BigInteger(zoneBytes).toString(2).toCharArray();
38         int len = binary.length - 1;
39
40         for (int i = len; i >= 0; i--) {
41             zones[len - i + 1] = (binary[i] == '1');
42         }
43
44         return zones;
45     }
46
47     private static String zoneList(byte[] zoneBytes) {
48         boolean[] zones = zoneBits(zoneBytes);
49         List<String> names = new ArrayList<>();
50
51         for (int i = 1; i < zones.length; i++) {
52             if (zones[i]) {
53                 names.add(String.format("Zone %d", i));
54             }
55         }
56
57         return String.join(", ", names);
58     }
59
60     /**
61      * Constructor
62      *
63      * @param message
64      *            the received message as a buffer of bytes
65      */
66     public PowermaxStatusMessage(byte[] message) {
67         super(message);
68     }
69
70     @Override
71     protected PowermaxState handleMessageInternal(PowermaxCommManager commManager) {
72         if (commManager == null) {
73             return null;
74         }
75
76         PowermaxPanelSettings panelSettings = commManager.getPanelSettings();
77         PowermaxState updatedState = commManager.createNewState();
78
79         byte[] message = getRawData();
80         byte eventType = message[3];
81         String eventTypeStr = PowermaxMessageConstants.getMessageTypeString(eventType & 0x000000FF);
82
83         debug("Event type", eventType, eventTypeStr);
84
85         if (eventType == 0x02) {
86             byte[] zoneStatusBytes = zoneBytes(message[4], message[5], message[6], message[7]);
87             byte[] batteryStatusBytes = zoneBytes(message[8], message[9], message[10], message[11]);
88
89             boolean[] zoneStatus = zoneBits(zoneStatusBytes);
90             boolean[] batteryStatus = zoneBits(batteryStatusBytes);
91
92             String zoneStatusStr = zoneList(zoneStatusBytes);
93             String batteryStatusStr = zoneList(batteryStatusBytes);
94
95             for (int i = 1; i <= panelSettings.getNbZones(); i++) {
96                 updatedState.getZone(i).tripped.setValue(zoneStatus[i]);
97                 updatedState.getZone(i).lowBattery.setValue(batteryStatus[i]);
98             }
99
100             debug("Zone status", zoneStatusBytes, zoneStatusStr);
101             debug("Battery status", batteryStatusBytes, batteryStatusStr);
102         } else if (eventType == 0x04) {
103             byte sysStatus = message[4];
104             byte sysFlags = message[5];
105             byte eventZone = message[6];
106             byte zoneEType = message[7];
107             int x10Status = (message[10] & 0x000000FF) | ((message[11] << 8) & 0x0000FF00);
108
109             String eventZoneStr = PowermaxMessageConstants.getZoneOrUserString(eventZone & 0x000000FF);
110             String zoneETypeStr = PowermaxMessageConstants.getZoneEventString(zoneEType & 0x000000FF);
111
112             if (zoneEType == 0x03) {
113                 updatedState.getZone(eventZone).tripped.setValue(true);
114                 updatedState.getZone(eventZone).lastTripped.setValue(System.currentTimeMillis());
115             } else if (zoneEType == 0x04) {
116                 updatedState.getZone(eventZone).tripped.setValue(false);
117             } else if (zoneEType == 0x05) {
118                 PowermaxZoneSettings zone = panelSettings.getZoneSettings(eventZone);
119                 if ((zone != null) && zone.getSensorType().equalsIgnoreCase("unknown")) {
120                     zone.setSensorType("Motion");
121                 }
122                 updatedState.getZone(eventZone).tripped.setValue(true);
123                 updatedState.getZone(eventZone).lastTripped.setValue(System.currentTimeMillis());
124             }
125
126             // PGM & X10 devices
127             for (int i = 0; i < panelSettings.getNbPGMX10Devices(); i++) {
128                 updatedState.setPGMX10DeviceStatus(i, ((x10Status >> i) & 0x1) > 0);
129             }
130
131             String sysStatusStr = "";
132             if ((sysFlags & 0x1) == 1) {
133                 sysStatusStr = sysStatusStr + "Ready, ";
134                 updatedState.ready.setValue(true);
135             } else {
136                 sysStatusStr = sysStatusStr + "Not ready, ";
137                 updatedState.ready.setValue(false);
138             }
139             if (((sysFlags >> 1) & 0x1) == 1) {
140                 sysStatusStr = sysStatusStr + "Alert in memory, ";
141                 updatedState.alertInMemory.setValue(true);
142             } else {
143                 updatedState.alertInMemory.setValue(false);
144             }
145             if (((sysFlags >> 2) & 0x1) == 1) {
146                 sysStatusStr = sysStatusStr + "Trouble, ";
147                 updatedState.trouble.setValue(true);
148             } else {
149                 updatedState.trouble.setValue(false);
150             }
151             if (((sysFlags >> 3) & 0x1) == 1) {
152                 sysStatusStr = sysStatusStr + "Bypass on, ";
153                 updatedState.bypass.setValue(true);
154             } else {
155                 updatedState.bypass.setValue(false);
156                 for (int i = 1; i <= panelSettings.getNbZones(); i++) {
157                     updatedState.getZone(i).bypassed.setValue(false);
158                 }
159             }
160             if (((sysFlags >> 4) & 0x1) == 1) {
161                 sysStatusStr = sysStatusStr + "Last 10 seconds, ";
162             }
163             if (((sysFlags >> 5) & 0x1) == 1) {
164                 sysStatusStr = sysStatusStr + zoneETypeStr;
165                 if (eventZone == 0xFF) {
166                     sysStatusStr = sysStatusStr + " from Panel, ";
167                 } else if (eventZone > 0) {
168                     sysStatusStr = sysStatusStr + String.format(" in Zone %d, ", eventZone);
169                 } else {
170                     sysStatusStr = sysStatusStr + ", ";
171                 }
172             }
173             if (((sysFlags >> 6) & 0x1) == 1) {
174                 sysStatusStr = sysStatusStr + "Status changed, ";
175             }
176             if (((sysFlags >> 7) & 0x1) == 1) {
177                 sysStatusStr = sysStatusStr + "Alarm event, ";
178                 updatedState.alarmActive.setValue(true);
179             } else {
180                 updatedState.alarmActive.setValue(false);
181             }
182             sysStatusStr = sysStatusStr.substring(0, sysStatusStr.length() - 2);
183             String statusStr;
184             try {
185                 PowermaxArmMode armMode = PowermaxArmMode.fromCode(sysStatus & 0x000000FF);
186                 statusStr = armMode.getName();
187             } catch (IllegalArgumentException e) {
188                 statusStr = "UNKNOWN";
189             }
190             updatedState.armMode.setValue(statusStr);
191             updatedState.statusStr.setValue(statusStr + ", " + sysStatusStr);
192
193             debug("System status", sysStatus, statusStr);
194             debug("System flags", sysFlags, sysStatusStr);
195             debug("Event zone", eventZone, eventZoneStr);
196             debug("Zone event type", zoneEType, zoneETypeStr);
197             debug("X10 status", x10Status);
198
199             for (int i = 1; i <= panelSettings.getNbZones(); i++) {
200                 PowermaxZoneSettings zone = panelSettings.getZoneSettings(i);
201                 if (zone != null) {
202                     // mode: armed or not: 4=armed home; 5=armed away
203                     int mode = sysStatus & 0x0000000F;
204                     // Zone is shown as armed if
205                     // the sensor type always triggers an alarm
206                     // or the system is armed away (mode = 5)
207                     // or the system is armed home (mode = 4) and the zone is not interior(-follow)
208                     boolean armed = (!zone.getType().equalsIgnoreCase("Non-Alarm") && (zone.isAlwaysInAlarm()
209                             || (mode == 0x5) || ((mode == 0x4) && !zone.getType().equalsIgnoreCase("Interior-Follow")
210                                     && !zone.getType().equalsIgnoreCase("Interior"))));
211                     updatedState.getZone(i).armed.setValue(armed);
212                 }
213             }
214         } else if (eventType == 0x06) {
215             byte[] zoneBypassBytes = zoneBytes(message[8], message[9], message[10], message[11]);
216             boolean[] zoneBypass = zoneBits(zoneBypassBytes);
217             String zoneBypassStr = zoneList(zoneBypassBytes);
218
219             for (int i = 1; i <= panelSettings.getNbZones(); i++) {
220                 updatedState.getZone(i).bypassed.setValue(zoneBypass[i]);
221             }
222
223             debug("Zone bypass", zoneBypassBytes, zoneBypassStr);
224         }
225
226         return updatedState;
227     }
228 }