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.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.eclipse.jdt.annotation.NonNull;
24 import org.openhab.binding.paradoxalarm.internal.communication.IDataUpdateListener;
25 import org.openhab.binding.paradoxalarm.internal.communication.IParadoxCommunicator;
26 import org.openhab.binding.paradoxalarm.internal.exceptions.ParadoxRuntimeException;
27 import org.openhab.binding.paradoxalarm.internal.parsers.EvoParser;
28 import org.openhab.binding.paradoxalarm.internal.parsers.IParadoxParser;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
33 * The {@link ParadoxPanel} Composition class which contains all Paradox entities.
35 * @author Konstantin Polihronov - Initial contribution
37 public class ParadoxPanel implements IDataUpdateListener {
39 private final Logger logger = LoggerFactory.getLogger(ParadoxPanel.class);
42 private static ParadoxPanel paradoxPanel = new ParadoxPanel();
44 private ParadoxInformation panelInformation;
45 private List<Partition> partitions;
46 private List<Zone> zones;
47 private IParadoxParser parser;
48 private IParadoxCommunicator communicator;
49 private double vdcLevel;
50 private double batteryLevel;
51 private double dcLevel;
52 private ZonedDateTime panelTime;
54 private ParadoxPanel() {
55 this.parser = new EvoParser();
58 public void createModelEntities() {
59 byte[] panelInfoBytes = communicator.getPanelInfoBytes();
60 panelInformation = new ParadoxInformation(panelInfoBytes, parser);
62 if (isPanelSupported()) {
63 logger.info("Paradox system is supported. Panel data retrieved={} ", panelInformation);
67 throw new ParadoxRuntimeException(
68 "Unsupported panel type. Type: " + panelInformation.getPanelType().name());
72 public static ParadoxPanel getInstance() {
76 public boolean isPanelSupported() {
77 PanelType panelType = panelInformation.getPanelType();
78 return panelType == PanelType.EVO48 || panelType == PanelType.EVO192 || panelType == PanelType.EVOHD;
81 public void updateEntitiesStates() {
83 logger.debug("Not online. Unable to update entities states. ");
87 List<byte[]> currentPartitionFlags = communicator.getPartitionFlags();
88 for (int i = 0; i < partitions.size(); i++) {
89 Partition partition = partitions.get(i);
90 if (i < currentPartitionFlags.size()) {
91 partition.setState(parser.calculatePartitionState(currentPartitionFlags.get(i)));
93 logger.debug("Partition flags collection is smaller than the number of partitions.");
97 ZoneStateFlags zoneStateFlags = communicator.getZoneStateFlags();
98 for (int i = 0; i < zones.size(); i++) {
99 Zone zone = zones.get(i);
100 zone.setZoneState(parser.calculateZoneState(zone.getId(), zoneStateFlags));
103 byte[] firstRamPage = communicator.getMemoryMap().getElement(0);
104 panelTime = constructPanelTime(firstRamPage);
105 vdcLevel = Math.max(0, (firstRamPage[25] & 0xFF) * (20.3 - 1.4) / 255.0 + 1.4);
106 dcLevel = Math.max(0, (firstRamPage[27] & 0xFF) * 22.8 / 255);
107 batteryLevel = Math.max(0, (firstRamPage[26] & 0xFF) * 22.8 / 255);
110 protected ZonedDateTime constructPanelTime(byte[] firstPage) {
112 int year = firstPage[18] * 100 + firstPage[19];
113 return ZonedDateTime.of(
114 LocalDateTime.of(year, firstPage[20], firstPage[21], firstPage[22], firstPage[23], firstPage[24]),
115 TimeZone.getDefault().toZoneId());
116 } catch (DateTimeException e) {
117 logger.debug("Received exception during parsing panel time. Falling back to old time.", e);
122 private List<Zone> createZones() {
123 zones = new ArrayList<>();
124 Map<Integer, String> zoneLabels = communicator.getZoneLabels();
125 for (int i = 0; i < zoneLabels.size(); i++) {
126 Zone zone = new Zone(i + 1, zoneLabels.get(i));
132 private List<Partition> createPartitions() {
133 partitions = new ArrayList<>();
134 Map<Integer, String> partitionLabels = communicator.getPartitionLabels();
135 for (int i = 0; i < partitionLabels.size(); i++) {
136 Partition partition = new Partition(i + 1, partitionLabels.get(i));
137 partitions.add(partition);
138 logger.debug("Partition {}:\t{}", i + 1, partition.getState().getMainState());
144 public void update() {
145 if (panelInformation == null || partitions == null || zones == null) {
146 createModelEntities();
148 updateEntitiesStates();
151 public void dispose() {
152 this.panelInformation = null;
153 this.partitions = null;
157 public ParadoxInformation getPanelInformation() {
158 return panelInformation;
161 public List<Partition> getPartitions() {
165 public void setPartitions(List<Partition> partitions) {
166 this.partitions = partitions;
169 public List<Zone> getZones() {
173 public void setZones(List<Zone> zones) {
177 public boolean isOnline() {
178 return communicator != null && communicator.isOnline();
181 public double getVdcLevel() {
185 public double getBatteryLevel() {
189 public double getDcLevel() {
193 public ZonedDateTime getPanelTime() {
197 public void setCommunicator(IParadoxCommunicator communicator) {
198 this.communicator = communicator;
201 public IParadoxCommunicator getCommunicator() {
206 public String toString() {
207 return "ParadoxPanel [panelInformation=" + panelInformation + "]";