2 * Copyright (c) 2010-2021 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.state;
15 import static org.openhab.binding.powermax.internal.PowermaxBindingConstants.*;
17 import java.util.HashMap;
20 import org.openhab.core.i18n.TimeZoneProvider;
21 import org.openhab.core.library.types.OnOffType;
22 import org.openhab.core.library.types.StringType;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
27 * A class to store the state of the alarm system
29 * @author Laurent Garnier - Initial contribution
31 public class PowermaxState extends PowermaxStateContainer {
33 private final Logger logger = LoggerFactory.getLogger(PowermaxState.class);
35 // For values that are mapped to channels, use a channel name constant from
36 // PowermaxBindingConstants. For values used internally but not mapped to
37 // channels, use a unique name starting with "_".
39 public BooleanValue powerlinkMode = new BooleanValue(this, "_powerlink_mode");
40 public BooleanValue downloadMode = new BooleanValue(this, "_download_mode");
41 public BooleanValue ready = new BooleanValue(this, READY);
42 public BooleanValue bypass = new BooleanValue(this, WITH_ZONES_BYPASSED);
43 public BooleanValue alarmActive = new BooleanValue(this, ALARM_ACTIVE);
44 public BooleanValue trouble = new BooleanValue(this, TROUBLE);
45 public BooleanValue alertInMemory = new BooleanValue(this, ALERT_IN_MEMORY);
46 public StringValue statusStr = new StringValue(this, SYSTEM_STATUS);
47 public StringValue armMode = new StringValue(this, "_arm_mode");
48 public BooleanValue downloadSetupRequired = new BooleanValue(this, "_download_setup_required");
49 public DateTimeValue lastKeepAlive = new DateTimeValue(this, "_last_keepalive");
50 public StringValue panelStatus = new StringValue(this, "_panel_status");
51 public StringValue alarmType = new StringValue(this, "_alarm_type");
52 public StringValue troubleType = new StringValue(this, "_trouble_type");
54 public DynamicValue<Boolean> isArmed = new DynamicValue<>(this, SYSTEM_ARMED, () -> {
57 return isArmed() ? OnOffType.ON : OnOffType.OFF;
60 public DynamicValue<String> panelMode = new DynamicValue<>(this, MODE, () -> {
61 return getPanelMode();
63 return new StringType(getPanelMode());
66 public DynamicValue<String> shortArmMode = new DynamicValue<>(this, ARM_MODE, () -> {
67 return getShortArmMode();
69 return new StringType(getShortArmMode());
72 public DynamicValue<Boolean> pgmStatus = new DynamicValue<>(this, PGM_STATUS, () -> {
73 return getPGMX10DeviceStatus(0);
75 return getPGMX10DeviceStatus(0) ? OnOffType.ON : OnOffType.OFF;
78 private PowermaxZoneState[] zones;
79 private Boolean[] pgmX10DevicesStatus;
80 private byte[] updateSettings;
81 private String[] eventLog;
82 private Map<Integer, Byte> updatedZoneNames;
83 private Map<Integer, Integer> updatedZoneInfos;
86 * Constructor (default values)
88 public PowermaxState(PowermaxPanelSettings panelSettings, TimeZoneProvider timeZoneProvider) {
89 super(timeZoneProvider);
91 zones = new PowermaxZoneState[panelSettings.getNbZones()];
92 for (int i = 0; i < panelSettings.getNbZones(); i++) {
93 zones[i] = new PowermaxZoneState(timeZoneProvider);
95 pgmX10DevicesStatus = new Boolean[panelSettings.getNbPGMX10Devices()];
96 updatedZoneNames = new HashMap<>();
97 updatedZoneInfos = new HashMap<>();
101 * Return the PowermaxZoneState object for a given zone. If the zone number is
102 * out of range, returns a dummy PowermaxZoneState object that won't be
103 * persisted. The return value is never null, so it's safe to chain method
106 * @param zone the index of the zone (first zone is index 1)
107 * @return the zone state object (or a dummy zone state)
109 public PowermaxZoneState getZone(int zone) {
110 if ((zone < 1) || (zone > zones.length)) {
111 logger.warn("Received update for invalid zone {}", zone);
112 return new PowermaxZoneState(timeZoneProvider);
114 return zones[zone - 1];
119 * Get the status of a PGM or X10 device
121 * @param device the index of the PGM/X10 device (0 s for PGM; for X10 device is index 1)
123 * @return the status (true or false)
125 public Boolean getPGMX10DeviceStatus(int device) {
126 return ((device < 0) || (device >= pgmX10DevicesStatus.length)) ? null : pgmX10DevicesStatus[device];
130 * Set the status of a PGM or X10 device
132 * @param device the index of the PGM/X10 device (0 s for PGM; for X10 device is index 1)
133 * @param status true or false
135 public void setPGMX10DeviceStatus(int device, Boolean status) {
136 if ((device >= 0) && (device < pgmX10DevicesStatus.length)) {
137 this.pgmX10DevicesStatus[device] = status;
142 * Get the raw buffer containing all the settings
144 * @return the raw buffer as a table of bytes
146 public byte[] getUpdateSettings() {
147 return updateSettings;
151 * Set the raw buffer containing all the settings
153 * @param updateSettings the raw buffer as a table of bytes
155 public void setUpdateSettings(byte[] updateSettings) {
156 this.updateSettings = updateSettings;
160 * Get the number of entries in the event log
162 * @return the number of entries
164 public int getEventLogSize() {
165 return (eventLog == null) ? 0 : eventLog.length;
169 * Set the number of entries in the event log
171 * @param size the number of entries
173 public void setEventLogSize(int size) {
174 eventLog = new String[size];
178 * Get one entry from the event logs
180 * @param index the entry index (1 for the most recent entry)
182 * @return the entry value (event)
184 public String getEventLog(int index) {
185 return ((index < 1) || (index > getEventLogSize())) ? null : eventLog[index - 1];
189 * Set one entry from the event logs
191 * @param index the entry index (1 for the most recent entry)
192 * @param event the entry value (event)
194 public void setEventLog(int index, String event) {
195 if ((index >= 1) && (index <= getEventLogSize())) {
196 this.eventLog[index - 1] = event;
200 public Map<Integer, Byte> getUpdatedZoneNames() {
201 return updatedZoneNames;
204 public void updateZoneName(int zoneIdx, byte zoneNameIdx) {
205 this.updatedZoneNames.put(zoneIdx, zoneNameIdx);
208 public Map<Integer, Integer> getUpdatedZoneInfos() {
209 return updatedZoneInfos;
212 public void updateZoneInfo(int zoneIdx, int zoneInfo) {
213 this.updatedZoneInfos.put(zoneIdx, zoneInfo);
219 * @return either Download or Powerlink or Standard
221 public String getPanelMode() {
223 if (Boolean.TRUE.equals(downloadMode.getValue())) {
225 } else if (Boolean.TRUE.equals(powerlinkMode.getValue())) {
227 } else if (Boolean.FALSE.equals(powerlinkMode.getValue())) {
234 * Get whether or not the current arming mode is considered as armed
236 * @return true or false
238 public Boolean isArmed() {
239 return isArmed(armMode.getValue());
243 * Get whether or not an arming mode is considered as armed
245 * @param armMode the arming mode
247 * @return true or false; null if mode is unexpected
249 private static Boolean isArmed(String armMode) {
250 Boolean result = null;
251 if (armMode != null) {
253 PowermaxArmMode mode = PowermaxArmMode.fromName(armMode);
254 result = mode.isArmed();
255 } catch (IllegalArgumentException e) {
256 result = Boolean.FALSE;
263 * Get the short description associated to the current arming mode
265 * @return the short description
267 public String getShortArmMode() {
268 return getShortArmMode(armMode.getValue());
272 * Get the short name associated to an arming mode
274 * @param armMode the arming mode
276 * @return the short name or null if mode is unexpected
278 private static String getShortArmMode(String armMode) {
279 String result = null;
280 if (armMode != null) {
282 PowermaxArmMode mode = PowermaxArmMode.fromName(armMode);
283 result = mode.getShortName();
284 } catch (IllegalArgumentException e) {
292 * Keep only data that are different from another state and reset all others data to undefined
294 * @param otherState the other state
296 public void keepOnlyDifferencesWith(PowermaxState otherState) {
297 for (int zone = 1; zone <= zones.length; zone++) {
298 PowermaxZoneState thisZone = getZone(zone);
299 PowermaxZoneState otherZone = otherState.getZone(zone);
301 for (int i = 0; i < thisZone.getValues().size(); i++) {
302 Value<?> thisValue = thisZone.getValues().get(i);
303 Value<?> otherValue = otherZone.getValues().get(i);
305 if ((thisValue.getValue() != null) && thisValue.getValue().equals(otherValue.getValue())) {
306 thisValue.setValue(null);
311 for (int i = 0; i < pgmX10DevicesStatus.length; i++) {
312 if ((getPGMX10DeviceStatus(i) != null)
313 && getPGMX10DeviceStatus(i).equals(otherState.getPGMX10DeviceStatus(i))) {
314 setPGMX10DeviceStatus(i, null);
318 for (int i = 0; i < getValues().size(); i++) {
319 Value<?> thisValue = getValues().get(i);
320 Value<?> otherValue = otherState.getValues().get(i);
322 if ((thisValue.getValue() != null) && thisValue.getValue().equals(otherValue.getValue())) {
323 thisValue.setValue(null);
329 * Update (override) the current state data from another state, ignoring in this other state
332 * @param update the other state to consider for the update
334 public void merge(PowermaxState update) {
335 for (int zone = 1; zone <= zones.length; zone++) {
336 PowermaxZoneState thisZone = getZone(zone);
337 PowermaxZoneState otherZone = update.getZone(zone);
339 for (int i = 0; i < thisZone.getValues().size(); i++) {
340 Value<?> thisValue = thisZone.getValues().get(i);
341 Value<?> otherValue = otherZone.getValues().get(i);
343 if (otherValue.getValue() != null) {
344 thisValue.setValueUnsafe(otherValue.getValue());
349 for (int i = 0; i < pgmX10DevicesStatus.length; i++) {
350 if (update.getPGMX10DeviceStatus(i) != null) {
351 setPGMX10DeviceStatus(i, update.getPGMX10DeviceStatus(i));
355 for (int i = 0; i < getValues().size(); i++) {
356 Value<?> thisValue = getValues().get(i);
357 Value<?> otherValue = update.getValues().get(i);
359 if (otherValue.getValue() != null) {
360 thisValue.setValueUnsafe(otherValue.getValue());
364 if (update.getEventLogSize() > getEventLogSize()) {
365 setEventLogSize(update.getEventLogSize());
367 for (int i = 1; i <= getEventLogSize(); i++) {
368 if (update.getEventLog(i) != null) {
369 setEventLog(i, update.getEventLog(i));
375 public String toString() {
376 String str = "Bridge state:";
378 for (Value<?> value : getValues()) {
379 if ((value.getChannel() != null) && (value.getValue() != null)) {
380 String channel = value.getChannel();
381 String v_str = value.getValue().toString();
382 String state = value.getState().toString();
384 str += "\n - " + channel + " = " + v_str;
385 if (!v_str.equals(state)) {
386 str += " (" + state + ")";
391 for (int i = 0; i < pgmX10DevicesStatus.length; i++) {
392 if (getPGMX10DeviceStatus(i) != null) {
393 str += String.format("\n - %s status = %s", (i == 0) ? "PGM device" : String.format("X10 device %d", i),
394 getPGMX10DeviceStatus(i) ? "ON" : "OFF");
398 for (int i = 1; i <= zones.length; i++) {
399 for (Value<?> value : zones[i - 1].getValues()) {
400 if ((value.getChannel() != null) && (value.getValue() != null)) {
401 String channel = value.getChannel();
402 String v_str = value.getValue().toString();
403 String state = value.getState().toString();
405 str += String.format("\n - sensor zone %d %s = %s", i, channel, v_str);
406 if (!v_str.equals(state)) {
407 str += " (" + state + ")";
413 for (int i = 1; i <= getEventLogSize(); i++) {
414 if (getEventLog(i) != null) {
415 str += "\n - event log " + i + " = " + getEventLog(i);