]> git.basschouten.com Git - openhab-addons.git/blob
7faab1044981a7c7c93b584c2285c80f1f55906a
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.digitalstrom.internal.lib.manager.impl;
14
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.LinkedList;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21
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.structure.devices.AbstractGeneralDeviceInformations;
25 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Circuit;
26 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
27 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.CachedMeteringValue;
28 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
29 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSUID;
30
31 import com.google.gson.JsonArray;
32 import com.google.gson.JsonObject;
33
34 /**
35  * The {@link StructureManagerImpl} is the implementation of the {@link StructureManager}.
36  *
37  * @author Michael Ochel - Initial contribution
38  * @author Matthias Siegele - Initial contribution
39  */
40 public class StructureManagerImpl implements StructureManager {
41
42     private class ZoneGroupsNameAndIDMap {
43         public final String zoneName;
44         public final int zoneID;
45
46         private final Map<Short, String> groupIdNames;
47         private final Map<String, Short> groupNameIds;
48
49         public ZoneGroupsNameAndIDMap(final int zoneID, final String zoneName, JsonArray groups) {
50             this.zoneID = zoneID;
51             this.zoneName = zoneName;
52
53             groupIdNames = new HashMap<>(groups.size());
54             groupNameIds = new HashMap<>(groups.size());
55             for (int k = 0; k < groups.size(); k++) {
56                 short groupID = ((JsonObject) groups.get(k)).get("group").getAsShort();
57                 String groupName = ((JsonObject) groups.get(k)).get("name").getAsString();
58                 groupIdNames.put(groupID, groupName);
59                 groupNameIds.put(groupName, groupID);
60             }
61         }
62
63         public String getGroupName(Short groupID) {
64             return groupIdNames.get(groupID);
65         }
66
67         public short getGroupID(String groupName) {
68             final Short tmp = groupNameIds.get(groupName);
69             return tmp != null ? tmp : -1;
70         }
71     }
72
73     /**
74      * Query to get all zone and group names. Can be executed with {@link DsAPI#query(String, String)} or
75      * {@link DsAPI#query2(String, String)}.
76      */
77     public static final String ZONE_GROUP_NAMES = "/apartment/zones/*(ZoneID,name)/groups/*(group,name)";
78
79     private final Map<Integer, Map<Short, List<Device>>> zoneGroupDeviceMap = Collections
80             .synchronizedMap(new HashMap<>());
81     private final Map<DSID, Device> deviceMap = Collections.synchronizedMap(new HashMap<>());
82     private final Map<DSID, Circuit> circuitMap = Collections.synchronizedMap(new HashMap<>());
83     private final Map<String, DSID> dSUIDToDSIDMap = Collections.synchronizedMap(new HashMap<>());
84
85     private Map<Integer, ZoneGroupsNameAndIDMap> zoneGroupIdNameMap;
86     private Map<String, ZoneGroupsNameAndIDMap> zoneGroupNameIdMap;
87
88     /**
89      * Creates a new {@link StructureManagerImpl} with the {@link Device}s of the given referenceDeviceList.
90      *
91      * @param referenceDeviceList to add
92      */
93     public StructureManagerImpl(List<Device> referenceDeviceList) {
94         handleStructure(referenceDeviceList);
95     }
96
97     /**
98      * Creates a new {@link StructureManagerImpl} with the {@link Device}s of the given referenceDeviceList.
99      *
100      * @param referenceDeviceList to add
101      * @param referenceCircuitList to add
102      */
103     public StructureManagerImpl(List<Device> referenceDeviceList, List<Circuit> referenceCircuitList) {
104         handleStructure(referenceDeviceList);
105         addCircuitList(referenceCircuitList);
106     }
107
108     /**
109      * Creates a new {@link StructureManagerImpl} without {@link Device}s.
110      */
111     public StructureManagerImpl() {
112     }
113
114     @Override
115     public boolean generateZoneGroupNames(ConnectionManager connectionManager) {
116         JsonObject resultJsonObj = connectionManager.getDigitalSTROMAPI().query(connectionManager.getSessionToken(),
117                 ZONE_GROUP_NAMES);
118         if (resultJsonObj != null && resultJsonObj.get("zones") instanceof JsonArray) {
119             JsonArray zones = (JsonArray) resultJsonObj.get("zones");
120             if (zoneGroupIdNameMap == null) {
121                 zoneGroupIdNameMap = new HashMap<>(zones.size());
122                 zoneGroupNameIdMap = new HashMap<>(zones.size());
123             }
124             if (zones != null) {
125                 for (int i = 0; i < zones.size(); i++) {
126                     if (((JsonObject) zones.get(i)).get("groups") instanceof JsonArray) {
127                         JsonArray groups = (JsonArray) ((JsonObject) zones.get(i)).get("groups");
128                         ZoneGroupsNameAndIDMap zoneGoupIdNameMap = new ZoneGroupsNameAndIDMap(
129                                 ((JsonObject) zones.get(i)).get("ZoneID").getAsInt(),
130                                 ((JsonObject) zones.get(i)).get("name").getAsString(), groups);
131
132                         zoneGroupIdNameMap.put(zoneGoupIdNameMap.zoneID, zoneGoupIdNameMap);
133                         zoneGroupNameIdMap.put(zoneGoupIdNameMap.zoneName, zoneGoupIdNameMap);
134                     }
135                 }
136             }
137         }
138         return true;
139     }
140
141     @Override
142     public String getZoneName(int zoneID) {
143         if (zoneGroupIdNameMap == null) {
144             return null;
145         }
146         final ZoneGroupsNameAndIDMap tmp = zoneGroupIdNameMap.get(zoneID);
147         return tmp != null ? tmp.zoneName : null;
148     }
149
150     @Override
151     public String getZoneGroupName(int zoneID, short groupID) {
152         if (zoneGroupIdNameMap == null) {
153             return null;
154         }
155         final ZoneGroupsNameAndIDMap tmp = zoneGroupIdNameMap.get(zoneID);
156         return tmp != null ? tmp.getGroupName(groupID) : null;
157     }
158
159     @Override
160     public int getZoneId(String zoneName) {
161         if (zoneGroupNameIdMap == null) {
162             return -1;
163         }
164         final ZoneGroupsNameAndIDMap tmp = zoneGroupNameIdMap.get(zoneName);
165         return tmp != null ? tmp.zoneID : -1;
166     }
167
168     @Override
169     public boolean checkZoneID(int zoneID) {
170         return getGroupsFromZoneX(zoneID) != null;
171     }
172
173     @Override
174     public boolean checkZoneGroupID(int zoneID, short groupID) {
175         final Map<Short, List<Device>> tmp = getGroupsFromZoneX(zoneID);
176         return tmp != null ? tmp.get(groupID) != null : false;
177     }
178
179     @Override
180     public short getZoneGroupId(String zoneName, String groupName) {
181         if (zoneGroupNameIdMap == null) {
182             return -1;
183         }
184         final ZoneGroupsNameAndIDMap tmp = zoneGroupNameIdMap.get(zoneName);
185         return tmp != null ? tmp.getGroupID(groupName) : -1;
186     }
187
188     @Override
189     public Map<DSID, Device> getDeviceMap() {
190         return new HashMap<>(deviceMap);
191     }
192
193     private void putDeviceToHashMap(Device device) {
194         if (device.getDSID() != null) {
195             deviceMap.put(device.getDSID(), device);
196             addDSIDtoDSUID((AbstractGeneralDeviceInformations) device);
197         }
198     }
199
200     /**
201      * This method build the digitalSTROM structure as a {@link HashMap} with the zone id as key
202      * and a {@link HashMap} as value. This {@link HashMap} has the group id as key and a {@link List}
203      * with all digitalSTROM {@link Device}s.<br>
204      * <br>
205      * <b>Note:</b> the zone id 0 is the broadcast address and the group id 0, too.
206      */
207     private void handleStructure(List<Device> deviceList) {
208         Map<Short, List<Device>> groupXHashMap = new HashMap<>();
209         groupXHashMap.put((short) 0, deviceList);
210
211         zoneGroupDeviceMap.put(0, groupXHashMap);
212
213         for (Device device : deviceList) {
214             addDeviceToStructure(device);
215         }
216     }
217
218     @Override
219     public Map<DSID, Device> getDeviceHashMapReference() {
220         return deviceMap;
221     }
222
223     @Override
224     public Map<Integer, Map<Short, List<Device>>> getStructureReference() {
225         return zoneGroupDeviceMap;
226     }
227
228     @Override
229     public Map<Short, List<Device>> getGroupsFromZoneX(int zoneID) {
230         return zoneGroupDeviceMap.get(zoneID);
231     }
232
233     @Override
234     public List<Device> getReferenceDeviceListFromZoneXGroupX(int zoneID, short groupID) {
235         final Map<Short, List<Device>> tmp = getGroupsFromZoneX(zoneID);
236         return tmp != null ? tmp.get(groupID) : null;
237     }
238
239     @Override
240     public Device getDeviceByDSID(String dSID) {
241         return getDeviceByDSID(new DSID(dSID));
242     }
243
244     @Override
245     public Device getDeviceByDSID(DSID dSID) {
246         return deviceMap.get(dSID);
247     }
248
249     @Override
250     public Device getDeviceByDSUID(String dSUID) {
251         final DSID tmp = dSUIDToDSIDMap.get(dSUID);
252         return tmp != null ? getDeviceByDSID(tmp) : null;
253     }
254
255     @Override
256     public void updateDevice(int oldZone, List<Short> oldGroups, Device device) {
257         int intOldZoneID = oldZone;
258         if (intOldZoneID == -1) {
259             intOldZoneID = device.getZoneId();
260         }
261         deleteDevice(intOldZoneID, oldGroups, device);
262         addDeviceToStructure(device);
263     }
264
265     @Override
266     public void updateDevice(Device device) {
267         if (device != null) {
268             int oldZoneID = -1;
269             List<Short> oldGroups = null;
270             Device internalDevice = this.getDeviceByDSID(device.getDSID());
271             if (internalDevice != null) {
272                 if (device.getZoneId() != internalDevice.getZoneId()) {
273                     oldZoneID = internalDevice.getZoneId();
274                     internalDevice.setZoneId(device.getZoneId());
275                 }
276
277                 if (!internalDevice.getGroups().equals(device.getGroups())) {
278                     oldGroups = internalDevice.getGroups();
279                     internalDevice.setGroups(device.getGroups());
280                 }
281
282                 if (deleteDevice(oldZoneID, oldGroups, internalDevice)) {
283                     addDeviceToStructure(internalDevice);
284                 }
285             }
286         }
287     }
288
289     @Override
290     public void deleteDevice(Device device) {
291         dSUIDToDSIDMap.remove(device.getDSUID());
292         deviceMap.remove(device.getDSID());
293         deleteDevice(device.getZoneId(), device.getGroups(), device);
294     }
295
296     private boolean deleteDevice(int zoneID, List<Short> groups, Device device) {
297         List<Short> intGroups = groups;
298         int intZoneID = zoneID;
299         if (intGroups != null || intZoneID >= 0) {
300             if (intGroups == null) {
301                 intGroups = device.getGroups();
302             }
303             if (intZoneID == -1) {
304                 intZoneID = device.getZoneId();
305             }
306             for (Short groupID : intGroups) {
307                 List<Device> deviceList = getReferenceDeviceListFromZoneXGroupX(intZoneID, groupID);
308                 if (deviceList != null) {
309                     deviceList.remove(device);
310                 }
311                 deviceList = getReferenceDeviceListFromZoneXGroupX(0, groupID);
312                 if (deviceList != null) {
313                     deviceList.remove(device);
314                 }
315             }
316             return true;
317         }
318         return false;
319     }
320
321     @Override
322     public void addDeviceToStructure(Device device) {
323         putDeviceToHashMap(device);
324
325         addDevicetoZoneXGroupX(0, (short) 0, device);
326         int zoneID = device.getZoneId();
327         addDevicetoZoneXGroupX(zoneID, (short) 0, device);
328
329         for (Short groupID : device.getGroups()) {
330             addDevicetoZoneXGroupX(zoneID, groupID, device);
331
332             if (groupID <= 16) {
333                 addDevicetoZoneXGroupX(0, groupID, device);
334             }
335         }
336     }
337
338     private void addDevicetoZoneXGroupX(int zoneID, short groupID, Device device) {
339         Map<Short, List<Device>> groupXHashMap = zoneGroupDeviceMap.get(zoneID);
340         if (groupXHashMap == null) {
341             groupXHashMap = new HashMap<>();
342             zoneGroupDeviceMap.put(zoneID, groupXHashMap);
343         }
344         List<Device> groupDeviceList = groupXHashMap.get(groupID);
345         if (groupDeviceList == null) {
346             groupDeviceList = new LinkedList<>();
347             groupDeviceList.add(device);
348             groupXHashMap.put(groupID, groupDeviceList);
349         } else {
350             if (!groupDeviceList.contains(device)) {
351                 groupDeviceList.add(device);
352             }
353         }
354     }
355
356     @Override
357     public Set<Integer> getZoneIDs() {
358         return zoneGroupDeviceMap.keySet();
359     }
360
361     @Override
362     public void addCircuitList(List<Circuit> referenceCircuitList) {
363         for (Circuit circuit : referenceCircuitList) {
364             addCircuit(circuit);
365         }
366     }
367
368     @Override
369     public Circuit addCircuit(Circuit circuit) {
370         addDSIDtoDSUID((AbstractGeneralDeviceInformations) circuit);
371         return circuitMap.put(circuit.getDSID(), circuit);
372     }
373
374     private void addDSIDtoDSUID(AbstractGeneralDeviceInformations deviceInfo) {
375         if (deviceInfo.getDSID() != null) {
376             dSUIDToDSIDMap.put(deviceInfo.getDSUID(), deviceInfo.getDSID());
377         }
378     }
379
380     @Override
381     public Circuit getCircuitByDSID(DSID dSID) {
382         return circuitMap.get(dSID);
383     }
384
385     @Override
386     public Circuit getCircuitByDSUID(String dSUID) {
387         final DSID tmp = dSUIDToDSIDMap.get(dSUID);
388         return tmp != null ? getCircuitByDSID(tmp) : null;
389     }
390
391     @Override
392     public Circuit getCircuitByDSUID(DSUID dSUID) {
393         return dSUID != null ? getCircuitByDSUID(dSUID.getValue()) : null;
394     }
395
396     @Override
397     public Circuit getCircuitByDSID(String dSID) {
398         return getCircuitByDSID(new DSID(dSID));
399     }
400
401     @Override
402     public Circuit updateCircuitConfig(Circuit newCircuit) {
403         Circuit intCircuit = circuitMap.get(newCircuit.getDSID());
404         if (intCircuit != null && !intCircuit.equals(newCircuit)) {
405             for (CachedMeteringValue meteringValue : intCircuit.getAllCachedMeteringValues()) {
406                 newCircuit.addMeteringValue(meteringValue);
407             }
408             if (intCircuit.isListenerRegisterd()) {
409                 newCircuit.registerDeviceStatusListener(intCircuit.getDeviceStatusListener());
410             }
411         }
412         return addCircuit(newCircuit);
413     }
414
415     @Override
416     public Circuit deleteCircuit(DSID dSID) {
417         return circuitMap.remove(dSID);
418     }
419
420     @Override
421     public Circuit deleteCircuit(String dSUID) {
422         return deleteCircuit(dSUIDToDSIDMap.get(dSUID));
423     }
424
425     @Override
426     public Map<DSID, Circuit> getCircuitMap() {
427         return new HashMap<>(circuitMap);
428     }
429 }