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.digitalstrom.internal.lib.manager.impl;
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.LinkedList;
18 import java.util.List;
22 import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
23 import org.openhab.binding.digitalstrom.internal.lib.manager.StructureManager;
24 import org.openhab.binding.digitalstrom.internal.lib.serverconnection.DsAPI;
25 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.AbstractGeneralDeviceInformations;
26 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Circuit;
27 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
28 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.CachedMeteringValue;
29 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
30 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSUID;
32 import com.google.gson.JsonArray;
33 import com.google.gson.JsonObject;
36 * The {@link StructureManagerImpl} is the implementation of the {@link StructureManager}.
38 * @author Michael Ochel - Initial contribution
39 * @author Matthias Siegele - Initial contribution
41 public class StructureManagerImpl implements StructureManager {
43 private class ZoneGroupsNameAndIDMap {
44 public final String zoneName;
45 public final int zoneID;
47 private final Map<Short, String> groupIdNames;
48 private final Map<String, Short> groupNameIds;
50 public ZoneGroupsNameAndIDMap(final int zoneID, final String zoneName, JsonArray groups) {
52 this.zoneName = zoneName;
54 groupIdNames = new HashMap<>(groups.size());
55 groupNameIds = new HashMap<>(groups.size());
56 for (int k = 0; k < groups.size(); k++) {
57 short groupID = ((JsonObject) groups.get(k)).get("group").getAsShort();
58 String groupName = ((JsonObject) groups.get(k)).get("name").getAsString();
59 groupIdNames.put(groupID, groupName);
60 groupNameIds.put(groupName, groupID);
64 public String getGroupName(Short groupID) {
65 return groupIdNames.get(groupID);
68 public short getGroupID(String groupName) {
69 final Short tmp = groupNameIds.get(groupName);
70 return tmp != null ? tmp : -1;
75 * Query to get all zone and group names. Can be executed with {@link DsAPI#query(String, String)} or
76 * {@link DsAPI#query2(String, String)}.
78 public static final String ZONE_GROUP_NAMES = "/apartment/zones/*(ZoneID,name)/groups/*(group,name)";
80 private final Map<Integer, Map<Short, List<Device>>> zoneGroupDeviceMap = Collections
81 .synchronizedMap(new HashMap<>());
82 private final Map<DSID, Device> deviceMap = Collections.synchronizedMap(new HashMap<>());
83 private final Map<DSID, Circuit> circuitMap = Collections.synchronizedMap(new HashMap<>());
84 private final Map<String, DSID> dSUIDToDSIDMap = Collections.synchronizedMap(new HashMap<>());
86 private Map<Integer, ZoneGroupsNameAndIDMap> zoneGroupIdNameMap;
87 private Map<String, ZoneGroupsNameAndIDMap> zoneGroupNameIdMap;
90 * Creates a new {@link StructureManagerImpl} with the {@link Device}s of the given referenceDeviceList.
92 * @param referenceDeviceList to add
94 public StructureManagerImpl(List<Device> referenceDeviceList) {
95 handleStructure(referenceDeviceList);
99 * Creates a new {@link StructureManagerImpl} with the {@link Device}s of the given referenceDeviceList.
101 * @param referenceDeviceList to add
102 * @param referenceCircuitList to add
104 public StructureManagerImpl(List<Device> referenceDeviceList, List<Circuit> referenceCircuitList) {
105 handleStructure(referenceDeviceList);
106 addCircuitList(referenceCircuitList);
110 * Creates a new {@link StructureManagerImpl} without {@link Device}s.
112 public StructureManagerImpl() {
116 public boolean generateZoneGroupNames(ConnectionManager connectionManager) {
117 JsonObject resultJsonObj = connectionManager.getDigitalSTROMAPI().query(connectionManager.getSessionToken(),
119 if (resultJsonObj != null && resultJsonObj.get("zones") instanceof JsonArray) {
120 JsonArray zones = (JsonArray) resultJsonObj.get("zones");
121 if (zoneGroupIdNameMap == null) {
122 zoneGroupIdNameMap = new HashMap<>(zones.size());
123 zoneGroupNameIdMap = new HashMap<>(zones.size());
126 for (int i = 0; i < zones.size(); i++) {
127 if (((JsonObject) zones.get(i)).get("groups") instanceof JsonArray) {
128 JsonArray groups = (JsonArray) ((JsonObject) zones.get(i)).get("groups");
129 ZoneGroupsNameAndIDMap zoneGoupIdNameMap = new ZoneGroupsNameAndIDMap(
130 ((JsonObject) zones.get(i)).get("ZoneID").getAsInt(),
131 ((JsonObject) zones.get(i)).get("name").getAsString(), groups);
133 zoneGroupIdNameMap.put(zoneGoupIdNameMap.zoneID, zoneGoupIdNameMap);
134 zoneGroupNameIdMap.put(zoneGoupIdNameMap.zoneName, zoneGoupIdNameMap);
143 public String getZoneName(int zoneID) {
144 if (zoneGroupIdNameMap == null) {
147 final ZoneGroupsNameAndIDMap tmp = zoneGroupIdNameMap.get(zoneID);
148 return tmp != null ? tmp.zoneName : null;
152 public String getZoneGroupName(int zoneID, short groupID) {
153 if (zoneGroupIdNameMap == null) {
156 final ZoneGroupsNameAndIDMap tmp = zoneGroupIdNameMap.get(zoneID);
157 return tmp != null ? tmp.getGroupName(groupID) : null;
161 public int getZoneId(String zoneName) {
162 if (zoneGroupNameIdMap == null) {
165 final ZoneGroupsNameAndIDMap tmp = zoneGroupNameIdMap.get(zoneName);
166 return tmp != null ? tmp.zoneID : -1;
170 public boolean checkZoneID(int zoneID) {
171 return getGroupsFromZoneX(zoneID) != null;
175 public boolean checkZoneGroupID(int zoneID, short groupID) {
176 final Map<Short, List<Device>> tmp = getGroupsFromZoneX(zoneID);
177 return tmp != null ? tmp.get(groupID) != null : false;
181 public short getZoneGroupId(String zoneName, String groupName) {
182 if (zoneGroupNameIdMap == null) {
185 final ZoneGroupsNameAndIDMap tmp = zoneGroupNameIdMap.get(zoneName);
186 return tmp != null ? tmp.getGroupID(groupName) : -1;
190 public Map<DSID, Device> getDeviceMap() {
191 return new HashMap<>(deviceMap);
194 private void putDeviceToHashMap(Device device) {
195 if (device.getDSID() != null) {
196 deviceMap.put(device.getDSID(), device);
197 addDSIDtoDSUID((AbstractGeneralDeviceInformations) device);
202 * This method build the digitalSTROM structure as a {@link HashMap} with the zone id as key
203 * and a {@link HashMap} as value. This {@link HashMap} has the group id as key and a {@link List}
204 * with all digitalSTROM {@link Device}s.<br>
206 * <b>Note:</b> the zone id 0 is the broadcast address and the group id 0, too.
208 private void handleStructure(List<Device> deviceList) {
209 Map<Short, List<Device>> groupXHashMap = new HashMap<>();
210 groupXHashMap.put((short) 0, deviceList);
212 zoneGroupDeviceMap.put(0, groupXHashMap);
214 for (Device device : deviceList) {
215 addDeviceToStructure(device);
220 public Map<DSID, Device> getDeviceHashMapReference() {
225 public Map<Integer, Map<Short, List<Device>>> getStructureReference() {
226 return zoneGroupDeviceMap;
230 public Map<Short, List<Device>> getGroupsFromZoneX(int zoneID) {
231 return zoneGroupDeviceMap.get(zoneID);
235 public List<Device> getReferenceDeviceListFromZoneXGroupX(int zoneID, short groupID) {
236 final Map<Short, List<Device>> tmp = getGroupsFromZoneX(zoneID);
237 return tmp != null ? tmp.get(groupID) : null;
241 public Device getDeviceByDSID(String dSID) {
242 return getDeviceByDSID(new DSID(dSID));
246 public Device getDeviceByDSID(DSID dSID) {
247 return deviceMap.get(dSID);
251 public Device getDeviceByDSUID(String dSUID) {
252 final DSID tmp = dSUIDToDSIDMap.get(dSUID);
253 return tmp != null ? getDeviceByDSID(tmp) : null;
257 public void updateDevice(int oldZone, List<Short> oldGroups, Device device) {
258 int intOldZoneID = oldZone;
259 if (intOldZoneID == -1) {
260 intOldZoneID = device.getZoneId();
262 deleteDevice(intOldZoneID, oldGroups, device);
263 addDeviceToStructure(device);
267 public void updateDevice(Device device) {
268 if (device != null) {
270 List<Short> oldGroups = null;
271 Device internalDevice = this.getDeviceByDSID(device.getDSID());
272 if (internalDevice != null) {
273 if (device.getZoneId() != internalDevice.getZoneId()) {
274 oldZoneID = internalDevice.getZoneId();
275 internalDevice.setZoneId(device.getZoneId());
278 if (!internalDevice.getGroups().equals(device.getGroups())) {
279 oldGroups = internalDevice.getGroups();
280 internalDevice.setGroups(device.getGroups());
283 if (deleteDevice(oldZoneID, oldGroups, internalDevice)) {
284 addDeviceToStructure(internalDevice);
291 public void deleteDevice(Device device) {
292 dSUIDToDSIDMap.remove(device.getDSUID());
293 deviceMap.remove(device.getDSID());
294 deleteDevice(device.getZoneId(), device.getGroups(), device);
297 private boolean deleteDevice(int zoneID, List<Short> groups, Device device) {
298 List<Short> intGroups = groups;
299 int intZoneID = zoneID;
300 if (intGroups != null || intZoneID >= 0) {
301 if (intGroups == null) {
302 intGroups = device.getGroups();
304 if (intZoneID == -1) {
305 intZoneID = device.getZoneId();
307 for (Short groupID : intGroups) {
308 List<Device> deviceList = getReferenceDeviceListFromZoneXGroupX(intZoneID, groupID);
309 if (deviceList != null) {
310 deviceList.remove(device);
312 deviceList = getReferenceDeviceListFromZoneXGroupX(0, groupID);
313 if (deviceList != null) {
314 deviceList.remove(device);
323 public void addDeviceToStructure(Device device) {
324 putDeviceToHashMap(device);
326 addDevicetoZoneXGroupX(0, (short) 0, device);
327 int zoneID = device.getZoneId();
328 addDevicetoZoneXGroupX(zoneID, (short) 0, device);
330 for (Short groupID : device.getGroups()) {
331 addDevicetoZoneXGroupX(zoneID, groupID, device);
334 addDevicetoZoneXGroupX(0, groupID, device);
339 private void addDevicetoZoneXGroupX(int zoneID, short groupID, Device device) {
340 Map<Short, List<Device>> groupXHashMap = zoneGroupDeviceMap.get(zoneID);
341 if (groupXHashMap == null) {
342 groupXHashMap = new HashMap<>();
343 zoneGroupDeviceMap.put(zoneID, groupXHashMap);
345 List<Device> groupDeviceList = groupXHashMap.get(groupID);
346 if (groupDeviceList == null) {
347 groupDeviceList = new LinkedList<>();
348 groupDeviceList.add(device);
349 groupXHashMap.put(groupID, groupDeviceList);
351 if (!groupDeviceList.contains(device)) {
352 groupDeviceList.add(device);
358 public Set<Integer> getZoneIDs() {
359 return zoneGroupDeviceMap.keySet();
363 public void addCircuitList(List<Circuit> referenceCircuitList) {
364 for (Circuit circuit : referenceCircuitList) {
370 public Circuit addCircuit(Circuit circuit) {
371 addDSIDtoDSUID((AbstractGeneralDeviceInformations) circuit);
372 return circuitMap.put(circuit.getDSID(), circuit);
375 private void addDSIDtoDSUID(AbstractGeneralDeviceInformations deviceInfo) {
376 if (deviceInfo.getDSID() != null) {
377 dSUIDToDSIDMap.put(deviceInfo.getDSUID(), deviceInfo.getDSID());
382 public Circuit getCircuitByDSID(DSID dSID) {
383 return circuitMap.get(dSID);
387 public Circuit getCircuitByDSUID(String dSUID) {
388 final DSID tmp = dSUIDToDSIDMap.get(dSUID);
389 return tmp != null ? getCircuitByDSID(tmp) : null;
393 public Circuit getCircuitByDSUID(DSUID dSUID) {
394 return dSUID != null ? getCircuitByDSUID(dSUID.getValue()) : null;
398 public Circuit getCircuitByDSID(String dSID) {
399 return getCircuitByDSID(new DSID(dSID));
403 public Circuit updateCircuitConfig(Circuit newCircuit) {
404 Circuit intCircuit = circuitMap.get(newCircuit.getDSID());
405 if (intCircuit != null && !intCircuit.equals(newCircuit)) {
406 for (CachedMeteringValue meteringValue : intCircuit.getAllCachedMeteringValues()) {
407 newCircuit.addMeteringValue(meteringValue);
409 if (intCircuit.isListenerRegisterd()) {
410 newCircuit.registerDeviceStatusListener(intCircuit.getDeviceStatusListener());
413 return addCircuit(newCircuit);
417 public Circuit deleteCircuit(DSID dSID) {
418 return circuitMap.remove(dSID);
422 public Circuit deleteCircuit(String dSUID) {
423 return deleteCircuit(dSUIDToDSIDMap.get(dSUID));
427 public Map<DSID, Circuit> getCircuitMap() {
428 return new HashMap<>(circuitMap);