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 DateTimeValue lastMessageReceived = new DateTimeValue(this, "_last_message_received");
51 public StringValue panelStatus = new StringValue(this, "_panel_status");
52 public StringValue alarmType = new StringValue(this, "_alarm_type");
53 public StringValue troubleType = new StringValue(this, "_trouble_type");
55 public DynamicValue<Boolean> isArmed = new DynamicValue<>(this, SYSTEM_ARMED, () -> {
58 return isArmed() ? OnOffType.ON : OnOffType.OFF;
61 public DynamicValue<String> panelMode = new DynamicValue<>(this, MODE, () -> {
62 return getPanelMode();
64 return new StringType(getPanelMode());
67 public DynamicValue<String> shortArmMode = new DynamicValue<>(this, ARM_MODE, () -> {
68 return getShortArmMode();
70 return new StringType(getShortArmMode());
73 public DynamicValue<Boolean> pgmStatus = new DynamicValue<>(this, PGM_STATUS, () -> {
74 return getPGMX10DeviceStatus(0);
76 return getPGMX10DeviceStatus(0) ? OnOffType.ON : OnOffType.OFF;
79 private PowermaxZoneState[] zones;
80 private Boolean[] pgmX10DevicesStatus;
81 private byte[] updateSettings;
82 private String[] eventLog;
83 private Map<Integer, Byte> updatedZoneNames;
84 private Map<Integer, Integer> updatedZoneInfos;
87 * Constructor (default values)
89 public PowermaxState(PowermaxPanelSettings panelSettings, TimeZoneProvider timeZoneProvider) {
90 super(timeZoneProvider);
92 zones = new PowermaxZoneState[panelSettings.getNbZones()];
93 for (int i = 0; i < panelSettings.getNbZones(); i++) {
94 zones[i] = new PowermaxZoneState(timeZoneProvider);
96 pgmX10DevicesStatus = new Boolean[panelSettings.getNbPGMX10Devices()];
97 updatedZoneNames = new HashMap<>();
98 updatedZoneInfos = new HashMap<>();
102 * Return the PowermaxZoneState object for a given zone. If the zone number is
103 * out of range, returns a dummy PowermaxZoneState object that won't be
104 * persisted. The return value is never null, so it's safe to chain method
107 * @param zone the index of the zone (first zone is index 1)
108 * @return the zone state object (or a dummy zone state)
110 public PowermaxZoneState getZone(int zone) {
111 if ((zone < 1) || (zone > zones.length)) {
112 logger.warn("Received update for invalid zone {}", zone);
113 return new PowermaxZoneState(timeZoneProvider);
115 return zones[zone - 1];
120 * Get the status of a PGM or X10 device
122 * @param device the index of the PGM/X10 device (0 s for PGM; for X10 device is index 1)
124 * @return the status (true or false)
126 public Boolean getPGMX10DeviceStatus(int device) {
127 return ((device < 0) || (device >= pgmX10DevicesStatus.length)) ? null : pgmX10DevicesStatus[device];
131 * Set the status of a PGM or X10 device
133 * @param device the index of the PGM/X10 device (0 s for PGM; for X10 device is index 1)
134 * @param status true or false
136 public void setPGMX10DeviceStatus(int device, Boolean status) {
137 if ((device >= 0) && (device < pgmX10DevicesStatus.length)) {
138 this.pgmX10DevicesStatus[device] = status;
143 * Get the raw buffer containing all the settings
145 * @return the raw buffer as a table of bytes
147 public byte[] getUpdateSettings() {
148 return updateSettings;
152 * Set the raw buffer containing all the settings
154 * @param updateSettings the raw buffer as a table of bytes
156 public void setUpdateSettings(byte[] updateSettings) {
157 this.updateSettings = updateSettings;
161 * Get the number of entries in the event log
163 * @return the number of entries
165 public int getEventLogSize() {
166 return (eventLog == null) ? 0 : eventLog.length;
170 * Set the number of entries in the event log
172 * @param size the number of entries
174 public void setEventLogSize(int size) {
175 eventLog = new String[size];
179 * Get one entry from the event logs
181 * @param index the entry index (1 for the most recent entry)
183 * @return the entry value (event)
185 public String getEventLog(int index) {
186 return ((index < 1) || (index > getEventLogSize())) ? null : eventLog[index - 1];
190 * Set one entry from the event logs
192 * @param index the entry index (1 for the most recent entry)
193 * @param event the entry value (event)
195 public void setEventLog(int index, String event) {
196 if ((index >= 1) && (index <= getEventLogSize())) {
197 this.eventLog[index - 1] = event;
201 public Map<Integer, Byte> getUpdatedZoneNames() {
202 return updatedZoneNames;
205 public void updateZoneName(int zoneIdx, byte zoneNameIdx) {
206 this.updatedZoneNames.put(zoneIdx, zoneNameIdx);
209 public Map<Integer, Integer> getUpdatedZoneInfos() {
210 return updatedZoneInfos;
213 public void updateZoneInfo(int zoneIdx, int zoneInfo) {
214 this.updatedZoneInfos.put(zoneIdx, zoneInfo);
220 * @return either Download or Powerlink or Standard
222 public String getPanelMode() {
224 if (Boolean.TRUE.equals(downloadMode.getValue())) {
226 } else if (Boolean.TRUE.equals(powerlinkMode.getValue())) {
228 } else if (Boolean.FALSE.equals(powerlinkMode.getValue())) {
235 * Get whether or not the current arming mode is considered as armed
237 * @return true or false
239 public Boolean isArmed() {
240 return isArmed(armMode.getValue());
244 * Get whether or not an arming mode is considered as armed
246 * @param armMode the arming mode
248 * @return true or false; null if mode is unexpected
250 private static Boolean isArmed(String armMode) {
251 Boolean result = null;
252 if (armMode != null) {
254 PowermaxArmMode mode = PowermaxArmMode.fromName(armMode);
255 result = mode.isArmed();
256 } catch (IllegalArgumentException e) {
257 result = Boolean.FALSE;
264 * Get the short description associated to the current arming mode
266 * @return the short description
268 public String getShortArmMode() {
269 return getShortArmMode(armMode.getValue());
273 * Get the short name associated to an arming mode
275 * @param armMode the arming mode
277 * @return the short name or null if mode is unexpected
279 private static String getShortArmMode(String armMode) {
280 String result = null;
281 if (armMode != null) {
283 PowermaxArmMode mode = PowermaxArmMode.fromName(armMode);
284 result = mode.getShortName();
285 } catch (IllegalArgumentException e) {
293 * Keep only data that are different from another state and reset all others data to undefined
295 * @param otherState the other state
297 public void keepOnlyDifferencesWith(PowermaxState otherState) {
298 for (int zone = 1; zone <= zones.length; zone++) {
299 PowermaxZoneState thisZone = getZone(zone);
300 PowermaxZoneState otherZone = otherState.getZone(zone);
302 for (int i = 0; i < thisZone.getValues().size(); i++) {
303 Value<?> thisValue = thisZone.getValues().get(i);
304 Value<?> otherValue = otherZone.getValues().get(i);
306 if ((thisValue.getValue() != null) && thisValue.getValue().equals(otherValue.getValue())) {
307 thisValue.setValue(null);
312 for (int i = 0; i < pgmX10DevicesStatus.length; i++) {
313 if ((getPGMX10DeviceStatus(i) != null)
314 && getPGMX10DeviceStatus(i).equals(otherState.getPGMX10DeviceStatus(i))) {
315 setPGMX10DeviceStatus(i, null);
319 for (int i = 0; i < getValues().size(); i++) {
320 Value<?> thisValue = getValues().get(i);
321 Value<?> otherValue = otherState.getValues().get(i);
323 if ((thisValue.getValue() != null) && thisValue.getValue().equals(otherValue.getValue())) {
324 thisValue.setValue(null);
330 * Update (override) the current state data from another state, ignoring in this other state
333 * @param update the other state to consider for the update
335 public void merge(PowermaxState update) {
336 for (int zone = 1; zone <= zones.length; zone++) {
337 PowermaxZoneState thisZone = getZone(zone);
338 PowermaxZoneState otherZone = update.getZone(zone);
340 for (int i = 0; i < thisZone.getValues().size(); i++) {
341 Value<?> thisValue = thisZone.getValues().get(i);
342 Value<?> otherValue = otherZone.getValues().get(i);
344 if (otherValue.getValue() != null) {
345 thisValue.setValueUnsafe(otherValue.getValue());
350 for (int i = 0; i < pgmX10DevicesStatus.length; i++) {
351 if (update.getPGMX10DeviceStatus(i) != null) {
352 setPGMX10DeviceStatus(i, update.getPGMX10DeviceStatus(i));
356 for (int i = 0; i < getValues().size(); i++) {
357 Value<?> thisValue = getValues().get(i);
358 Value<?> otherValue = update.getValues().get(i);
360 if (otherValue.getValue() != null) {
361 thisValue.setValueUnsafe(otherValue.getValue());
365 if (update.getEventLogSize() > getEventLogSize()) {
366 setEventLogSize(update.getEventLogSize());
368 for (int i = 1; i <= getEventLogSize(); i++) {
369 if (update.getEventLog(i) != null) {
370 setEventLog(i, update.getEventLog(i));
376 public String toString() {
377 String str = "Bridge state:";
379 for (Value<?> value : getValues()) {
380 if ((value.getChannel() != null) && (value.getValue() != null)) {
381 String channel = value.getChannel();
382 String v_str = value.getValue().toString();
383 String state = value.getState().toString();
385 str += "\n - " + channel + " = " + v_str;
386 if (!v_str.equals(state)) {
387 str += " (" + state + ")";
392 for (int i = 0; i < pgmX10DevicesStatus.length; i++) {
393 if (getPGMX10DeviceStatus(i) != null) {
394 str += String.format("\n - %s status = %s", (i == 0) ? "PGM device" : String.format("X10 device %d", i),
395 getPGMX10DeviceStatus(i) ? "ON" : "OFF");
399 for (int i = 1; i <= zones.length; i++) {
400 for (Value<?> value : zones[i - 1].getValues()) {
401 if ((value.getChannel() != null) && (value.getValue() != null)) {
402 String channel = value.getChannel();
403 String v_str = value.getValue().toString();
404 String state = value.getState().toString();
406 str += String.format("\n - sensor zone %d %s = %s", i, channel, v_str);
407 if (!v_str.equals(state)) {
408 str += " (" + state + ")";
414 for (int i = 1; i <= getEventLogSize(); i++) {
415 if (getEventLog(i) != null) {
416 str += "\n - event log " + i + " = " + getEventLog(i);