]> git.basschouten.com Git - openhab-addons.git/blob
01c8027764c37e251f151c41534a23ed59915a75
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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.caddx.internal.handler;
14
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.Set;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.caddx.internal.CaddxBindingConstants;
22 import org.openhab.binding.caddx.internal.CaddxEvent;
23 import org.openhab.binding.caddx.internal.CaddxMessage;
24 import org.openhab.binding.caddx.internal.CaddxMessageContext;
25 import org.openhab.binding.caddx.internal.CaddxMessageType;
26 import org.openhab.binding.caddx.internal.CaddxProperty;
27 import org.openhab.binding.caddx.internal.action.CaddxPanelActions;
28 import org.openhab.core.library.types.OnOffType;
29 import org.openhab.core.library.types.StringType;
30 import org.openhab.core.thing.ChannelUID;
31 import org.openhab.core.thing.Thing;
32 import org.openhab.core.thing.ThingStatus;
33 import org.openhab.core.thing.binding.ThingHandlerService;
34 import org.openhab.core.types.Command;
35 import org.openhab.core.types.RefreshType;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 /**
40  * This is a class for handling a Panel type Thing.
41  *
42  * @author Georgios Moutsos - Initial contribution
43  */
44 @NonNullByDefault
45 public class ThingHandlerPanel extends CaddxBaseThingHandler {
46     private final Logger logger = LoggerFactory.getLogger(ThingHandlerPanel.class);
47     private @Nullable HashMap<String, String> panelLogMessagesMap = null;
48     private @Nullable String communicatorStackPointer = null;
49     private long lastRefreshTime = 0;
50
51     public ThingHandlerPanel(Thing thing) {
52         super(thing, CaddxThingType.PANEL);
53     }
54
55     @Override
56     public void initialize() {
57         super.initialize();
58
59         CaddxBridgeHandler bridgeHandler = getCaddxBridgeHandler();
60         if (bridgeHandler == null) {
61             return;
62         }
63
64         String cmd = CaddxBindingConstants.PANEL_SYSTEM_STATUS_REQUEST;
65         String data = "";
66         bridgeHandler.sendCommand(CaddxMessageContext.COMMAND, cmd, data);
67     }
68
69     @Override
70     public void updateChannel(ChannelUID channelUID, String data) {
71         if (channelUID.getId().equals(CaddxBindingConstants.PANEL_FIRMWARE_VERSION)
72                 || channelUID.getId().startsWith("panel_log_message_")) {
73             updateState(channelUID, new StringType(data));
74         } else {
75             // All Panel channels are OnOffType
76             OnOffType onOffType;
77
78             onOffType = OnOffType.from("true".equals(data));
79             updateState(channelUID, onOffType);
80         }
81     }
82
83     @Override
84     public void handleCommand(ChannelUID channelUID, Command command) {
85         logger.debug("handleCommand(): Command Received - {} {}.", channelUID, command);
86
87         String cmd = null;
88         String data = null;
89         CaddxBridgeHandler bridgeHandler = getCaddxBridgeHandler();
90         if (bridgeHandler == null) {
91             return;
92         }
93
94         if (command instanceof RefreshType) {
95             if (CaddxBindingConstants.PANEL_LOG_MESSAGE_N_0.equals(channelUID.getId())) {
96                 cmd = CaddxBindingConstants.PANEL_SYSTEM_STATUS_REQUEST;
97                 data = "";
98             } else if (System.currentTimeMillis() - lastRefreshTime > 2000) {
99                 // Refresh only if 2 seconds have passed from the last refresh
100                 cmd = CaddxBindingConstants.PANEL_SYSTEM_STATUS_REQUEST;
101                 data = "";
102             } else {
103                 return;
104             }
105
106             bridgeHandler.sendCommand(CaddxMessageContext.COMMAND, cmd, data);
107             lastRefreshTime = System.currentTimeMillis();
108         } else {
109             logger.debug("Unknown command {}", command);
110         }
111     }
112
113     @Override
114     public void caddxEventReceived(CaddxEvent event, Thing thing) {
115         logger.trace("caddxEventReceived(): Event Received - {}.", event);
116
117         if (getThing().equals(thing)) {
118             CaddxMessage message = event.getCaddxMessage();
119             CaddxMessageType mt = message.getCaddxMessageType();
120             ChannelUID channelUID = null;
121
122             for (CaddxProperty p : mt.properties) {
123                 if (!p.getId().isEmpty()) {
124                     String value = message.getPropertyById(p.getId());
125                     channelUID = new ChannelUID(getThing().getUID(), p.getId());
126                     updateChannel(channelUID, value);
127                     logger.trace("Updating panel channel: {}", channelUID.getAsString());
128                 }
129             }
130
131             // Log event messages have special handling
132             if (CaddxMessageType.SYSTEM_STATUS_MESSAGE.equals(mt)) {
133                 handleSystemStatusMessage(message);
134             } else if (CaddxMessageType.LOG_EVENT_MESSAGE.equals(mt)) {
135                 handleLogEventMessage(message);
136             } else if (CaddxMessageType.ZONES_SNAPSHOT_MESSAGE.equals(mt)) {
137                 handleZonesSnapshotMessage(message);
138             }
139
140             updateStatus(ThingStatus.ONLINE);
141         }
142     }
143
144     /*
145      * Gets the pointer into the panel's log messages ring buffer
146      * and sends the command for the retrieval of the last event_message
147      */
148     private void handleSystemStatusMessage(CaddxMessage message) {
149         // Get the bridge handler
150         CaddxBridgeHandler bridgeHandler = getCaddxBridgeHandler();
151         if (bridgeHandler == null) {
152             return;
153         }
154
155         String pointer = message.getPropertyById("panel_communicator_stack_pointer");
156         communicatorStackPointer = pointer;
157
158         // build map of log message channels to event numbers
159         HashMap<String, String> map = new HashMap<String, String>();
160         map.put(pointer, CaddxBindingConstants.PANEL_LOG_MESSAGE_N_0);
161         bridgeHandler.sendCommand(CaddxMessageContext.COMMAND, CaddxBindingConstants.PANEL_LOG_EVENT_REQUEST, pointer);
162         panelLogMessagesMap = map;
163     }
164
165     /*
166      * This function handles the panel log messages.
167      * If the received event_number matches our communication stack pointer then this is the last panel message. The
168      * channel gets updated and the required log message requests are generated for the update of the other log message
169      * channels
170      */
171     private void handleLogEventMessage(CaddxMessage message) {
172         // Get the bridge handler
173         CaddxBridgeHandler bridgeHandler = getCaddxBridgeHandler();
174         if (bridgeHandler == null) {
175             return;
176         }
177
178         String eventNumberString = message.getPropertyById("panel_log_event_number");
179         String eventSizeString = message.getPropertyById("panel_log_event_size");
180
181         // build the message
182         LogEventMessage logEventMessage = new LogEventMessage(message);
183
184         logger.trace("Log_event: {}", logEventMessage);
185
186         // get the channel id from the map
187         HashMap<String, String> logMap = panelLogMessagesMap;
188         if (logMap != null) {
189             String id = logMap.get(eventNumberString);
190             if (id != null) {
191                 ChannelUID channelUID = new ChannelUID(getThing().getUID(), id);
192                 updateChannel(channelUID, logEventMessage.toString());
193             }
194         }
195
196         if (communicatorStackPointer != null && eventNumberString.equals(communicatorStackPointer)) {
197             HashMap<String, String> map = new HashMap<String, String>();
198
199             int eventNumber = Integer.parseInt(eventNumberString);
200             int eventSize = Integer.parseInt(eventSizeString);
201
202             // Retrieve at maximum the 10 last log messages from the panel
203             int messagesToRetrieve = Math.min(eventSize, 10);
204             for (int i = 1; i < messagesToRetrieve; i++) {
205                 eventNumber--;
206                 if (eventNumber < 0) {
207                     eventNumber = eventSize;
208                 }
209
210                 map.put(Integer.toString(eventNumber), "panel_log_message_n_" + i);
211                 bridgeHandler.sendCommand(CaddxMessageContext.COMMAND, CaddxBindingConstants.PANEL_LOG_EVENT_REQUEST,
212                         Integer.toString(eventNumber));
213             }
214
215             communicatorStackPointer = null;
216             panelLogMessagesMap = map;
217         }
218     }
219
220     private void handleZonesSnapshotMessage(CaddxMessage message) {
221         // Get the bridge handler
222         CaddxBridgeHandler bridgeHandler = getCaddxBridgeHandler();
223         if (bridgeHandler == null) {
224             return;
225         }
226
227         int zoneOffset = Integer.parseInt(message.getPropertyById("zone_offset"));
228
229         for (int i = 1; i <= 16; i++) {
230             int zoneNumber = zoneOffset * 16 + i;
231
232             String zoneFaulted = message.getPropertyById("zone_" + i + "_faulted");
233             String zoneBypassed = message.getPropertyById("zone_" + i + "_bypassed");
234             String zoneTrouble = message.getPropertyById("zone_" + i + "_trouble");
235             String zoneAlarmMemory = message.getPropertyById("zone_" + i + "_alarm_memory");
236
237             logger.debug("Flags for zone {}. faulted:{}, bypassed:{}, trouble:{}, alarm_memory:{}", zoneNumber,
238                     zoneFaulted, zoneBypassed, zoneTrouble, zoneAlarmMemory);
239
240             // Get thing
241             Thing thing = bridgeHandler.findThing(CaddxThingType.ZONE, null, zoneNumber, null);
242             if (thing != null) {
243                 ChannelUID channelUID;
244
245                 logger.debug("Thing found for zone {}.", zoneNumber);
246
247                 channelUID = new ChannelUID(thing.getUID(), "zone_faulted");
248                 updateChannel(channelUID, zoneFaulted);
249                 channelUID = new ChannelUID(thing.getUID(), "zone_bypassed");
250                 updateChannel(channelUID, zoneBypassed);
251                 channelUID = new ChannelUID(thing.getUID(), "zone_trouble");
252                 updateChannel(channelUID, zoneTrouble);
253                 channelUID = new ChannelUID(thing.getUID(), "zone_alarm_memory");
254                 updateChannel(channelUID, zoneAlarmMemory);
255             }
256         }
257     }
258
259     @Override
260     public Collection<Class<? extends ThingHandlerService>> getServices() {
261         return Set.of(CaddxPanelActions.class);
262     }
263
264     private void sendPrimaryCommand(String pin, String function) {
265         String cmd = CaddxBindingConstants.PARTITION_PRIMARY_COMMAND_WITH_PIN;
266
267         // Build the data
268         StringBuilder sb = new StringBuilder();
269         sb.append("0x").append(pin.charAt(1)).append(pin.charAt(0)).append(",0x").append(pin.charAt(3))
270                 .append(pin.charAt(2)).append(",0x").append(pin.charAt(5)).append(pin.charAt(4)).append(",")
271                 .append(function).append(",").append("255");
272
273         CaddxBridgeHandler bridgeHandler = getCaddxBridgeHandler();
274         if (bridgeHandler == null) {
275             return;
276         }
277         bridgeHandler.sendCommand(CaddxMessageContext.COMMAND, cmd, sb.toString());
278     }
279
280     private void sendSecondaryCommand(String function) {
281         String cmd = CaddxBindingConstants.PARTITION_SECONDARY_COMMAND;
282
283         // Build the data
284         StringBuilder sb = new StringBuilder();
285         sb.append(function).append(",").append("255");
286
287         CaddxBridgeHandler bridgeHandler = getCaddxBridgeHandler();
288         if (bridgeHandler == null) {
289             return;
290         }
291         bridgeHandler.sendCommand(CaddxMessageContext.COMMAND, cmd, sb.toString());
292     }
293
294     public void turnOffAnySounderOrAlarm(String pin) {
295         sendPrimaryCommand(pin, "0");
296     }
297
298     public void disarm(String pin) {
299         sendPrimaryCommand(pin, "1");
300     }
301
302     public void armInAwayMode(String pin) {
303         sendPrimaryCommand(pin, "2");
304     }
305
306     public void armInStayMode(String pin) {
307         sendPrimaryCommand(pin, "3");
308     }
309
310     public void cancel(String pin) {
311         sendPrimaryCommand(pin, "4");
312     }
313
314     public void initiateAutoArm(String pin) {
315         sendPrimaryCommand(pin, "5");
316     }
317
318     public void startWalkTestMode(String pin) {
319         sendPrimaryCommand(pin, "6");
320     }
321
322     public void stopWalkTestMode(String pin) {
323         sendPrimaryCommand(pin, "7");
324     }
325
326     public void stay() {
327         sendSecondaryCommand("0");
328     }
329
330     public void chime() {
331         sendSecondaryCommand("1");
332     }
333
334     public void exit() {
335         sendSecondaryCommand("2");
336     }
337
338     public void bypassInteriors() {
339         sendSecondaryCommand("3");
340     }
341
342     public void firePanic() {
343         sendSecondaryCommand("4");
344     }
345
346     public void medicalPanic() {
347         sendSecondaryCommand("5");
348     }
349
350     public void policePanic() {
351         sendSecondaryCommand("6");
352     }
353
354     public void smokeDetectorReset() {
355         sendSecondaryCommand("7");
356     }
357
358     public void autoCallbackDownload() {
359         sendSecondaryCommand("8");
360     }
361
362     public void manualPickupDownload() {
363         sendSecondaryCommand("9");
364     }
365
366     public void enableSilentExit() {
367         sendSecondaryCommand("10");
368     }
369
370     public void performTest() {
371         sendSecondaryCommand("11");
372     }
373
374     public void groupBypass() {
375         sendSecondaryCommand("12");
376     }
377
378     public void auxiliaryFunction1() {
379         sendSecondaryCommand("13");
380     }
381
382     public void auxiliaryFunction2() {
383         sendSecondaryCommand("14");
384     }
385
386     public void startKeypadSounder() {
387         sendSecondaryCommand("15");
388     }
389 }