2 * Copyright (c) 2010-2023 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.paradoxalarm.internal.model;
15 import java.time.DateTimeException;
16 import java.time.LocalDateTime;
17 import java.time.ZonedDateTime;
18 import java.util.ArrayList;
19 import java.util.List;
21 import java.util.TimeZone;
23 import org.openhab.binding.paradoxalarm.internal.communication.IDataUpdateListener;
24 import org.openhab.binding.paradoxalarm.internal.communication.IParadoxCommunicator;
25 import org.openhab.binding.paradoxalarm.internal.exceptions.ParadoxRuntimeException;
26 import org.openhab.binding.paradoxalarm.internal.parsers.EvoParser;
27 import org.openhab.binding.paradoxalarm.internal.parsers.IParadoxParser;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
32 * The {@link ParadoxPanel} Composition class which contains all Paradox entities.
34 * @author Konstantin Polihronov - Initial contribution
36 public class ParadoxPanel implements IDataUpdateListener {
38 private final Logger logger = LoggerFactory.getLogger(ParadoxPanel.class);
40 private ParadoxInformation panelInformation;
41 private List<Partition> partitions;
42 private List<Zone> zones;
43 private IParadoxParser parser;
44 private IParadoxCommunicator communicator;
45 private double vdcLevel;
46 private double batteryLevel;
47 private double dcLevel;
48 private ZonedDateTime panelTime;
50 public ParadoxPanel() {
51 this.parser = new EvoParser();
54 public void createModelEntities() {
55 byte[] panelInfoBytes = communicator.getPanelInfoBytes();
56 panelInformation = new ParadoxInformation(panelInfoBytes, parser);
58 if (isPanelSupported()) {
59 logger.info("Paradox system is supported. Panel data retrieved={} ", panelInformation);
63 throw new ParadoxRuntimeException(
64 "Unsupported panel type. Type: " + panelInformation.getPanelType().name());
68 public boolean isPanelSupported() {
69 PanelType panelType = panelInformation.getPanelType();
70 return panelType == PanelType.EVO48 || panelType == PanelType.EVO192 || panelType == PanelType.EVOHD;
73 public void updateEntitiesStates() {
75 logger.debug("Not online. Unable to update entities states. ");
79 List<byte[]> currentPartitionFlags = communicator.getPartitionFlags();
80 for (int i = 0; i < partitions.size(); i++) {
81 Partition partition = partitions.get(i);
82 if (i < currentPartitionFlags.size()) {
83 partition.setState(parser.calculatePartitionState(currentPartitionFlags.get(i)));
85 logger.debug("Partition flags collection is smaller than the number of partitions.");
89 ZoneStateFlags zoneStateFlags = communicator.getZoneStateFlags();
90 for (int i = 0; i < zones.size(); i++) {
91 Zone zone = zones.get(i);
92 zone.setZoneState(parser.calculateZoneState(zone.getId(), zoneStateFlags));
95 byte[] firstRamPage = communicator.getMemoryMap().getElement(0);
96 panelTime = constructPanelTime(firstRamPage);
97 vdcLevel = Math.max(0, (firstRamPage[25] & 0xFF) * (20.3 - 1.4) / 255.0 + 1.4);
98 dcLevel = Math.max(0, (firstRamPage[27] & 0xFF) * 22.8 / 255);
99 batteryLevel = Math.max(0, (firstRamPage[26] & 0xFF) * 22.8 / 255);
102 protected ZonedDateTime constructPanelTime(byte[] firstPage) {
104 int year = firstPage[18] * 100 + firstPage[19];
105 return ZonedDateTime.of(
106 LocalDateTime.of(year, firstPage[20], firstPage[21], firstPage[22], firstPage[23], firstPage[24]),
107 TimeZone.getDefault().toZoneId());
108 } catch (DateTimeException e) {
109 logger.debug("Received exception during parsing panel time. Falling back to old time.", e);
114 private List<Zone> createZones() {
115 zones = new ArrayList<>();
116 Map<Integer, String> zoneLabels = communicator.getZoneLabels();
117 for (int i = 0; i < zoneLabels.size(); i++) {
118 Zone zone = new Zone(this, i + 1, zoneLabels.get(i));
124 private List<Partition> createPartitions() {
125 partitions = new ArrayList<>();
126 Map<Integer, String> partitionLabels = communicator.getPartitionLabels();
127 for (int i = 0; i < partitionLabels.size(); i++) {
128 Partition partition = new Partition(this, i + 1, partitionLabels.get(i));
129 partitions.add(partition);
130 logger.debug("Partition {}:\t{}", i + 1, partition.getState().getMainState());
136 public void update() {
137 if (panelInformation == null || partitions == null || zones == null) {
138 createModelEntities();
140 updateEntitiesStates();
143 public void dispose() {
144 this.panelInformation = null;
145 this.partitions = null;
149 public ParadoxInformation getPanelInformation() {
150 return panelInformation;
153 public List<Partition> getPartitions() {
157 public void setPartitions(List<Partition> partitions) {
158 this.partitions = partitions;
161 public List<Zone> getZones() {
165 public void setZones(List<Zone> zones) {
169 public boolean isOnline() {
170 return communicator != null && communicator.isOnline();
173 public double getVdcLevel() {
177 public double getBatteryLevel() {
181 public double getDcLevel() {
185 public ZonedDateTime getPanelTime() {
189 public void setCommunicator(IParadoxCommunicator communicator) {
190 this.communicator = communicator;
193 public IParadoxCommunicator getCommunicator() {
198 public String toString() {
199 return "ParadoxPanel [panelInformation=" + panelInformation + "]";