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.Arrays;
16 import java.util.Calendar;
17 import java.util.HashMap;
18 import java.util.LinkedList;
19 import java.util.List;
21 import java.util.Map.Entry;
22 import java.util.Objects;
23 import java.util.concurrent.CopyOnWriteArrayList;
24 import java.util.concurrent.ScheduledExecutorService;
25 import java.util.concurrent.ScheduledFuture;
26 import java.util.concurrent.TimeUnit;
28 import org.openhab.binding.digitalstrom.internal.lib.GeneralLibConstance;
29 import org.openhab.binding.digitalstrom.internal.lib.config.Config;
30 import org.openhab.binding.digitalstrom.internal.lib.event.EventListener;
31 import org.openhab.binding.digitalstrom.internal.lib.event.constants.EventNames;
32 import org.openhab.binding.digitalstrom.internal.lib.event.constants.EventResponseEnum;
33 import org.openhab.binding.digitalstrom.internal.lib.event.types.EventItem;
34 import org.openhab.binding.digitalstrom.internal.lib.listener.ConnectionListener;
35 import org.openhab.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
36 import org.openhab.binding.digitalstrom.internal.lib.listener.ManagerStatusListener;
37 import org.openhab.binding.digitalstrom.internal.lib.listener.SceneStatusListener;
38 import org.openhab.binding.digitalstrom.internal.lib.listener.TotalPowerConsumptionListener;
39 import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerStates;
40 import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerTypes;
41 import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
42 import org.openhab.binding.digitalstrom.internal.lib.manager.DeviceStatusManager;
43 import org.openhab.binding.digitalstrom.internal.lib.manager.SceneManager;
44 import org.openhab.binding.digitalstrom.internal.lib.manager.StructureManager;
45 import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.SceneReadingJobExecutor;
46 import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.SensorJobExecutor;
47 import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.SensorJob;
48 import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.impl.DeviceConsumptionSensorJob;
49 import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.impl.DeviceOutputValueSensorJob;
50 import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.impl.SceneConfigReadingJob;
51 import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.impl.SceneOutputValueReadingJob;
52 import org.openhab.binding.digitalstrom.internal.lib.serverconnection.DsAPI;
53 import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
54 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Circuit;
55 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
56 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.CachedMeteringValue;
57 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceConstants;
58 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
59 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.DeviceBinarayInputEnum;
60 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringTypeEnum;
61 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringUnitsEnum;
62 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputModeEnum;
63 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
64 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
65 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DeviceStateUpdateImpl;
66 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.impl.DeviceImpl;
67 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
68 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.ApartmentSceneEnum;
69 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.SceneEnum;
70 import org.openhab.core.common.ThreadPoolManager;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
74 import com.google.gson.JsonElement;
75 import com.google.gson.JsonObject;
78 * The {@link DeviceStatusManagerImpl} is the implementation of the {@link DeviceStatusManager}.
80 * @author Michael Ochel - Initial contribution
81 * @author Matthias Siegele - Initial contribution
83 public class DeviceStatusManagerImpl implements DeviceStatusManager {
85 private final Logger logger = LoggerFactory.getLogger(DeviceStatusManagerImpl.class);
88 * Contains all supported event-types.
90 public static final List<String> SUPPORTED_EVENTS = Arrays.asList(EventNames.DEVICE_SENSOR_VALUE,
91 EventNames.DEVICE_BINARY_INPUT_EVENT);
93 private final ScheduledExecutorService scheduler = ThreadPoolManager.getScheduledPool(Config.THREADPOOL_NAME);
94 private ScheduledFuture<?> pollingScheduler;
97 * Query to get all {@link Device}'s with more informations than {@link DsAPI#getApartmentDevices(String)}. Can be
98 * executed with {@link DsAPI#query(String, String)} or {@link DsAPI#query2(String, String)}.
100 public static final String GET_DETAILD_DEVICES = "/apartment/zones/zone0(*)/devices/*(*)/*(*)/*(*)";
102 * Query to get the last called scenes of all groups in digitalSTROM. Can be executed with
103 * {@link DsAPI#query(String, String)} or
104 * {@link DsAPI#query2(String, String)}.
106 public static final String LAST_CALL_SCENE_QUERY = "/apartment/zones/*(*)/groups/*(*)/*(*)";
108 private ConnectionManager connMan;
109 private StructureManager strucMan;
110 private SceneManager sceneMan;
111 private DsAPI digitalSTROMClient;
112 private Config config;
114 private SensorJobExecutor sensorJobExecutor;
115 private SceneReadingJobExecutor sceneJobExecutor;
116 private EventListener eventListener;
118 private final List<TrashDevice> trashDevices = new CopyOnWriteArrayList<>();
120 private long lastBinCheck = 0;
121 private ManagerStates state = ManagerStates.STOPPED;
123 private int tempConsumption = 0;
124 private int tempEnergyMeter = 0;
125 private int tempEnergyMeterWs = 0;
127 private DeviceStatusListener deviceDiscovery;
128 private TotalPowerConsumptionListener totalPowerConsumptionListener;
129 private ManagerStatusListener statusListener;
132 * Creates a new {@link DeviceStatusManagerImpl} through the given {@link Config} object, which has to be contains
133 * all needed parameters like host address, authentication data and so on. This constructor the
134 * {@link DeviceStatusManagerImpl} will be create all needed managers itself.
136 * @param config (must not be null)
138 public DeviceStatusManagerImpl(Config config) {
139 init(new ConnectionManagerImpl(config), null, null, null, null);
143 * Creates a new {@link DeviceStatusManagerImpl}. The given fields needed to create {@link ConnectionManager}
144 * through the constructor {@link ConnectionManagerImpl#ConnectionManagerImpl(String, String, String, String)}. All
145 * other needed manager will be automatically created, too.
147 * @param hostAddress (must not be null)
148 * @param user (can be null, if appToken is set)
149 * @param password (can be null, if appToken is set)
150 * @param appToken (can be null, if user and password is set)
152 public DeviceStatusManagerImpl(String hostAddress, String user, String password, String appToken) {
153 init(new ConnectionManagerImpl(hostAddress, user, password, false), null, null, null, null);
157 * Creates a new {@link DeviceStatusManagerImpl} with the given managers. If the {@link StructureManager} or
158 * {@link SceneManager} is null, they will be automatically created.
160 * @param connMan (must not be null)
161 * @param strucMan (can be null)
162 * @param sceneMan (can be null)
164 public DeviceStatusManagerImpl(ConnectionManager connMan, StructureManager strucMan, SceneManager sceneMan) {
165 init(connMan, strucMan, sceneMan, null, null);
169 * Same constructor like {@link #DeviceStatusManagerImpl(ConnectionManager, StructureManager, SceneManager)}, but a
170 * {@link ManagerStatusListener} can be set, too.
172 * @param connMan (must not be null)
173 * @param strucMan (can be null)
174 * @param sceneMan (can be null)
175 * @param statusListener (can be null)
176 * @see #DeviceStatusManagerImpl(ConnectionManager, StructureManager, SceneManager)
178 public DeviceStatusManagerImpl(ConnectionManager connMan, StructureManager strucMan, SceneManager sceneMan,
179 ManagerStatusListener statusListener) {
180 init(connMan, strucMan, sceneMan, statusListener, null);
184 * Same constructor like
185 * {@link #DeviceStatusManagerImpl(ConnectionManager, StructureManager, SceneManager, ManagerStatusListener)}, but a
186 * {@link EventListener} can be set, too.
188 * @param connMan (must not be null)
189 * @param strucMan (can be null)
190 * @param sceneMan (can be null)
191 * @param statusListener (can be null)
192 * @param eventListener (can be null)
193 * @see #DeviceStatusManagerImpl(ConnectionManager, StructureManager, SceneManager, ManagerStatusListener)
195 public DeviceStatusManagerImpl(ConnectionManager connMan, StructureManager strucMan, SceneManager sceneMan,
196 ManagerStatusListener statusListener, EventListener eventListener) {
197 init(connMan, strucMan, sceneMan, statusListener, eventListener);
201 * Creates a new {@link DeviceStatusManagerImpl} with the given {@link ConnectionManager}. The
202 * {@link StructureManager} and
203 * {@link SceneManager} will be automatically created.
205 * @param connMan (must not be null)
207 public DeviceStatusManagerImpl(ConnectionManager connMan) {
208 init(connMan, null, null, null, null);
211 private void init(ConnectionManager connMan, StructureManager strucMan, SceneManager sceneMan,
212 ManagerStatusListener statusListener, EventListener eventListener) {
213 this.connMan = connMan;
214 this.digitalSTROMClient = connMan.getDigitalSTROMAPI();
215 this.config = connMan.getConfig();
216 if (strucMan != null) {
217 this.strucMan = strucMan;
219 this.strucMan = new StructureManagerImpl();
221 if (sceneMan != null) {
222 this.sceneMan = sceneMan;
224 this.sceneMan = new SceneManagerImpl(connMan, strucMan, statusListener);
226 this.statusListener = statusListener;
227 this.eventListener = eventListener;
231 * Check and updates the {@link Device} structure, configurations and status.
233 * @author Michael Ochel - Initial contribution
234 * @author Matthias Siegele - Initial contribution
236 private class PollingRunnable implements Runnable {
237 private boolean devicesLoaded = false;
238 private long nextSensorUpdate = 0;
242 if (!getManagerState().equals(ManagerStates.RUNNING)) {
243 logger.debug("Thread started");
245 stateChanged(ManagerStates.RUNNING);
247 stateChanged(ManagerStates.INITIALIZING);
250 Map<DSID, Device> tempDeviceMap;
251 if (strucMan.getDeviceMap() != null) {
252 tempDeviceMap = strucMan.getDeviceMap();
254 tempDeviceMap = new HashMap<>();
257 List<Device> currentDeviceList = getDetailedDevices();
259 // update the current total power consumption
260 if (nextSensorUpdate <= System.currentTimeMillis()) {
262 List<Circuit> circuits = digitalSTROMClient.getApartmentCircuits(connMan.getSessionToken());
263 for (Circuit circuit : circuits) {
264 if (strucMan.getCircuitByDSID(circuit.getDSID()) != null) {
265 if (!circuit.equals(strucMan.getCircuitByDSID(circuit.getDSID()))) {
266 strucMan.updateCircuitConfig(circuit);
269 strucMan.addCircuit(circuit);
270 if (deviceDiscovery != null) {
271 deviceDiscovery.onDeviceAdded(circuit);
276 nextSensorUpdate = System.currentTimeMillis() + config.getTotalPowerUpdateInterval();
279 while (!currentDeviceList.isEmpty()) {
280 Device currentDevice = currentDeviceList.remove(0);
281 DSID currentDeviceDSID = currentDevice.getDSID();
282 Device device = tempDeviceMap.remove(currentDeviceDSID);
284 if (device != null) {
285 checkDeviceConfig(currentDevice, device);
287 if (device.isPresent()) {
288 // check device state updates
289 while (!device.isDeviceUpToDate()) {
290 DeviceStateUpdate deviceStateUpdate = device.getNextDeviceUpdateState();
291 if (deviceStateUpdate != null) {
292 switch (deviceStateUpdate.getType()) {
293 case DeviceStateUpdate.OUTPUT:
294 case DeviceStateUpdate.SLAT_ANGLE_INCREASE:
295 case DeviceStateUpdate.SLAT_ANGLE_DECREASE:
296 filterCommand(deviceStateUpdate, device);
298 case DeviceStateUpdate.UPDATE_SCENE_CONFIG:
299 case DeviceStateUpdate.UPDATE_SCENE_OUTPUT:
300 updateSceneData(device, deviceStateUpdate);
302 case DeviceStateUpdate.UPDATE_OUTPUT_VALUE:
303 if (deviceStateUpdate.getValueAsInteger() > -1) {
304 readOutputValue(device);
306 removeSensorJob(device, deviceStateUpdate);
310 sendComandsToDSS(device, deviceStateUpdate);
316 logger.debug("Found new device!");
317 if (trashDevices.isEmpty()) {
318 currentDevice.setConfig(config);
319 strucMan.addDeviceToStructure(currentDevice);
320 logger.debug("trashDevices are empty, add Device with dSID {} to the deviceMap!",
321 currentDevice.getDSID());
323 logger.debug("Search device in trashDevices.");
324 boolean found = trashDevices.removeIf(trashDevice -> {
325 if (trashDevice.getDevice().equals(currentDevice)) {
327 "Found device in trashDevices, add TrashDevice with dSID {} to the StructureManager!",
329 strucMan.addDeviceToStructure(trashDevice.getDevice());
336 strucMan.addDeviceToStructure(currentDevice);
338 "Can't find device in trashDevices, add Device with dSID: {} to the StructureManager!",
342 if (deviceDiscovery != null) {
343 // only informs discovery, if the device is an output or a sensor device
344 deviceDiscovery.onDeviceAdded(currentDevice);
345 logger.debug("inform DeviceStatusListener: {} about added device with dSID {}",
346 DeviceStatusListener.DEVICE_DISCOVERY, currentDevice.getDSID().getValue());
349 "The device discovery is not registrated, can't inform device discovery about found device.");
354 if (!devicesLoaded && strucMan.getDeviceMap() != null) {
355 if (!strucMan.getDeviceMap().values().isEmpty()) {
356 logger.debug("Devices loaded");
357 devicesLoaded = true;
358 setInizialStateWithLastCallScenes();
359 stateChanged(ManagerStates.RUNNING);
361 logger.debug("No devices found");
365 if (!sceneMan.scenesGenerated() && devicesLoaded
366 && !sceneMan.getManagerState().equals(ManagerStates.GENERATING_SCENES)) {
367 logger.debug("{}", sceneMan.getManagerState());
368 sceneMan.generateScenes();
371 for (Device device : tempDeviceMap.values()) {
372 logger.debug("Found removed devices.");
374 trashDevices.add(new TrashDevice(device));
375 DeviceStatusListener listener = device.unregisterDeviceStatusListener();
376 if (listener != null) {
377 listener.onDeviceRemoved(null);
379 strucMan.deleteDevice(device);
380 logger.debug("Add device with dSID {} to trashDevices", device.getDSID().getValue());
382 if (deviceDiscovery != null) {
383 deviceDiscovery.onDeviceRemoved(device);
384 logger.debug("inform DeviceStatusListener: {} about removed device with dSID {}",
385 DeviceStatusListener.DEVICE_DISCOVERY, device.getDSID().getValue());
388 "The device-Discovery is not registered, can't inform device discovery about removed device.");
392 if (!trashDevices.isEmpty() && (lastBinCheck + config.getBinCheckTime() < System.currentTimeMillis())) {
393 trashDevices.removeIf(trashDevice -> {
394 if (trashDevice.isTimeToDelete(Calendar.getInstance().get(Calendar.DAY_OF_YEAR))) {
395 logger.debug("Deleted trashDevice: {}", trashDevice.getDevice().getDSID().getValue());
401 lastBinCheck = System.currentTimeMillis();
405 private List<Device> getDetailedDevices() {
406 List<Device> deviceList = new LinkedList<>();
407 JsonObject result = connMan.getDigitalSTROMAPI().query2(connMan.getSessionToken(), GET_DETAILD_DEVICES);
408 if (result != null && result.isJsonObject()) {
409 if (result.getAsJsonObject().get(GeneralLibConstance.QUERY_BROADCAST_ZONE_STRING).isJsonObject()) {
410 result = result.getAsJsonObject().get(GeneralLibConstance.QUERY_BROADCAST_ZONE_STRING)
412 for (Entry<String, JsonElement> entry : result.entrySet()) {
413 if (!(entry.getKey().equals(JSONApiResponseKeysEnum.ZONE_ID.getKey())
414 && entry.getKey().equals(JSONApiResponseKeysEnum.NAME.getKey()))
415 && entry.getValue().isJsonObject()) {
416 deviceList.add(new DeviceImpl(entry.getValue().getAsJsonObject()));
424 private void filterCommand(DeviceStateUpdate deviceStateUpdate, Device device) {
425 DeviceStateUpdate intDeviceStateUpdate = deviceStateUpdate;
426 String stateUpdateType = intDeviceStateUpdate.getType();
428 if (stateUpdateType.equals(DeviceStateUpdate.SLAT_ANGLE_INCREASE)
429 || stateUpdateType.equals(DeviceStateUpdate.SLAT_ANGLE_DECREASE)) {
430 newAngle = device.getAnglePosition();
432 DeviceStateUpdate nextDeviceStateUpdate = device.getNextDeviceUpdateState();
433 while (nextDeviceStateUpdate != null && nextDeviceStateUpdate.getType().equals(stateUpdateType)) {
434 switch (stateUpdateType) {
435 case DeviceStateUpdate.OUTPUT:
436 intDeviceStateUpdate = nextDeviceStateUpdate;
437 nextDeviceStateUpdate = device.getNextDeviceUpdateState();
439 case DeviceStateUpdate.SLAT_ANGLE_INCREASE:
440 if (intDeviceStateUpdate.getValueAsInteger() == 1) {
441 newAngle = (short) (newAngle + DeviceConstants.ANGLE_STEP_SLAT);
444 case DeviceStateUpdate.SLAT_ANGLE_DECREASE:
445 if (intDeviceStateUpdate.getValueAsInteger() == 1) {
446 newAngle = (short) (newAngle - DeviceConstants.ANGLE_STEP_SLAT);
451 if (stateUpdateType.equals(DeviceStateUpdate.SLAT_ANGLE_INCREASE)
452 || stateUpdateType.equals(DeviceStateUpdate.SLAT_ANGLE_DECREASE)) {
453 if (newAngle > device.getMaxSlatAngle()) {
454 newAngle = (short) device.getMaxSlatAngle();
456 if (newAngle < device.getMinSlatAngle()) {
457 newAngle = (short) device.getMinSlatAngle();
459 if (!(stateUpdateType.equals(DeviceStateUpdate.SLAT_ANGLE_INCREASE) && checkAngleIsMinMax(device) == 1)
460 || !(stateUpdateType.equals(DeviceStateUpdate.SLAT_ANGLE_DECREASE)
461 && checkAngleIsMinMax(device) == 0)) {
462 intDeviceStateUpdate = new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE, newAngle);
465 sendComandsToDSS(device, intDeviceStateUpdate);
466 if (nextDeviceStateUpdate != null) {
467 if (DeviceStateUpdate.UPDATE_SCENE_CONFIG.equals(intDeviceStateUpdate.getType())
468 || DeviceStateUpdate.UPDATE_SCENE_OUTPUT.equals(intDeviceStateUpdate.getType())) {
469 updateSceneData(device, intDeviceStateUpdate);
471 sendComandsToDSS(device, intDeviceStateUpdate);
477 private void removeSensorJob(Device device, DeviceStateUpdate deviceStateUpdate) {
478 switch (deviceStateUpdate.getType()) {
479 case DeviceStateUpdate.UPDATE_SCENE_CONFIG:
480 if (sceneJobExecutor != null) {
481 sceneJobExecutor.removeSensorJob(device,
482 SceneConfigReadingJob.getID(device, deviceStateUpdate.getSceneId()));
485 case DeviceStateUpdate.UPDATE_SCENE_OUTPUT:
486 if (sceneJobExecutor != null) {
487 sceneJobExecutor.removeSensorJob(device,
488 SceneOutputValueReadingJob.getID(device, deviceStateUpdate.getSceneId()));
491 case DeviceStateUpdate.UPDATE_OUTPUT_VALUE:
492 if (sensorJobExecutor != null) {
493 sensorJobExecutor.removeSensorJob(device, DeviceOutputValueSensorJob.getID(device));
497 if (deviceStateUpdate.isSensorUpdateType()) {
498 if (sensorJobExecutor != null) {
499 logger.debug("remove SensorJob with ID: {}",
500 DeviceConsumptionSensorJob.getID(device, deviceStateUpdate.getTypeAsSensorEnum()));
501 sensorJobExecutor.removeSensorJob(device,
502 DeviceConsumptionSensorJob.getID(device, deviceStateUpdate.getTypeAsSensorEnum()));
508 public ManagerTypes getManagerType() {
509 return ManagerTypes.DEVICE_STATUS_MANAGER;
513 public synchronized ManagerStates getManagerState() {
517 private synchronized void stateChanged(ManagerStates state) {
518 if (statusListener != null) {
520 statusListener.onStatusChanged(ManagerTypes.DEVICE_STATUS_MANAGER, state);
525 public synchronized void start() {
526 logger.debug("start DeviceStatusManager");
527 if (pollingScheduler == null || pollingScheduler.isCancelled()) {
528 pollingScheduler = scheduler.scheduleWithFixedDelay(new PollingRunnable(), 0, config.getPollingFrequency(),
529 TimeUnit.MILLISECONDS);
530 logger.debug("start pollingScheduler");
533 if (sceneJobExecutor != null) {
534 this.sceneJobExecutor.startExecutor();
537 if (sensorJobExecutor != null) {
538 this.sensorJobExecutor.startExecutor();
540 if (eventListener != null) {
541 eventListener.addEventHandler(this);
543 eventListener = new EventListener(connMan, this);
544 eventListener.start();
549 public synchronized void stop() {
550 logger.debug("stop DeviceStatusManager");
551 stateChanged(ManagerStates.STOPPED);
552 if (sceneMan != null) {
555 if (pollingScheduler != null && !pollingScheduler.isCancelled()) {
556 pollingScheduler.cancel(true);
557 pollingScheduler = null;
558 logger.debug("stop pollingScheduler");
560 if (sceneJobExecutor != null) {
561 this.sceneJobExecutor.shutdown();
563 if (sensorJobExecutor != null) {
564 this.sensorJobExecutor.shutdown();
566 if (eventListener != null) {
567 eventListener.removeEventHandler(this);
572 * The {@link TrashDevice} saves not present {@link Device}'s, but at this point not deleted from the
573 * digitalSTROM-System, temporary to get back the configuration of the {@link Device}'s faster.
575 * @author Michael Ochel - Initial contribution
576 * @author Matthias Siegele - Initial contribution
578 private class TrashDevice {
579 private final Device device;
580 private final int timestamp;
583 * Creates a new {@link TrashDevice}.
585 * @param device to put in {@link TrashDevice}
587 public TrashDevice(Device device) {
588 this.device = device;
589 this.timestamp = Calendar.getInstance().get(Calendar.DAY_OF_YEAR);
593 * Returns the saved {@link Device}.
597 public Device getDevice() {
602 * Returns true if the time for the {@link TrashDevice} is over and it can be deleted.
604 * @param dayOfYear day of the current year
605 * @return true = time to delete | false = not time to delete
607 public boolean isTimeToDelete(int dayOfYear) {
608 return this.timestamp + config.getTrashDeviceDeleteTime() <= dayOfYear;
612 public boolean equals(Object object) {
613 return object instanceof TrashDevice td ? this.device.getDSID().equals(td.getDevice().getDSID()) : false;
617 private void checkDeviceConfig(Device newDevice, Device internalDevice) {
618 if (newDevice == null || internalDevice == null) {
621 // check device availability has changed and informs the deviceStatusListener about the change.
623 // The device is not availability for the digitalSTROM-Server, it has not been deleted and therefore it is set
626 // An alternate algorithm is responsible for deletion.
627 if (!Objects.equals(newDevice.isPresent(), internalDevice.isPresent())) {
628 internalDevice.setIsPresent(newDevice.isPresent());
630 if (newDevice.getMeterDSID() != null && !newDevice.getMeterDSID().equals(internalDevice.getMeterDSID())) {
631 internalDevice.setMeterDSID(newDevice.getMeterDSID().getValue());
633 if (newDevice.getFunctionalColorGroup() != null
634 && !newDevice.getFunctionalColorGroup().equals(internalDevice.getFunctionalColorGroup())) {
635 internalDevice.setFunctionalColorGroup(newDevice.getFunctionalColorGroup());
637 if (newDevice.getName() != null && !newDevice.getName().equals(internalDevice.getName())) {
638 internalDevice.setName(newDevice.getName());
640 if (newDevice.getOutputMode() != null && !newDevice.getOutputMode().equals(internalDevice.getOutputMode())) {
641 if (deviceDiscovery != null) {
642 if (OutputModeEnum.DISABLED.equals(internalDevice.getOutputMode())
643 || OutputModeEnum.outputModeIsTemperationControlled(internalDevice.getOutputMode())) {
644 deviceDiscovery.onDeviceAdded(newDevice);
646 if (OutputModeEnum.DISABLED.equals(newDevice.getOutputMode())
647 || OutputModeEnum.outputModeIsTemperationControlled(newDevice.getOutputMode())) {
648 deviceDiscovery.onDeviceRemoved(newDevice);
651 internalDevice.setOutputMode(newDevice.getOutputMode());
653 if (!newDevice.getBinaryInputs().equals(internalDevice.getBinaryInputs())) {
654 internalDevice.setBinaryInputs(newDevice.getBinaryInputs());
656 strucMan.updateDevice(newDevice);
659 private long lastSceneCall = 0;
660 private long sleepTime = 0;
663 public synchronized void sendSceneComandsToDSS(InternalScene scene, boolean call_undo) {
665 if (lastSceneCall + 1000 > System.currentTimeMillis()) {
666 sleepTime = System.currentTimeMillis() - lastSceneCall;
668 Thread.sleep(sleepTime);
669 } catch (InterruptedException e) {
670 logger.debug("An InterruptedException occurred", e);
673 lastSceneCall = System.currentTimeMillis();
674 boolean requestSuccessful = false;
675 if (scene.getZoneID() == 0) {
677 logger.debug("{} {} {}", scene.getGroupID(), scene.getSceneID(),
678 ApartmentSceneEnum.getApartmentScene(scene.getSceneID()));
679 requestSuccessful = this.digitalSTROMClient.callApartmentScene(connMan.getSessionToken(),
680 scene.getGroupID(), null, ApartmentSceneEnum.getApartmentScene(scene.getSceneID()), false);
682 requestSuccessful = this.digitalSTROMClient.undoApartmentScene(connMan.getSessionToken(),
683 scene.getGroupID(), null, ApartmentSceneEnum.getApartmentScene(scene.getSceneID()));
687 requestSuccessful = this.digitalSTROMClient.callZoneScene(connMan.getSessionToken(),
688 scene.getZoneID(), null, scene.getGroupID(), null, SceneEnum.getScene(scene.getSceneID()),
691 requestSuccessful = this.digitalSTROMClient.undoZoneScene(connMan.getSessionToken(),
692 scene.getZoneID(), null, scene.getGroupID(), null, SceneEnum.getScene(scene.getSceneID()));
696 logger.debug("Was the scene call succsessful?: {}", requestSuccessful);
697 if (requestSuccessful) {
698 this.sceneMan.addEcho(scene.getID());
700 scene.activateScene();
702 scene.deactivateScene();
709 public synchronized void sendStopComandsToDSS(final Device device) {
710 scheduler.execute(new Runnable() {
714 if (digitalSTROMClient.callDeviceScene(connMan.getSessionToken(), device.getDSID(), null, null,
715 SceneEnum.STOP, true)) {
716 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.STOP.getSceneNumber());
717 readOutputValue(device);
723 private void readOutputValue(Device device) {
724 short outputIndex = DeviceConstants.DEVICE_SENSOR_OUTPUT;
725 if (device.isShade()) {
726 outputIndex = DeviceConstants.DEVICE_SENSOR_SLAT_POSITION_OUTPUT;
729 int outputValue = this.digitalSTROMClient.getDeviceOutputValue(connMan.getSessionToken(), device.getDSID(),
730 null, null, outputIndex);
731 if (outputValue != -1) {
732 if (!device.isShade()) {
733 device.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT, outputValue));
735 device.updateInternalDeviceState(
736 new DeviceStateUpdateImpl(DeviceStateUpdate.SLATPOSITION, outputValue));
737 if (device.isBlind()) {
738 outputValue = this.digitalSTROMClient.getDeviceOutputValue(connMan.getSessionToken(),
739 device.getDSID(), null, null, DeviceConstants.DEVICE_SENSOR_SLAT_ANGLE_OUTPUT);
740 device.updateInternalDeviceState(
741 new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE, outputValue));
748 * Updates the {@link Device} status of the given {@link Device} with handling outstanding commands, which are saved
749 * as {@link DeviceStateUpdate}'s.
751 * @param device to update
753 public synchronized void updateDevice(Device device) {
754 logger.debug("Check device updates");
755 // check device state updates
756 while (!device.isDeviceUpToDate()) {
757 DeviceStateUpdate deviceStateUpdate = device.getNextDeviceUpdateState();
758 if (deviceStateUpdate != null) {
759 if (!DeviceStateUpdate.OUTPUT.equals(deviceStateUpdate.getType())) {
760 if (DeviceStateUpdate.UPDATE_SCENE_CONFIG.equals(deviceStateUpdate.getType())
761 || DeviceStateUpdate.UPDATE_SCENE_OUTPUT.equals(deviceStateUpdate.getType())) {
762 updateSceneData(device, deviceStateUpdate);
764 sendComandsToDSS(device, deviceStateUpdate);
767 DeviceStateUpdate nextDeviceStateUpdate = device.getNextDeviceUpdateState();
768 while (nextDeviceStateUpdate != null
769 && DeviceStateUpdate.OUTPUT.equals(nextDeviceStateUpdate.getType())) {
770 deviceStateUpdate = nextDeviceStateUpdate;
771 nextDeviceStateUpdate = device.getNextDeviceUpdateState();
773 sendComandsToDSS(device, deviceStateUpdate);
774 if (nextDeviceStateUpdate != null) {
775 if (DeviceStateUpdate.UPDATE_SCENE_CONFIG.equals(deviceStateUpdate.getType())
776 || DeviceStateUpdate.UPDATE_SCENE_OUTPUT.equals(deviceStateUpdate.getType())) {
777 updateSceneData(device, deviceStateUpdate);
779 sendComandsToDSS(device, deviceStateUpdate);
788 * Checks the output value of a {@link Device} and return 0, if the output value or slat position is min and 1, if
789 * the output value or slat position is max, otherwise it returns -1.
792 * @return 0 = output value is min, 1 device value is min, otherwise -1
794 private short checkIsAllreadyMinMax(Device device) {
795 if (device.isShade()) {
796 if (device.getSlatPosition() == device.getMaxSlatPosition()) {
797 if (device.isBlind()) {
798 if (device.getAnglePosition() == device.getMaxSlatAngle()) {
806 if (device.getSlatPosition() == device.getMinSlatPosition()) {
807 if (device.isBlind()) {
808 if (device.getAnglePosition() == device.getMinSlatAngle()) {
817 if (device.getOutputValue() == device.getMaxOutputValue()) {
820 if (device.getOutputValue() == device.getMinOutputValue() || device.getOutputValue() <= 0) {
828 * Checks the angle value of a {@link Device} and return 0, if the angle value is min and 1, if the angle value is
829 * max, otherwise it returns -1.
832 * @return 0 = angle value is min, 1 angle value is min, otherwise -1
834 private short checkAngleIsMinMax(Device device) {
835 if (device.getAnglePosition() == device.getMaxSlatAngle()) {
838 if (device.getAnglePosition() == device.getMinSlatAngle()) {
845 public synchronized void sendComandsToDSS(Device device, DeviceStateUpdate deviceStateUpdate) {
846 boolean requestSuccsessful = false;
847 boolean commandHasNoEffect = false;
848 if (deviceStateUpdate != null) {
849 if (deviceStateUpdate.isSensorUpdateType()) {
850 SensorEnum sensorType = deviceStateUpdate.getTypeAsSensorEnum();
851 if (deviceStateUpdate.getValueAsInteger() == 0) {
852 updateSensorData(new DeviceConsumptionSensorJob(device, sensorType),
853 device.getPowerSensorRefreshPriority(sensorType));
855 } else if (deviceStateUpdate.getValueAsInteger() < 0) {
856 removeSensorJob(device, deviceStateUpdate);
859 int consumption = this.digitalSTROMClient.getDeviceSensorValue(connMan.getSessionToken(),
860 device.getDSID(), null, null, device.getSensorIndex(sensorType));
861 if (consumption >= 0) {
862 device.setDeviceSensorDsValueBySensorJob(sensorType, consumption);
863 requestSuccsessful = true;
867 switch (deviceStateUpdate.getType()) {
868 case DeviceStateUpdate.OUTPUT_DECREASE:
869 case DeviceStateUpdate.SLAT_DECREASE:
870 if (checkIsAllreadyMinMax(device) != 0) {
871 requestSuccsessful = digitalSTROMClient.decreaseValue(connMan.getSessionToken(),
872 device.getDSID(), null, null);
873 if (requestSuccsessful) {
874 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.DECREMENT.getSceneNumber());
877 commandHasNoEffect = true;
880 case DeviceStateUpdate.OUTPUT_INCREASE:
881 case DeviceStateUpdate.SLAT_INCREASE:
882 if (checkIsAllreadyMinMax(device) != 1) {
883 requestSuccsessful = digitalSTROMClient.increaseValue(connMan.getSessionToken(),
884 device.getDSID(), null, null);
885 if (requestSuccsessful) {
886 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.INCREMENT.getSceneNumber());
889 commandHasNoEffect = true;
892 case DeviceStateUpdate.OUTPUT:
893 if (device.getOutputValue() != deviceStateUpdate.getValueAsInteger()) {
894 requestSuccsessful = digitalSTROMClient.setDeviceValue(connMan.getSessionToken(),
895 device.getDSID(), null, null, deviceStateUpdate.getValueAsInteger());
897 commandHasNoEffect = true;
900 case DeviceStateUpdate.OPEN_CLOSE:
901 case DeviceStateUpdate.ON_OFF:
902 if (deviceStateUpdate.getValueAsInteger() > 0) {
903 if (checkIsAllreadyMinMax(device) != 1) {
904 requestSuccsessful = digitalSTROMClient.turnDeviceOn(connMan.getSessionToken(),
905 device.getDSID(), null, null);
906 if (requestSuccsessful) {
907 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.MAXIMUM.getSceneNumber());
910 commandHasNoEffect = true;
913 if (checkIsAllreadyMinMax(device) != 0) {
914 requestSuccsessful = digitalSTROMClient.turnDeviceOff(connMan.getSessionToken(),
915 device.getDSID(), null, null);
916 if (requestSuccsessful) {
917 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.MINIMUM.getSceneNumber());
920 commandHasNoEffect = true;
924 case DeviceStateUpdate.SLATPOSITION:
925 if (device.getSlatPosition() != deviceStateUpdate.getValueAsInteger()) {
926 requestSuccsessful = digitalSTROMClient.setDeviceOutputValue(connMan.getSessionToken(),
927 device.getDSID(), null, null, DeviceConstants.DEVICE_SENSOR_SLAT_POSITION_OUTPUT,
928 deviceStateUpdate.getValueAsInteger());
930 commandHasNoEffect = true;
933 case DeviceStateUpdate.SLAT_STOP:
934 this.sendStopComandsToDSS(device);
936 case DeviceStateUpdate.SLAT_MOVE:
937 if (deviceStateUpdate.getValueAsInteger() > 0) {
938 requestSuccsessful = digitalSTROMClient.turnDeviceOn(connMan.getSessionToken(),
939 device.getDSID(), null, null);
940 if (requestSuccsessful) {
941 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.MAXIMUM.getSceneNumber());
944 requestSuccsessful = digitalSTROMClient.turnDeviceOff(connMan.getSessionToken(),
945 device.getDSID(), null, null);
946 if (requestSuccsessful) {
947 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.MINIMUM.getSceneNumber());
949 if (sensorJobExecutor != null) {
950 sensorJobExecutor.removeSensorJobs(device);
954 case DeviceStateUpdate.UPDATE_CALL_SCENE:
955 if (SceneEnum.getScene((short) deviceStateUpdate.getValue()) != null) {
956 requestSuccsessful = digitalSTROMClient.callDeviceScene(connMan.getSessionToken(),
957 device.getDSID(), null, null,
958 SceneEnum.getScene((short) deviceStateUpdate.getValue()), true);
961 case DeviceStateUpdate.UPDATE_UNDO_SCENE:
962 if (SceneEnum.getScene((short) deviceStateUpdate.getValue()) != null) {
963 requestSuccsessful = digitalSTROMClient.undoDeviceScene(connMan.getSessionToken(),
964 device.getDSID(), null, null,
965 SceneEnum.getScene((short) deviceStateUpdate.getValue()));
968 case DeviceStateUpdate.SLAT_ANGLE_DECREASE:
969 // By UPDATE_SLAT_ANGLE_DECREASE, UPDATE_SLAT_ANGLE_INCREASE with value unequal 1 which will
970 // handled in the pollingRunnable and UPDATE_OPEN_CLOSE_ANGLE the value will be set without
971 // checking, because it was triggered by setting the slat position.
972 requestSuccsessful = true;
974 case DeviceStateUpdate.SLAT_ANGLE_INCREASE:
975 requestSuccsessful = true;
977 case DeviceStateUpdate.OPEN_CLOSE_ANGLE:
978 requestSuccsessful = true;
980 case DeviceStateUpdate.SLAT_ANGLE:
981 if (device.getAnglePosition() != deviceStateUpdate.getValueAsInteger()) {
982 requestSuccsessful = digitalSTROMClient.setDeviceOutputValue(connMan.getSessionToken(),
983 device.getDSID(), null, null, DeviceConstants.DEVICE_SENSOR_SLAT_ANGLE_OUTPUT,
984 deviceStateUpdate.getValueAsInteger());
986 commandHasNoEffect = true;
989 case DeviceStateUpdate.REFRESH_OUTPUT:
990 readOutputValue(device);
991 logger.debug("Inizalize output value reading for device with dSID {}.",
992 device.getDSID().getValue());
998 if (commandHasNoEffect) {
999 logger.debug("Command {} for device with dSID {} not send to dSS, because it has no effect!",
1000 deviceStateUpdate.getType(), device.getDSID().getValue());
1003 if (requestSuccsessful) {
1004 logger.debug("Send {} command to dSS and updateInternalDeviceState for device with dSID {}.",
1005 deviceStateUpdate.getType(), device.getDSID().getValue());
1006 device.updateInternalDeviceState(deviceStateUpdate);
1008 logger.debug("Can't send {} command for device with dSID {} to dSS!", deviceStateUpdate.getType(),
1009 device.getDSID().getValue());
1015 public void updateSensorData(SensorJob sensorJob, String priority) {
1016 if (sensorJobExecutor == null) {
1017 sensorJobExecutor = new SensorJobExecutor(connMan);
1018 this.sensorJobExecutor.startExecutor();
1020 if (sensorJob != null && priority != null) {
1022 case Config.REFRESH_PRIORITY_HIGH:
1023 sensorJobExecutor.addHighPriorityJob(sensorJob);
1025 case Config.REFRESH_PRIORITY_MEDIUM:
1026 sensorJobExecutor.addMediumPriorityJob(sensorJob);
1028 case Config.REFRESH_PRIORITY_LOW:
1029 sensorJobExecutor.addLowPriorityJob(sensorJob);
1033 long prio = Long.parseLong(priority);
1034 sensorJobExecutor.addPriorityJob(sensorJob, prio);
1035 } catch (NumberFormatException e) {
1036 logger.debug("Sensor data update priority do not exist! Please check the input!");
1040 logger.debug("Add new sensorJob {} with priority: {} to sensorJobExecuter", sensorJob.toString(), priority);
1045 public void updateSceneData(Device device, DeviceStateUpdate deviceStateUpdate) {
1046 if (sceneJobExecutor == null) {
1047 sceneJobExecutor = new SceneReadingJobExecutor(connMan);
1048 this.sceneJobExecutor.startExecutor();
1051 if (deviceStateUpdate != null) {
1052 if (deviceStateUpdate.getScenePriority() > -1) {
1053 if (deviceStateUpdate.getType().equals(DeviceStateUpdate.UPDATE_SCENE_OUTPUT)) {
1054 sceneJobExecutor.addPriorityJob(
1055 new SceneOutputValueReadingJob(device, deviceStateUpdate.getSceneId()),
1056 deviceStateUpdate.getScenePriority().longValue());
1058 sceneJobExecutor.addPriorityJob(new SceneConfigReadingJob(device, deviceStateUpdate.getSceneId()),
1059 deviceStateUpdate.getScenePriority().longValue());
1061 if (deviceStateUpdate.getScenePriority() == 0) {
1062 updateSensorData(new DeviceOutputValueSensorJob(device), "0");
1064 logger.debug("Add new sceneReadingJob with priority: {} to SceneReadingJobExecuter",
1065 deviceStateUpdate.getScenePriority());
1067 removeSensorJob(device, deviceStateUpdate);
1073 public void registerDeviceListener(DeviceStatusListener deviceListener) {
1074 if (deviceListener != null) {
1075 String id = deviceListener.getDeviceStatusListenerID();
1076 if (id.equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
1077 this.deviceDiscovery = deviceListener;
1078 logger.debug("register Device-Discovery ");
1079 for (Device device : strucMan.getDeviceMap().values()) {
1080 deviceDiscovery.onDeviceAdded(device);
1082 for (Circuit circuit : strucMan.getCircuitMap().values()) {
1083 deviceDiscovery.onDeviceAdded(circuit);
1086 Device intDevice = strucMan.getDeviceByDSID(deviceListener.getDeviceStatusListenerID());
1087 if (intDevice != null) {
1088 logger.debug("register DeviceListener with id: {} to Device ", id);
1089 intDevice.registerDeviceStatusListener(deviceListener);
1091 Circuit intCircuit = strucMan
1092 .getCircuitByDSID(new DSID(deviceListener.getDeviceStatusListenerID()));
1093 if (intCircuit != null) {
1094 logger.debug("register DeviceListener with id: {} to Circuit ", id);
1095 intCircuit.registerDeviceStatusListener(deviceListener);
1097 deviceListener.onDeviceRemoved(null);
1105 public void unregisterDeviceListener(DeviceStatusListener deviceListener) {
1106 if (deviceListener != null) {
1107 String id = deviceListener.getDeviceStatusListenerID();
1108 logger.debug("unregister DeviceListener with id: {}", id);
1109 if (id.equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
1110 this.deviceDiscovery = null;
1112 Device intDevice = strucMan.getDeviceByDSID(deviceListener.getDeviceStatusListenerID());
1113 if (intDevice != null) {
1114 intDevice.unregisterDeviceStatusListener();
1116 Circuit intCircuit = strucMan
1117 .getCircuitByDSID(new DSID(deviceListener.getDeviceStatusListenerID()));
1118 if (intCircuit != null) {
1119 intCircuit.unregisterDeviceStatusListener();
1120 if (deviceDiscovery != null) {
1121 deviceDiscovery.onDeviceAdded(intCircuit);
1130 public void removeDevice(String dSID) {
1131 Device intDevice = strucMan.getDeviceByDSID(dSID);
1132 if (intDevice != null) {
1133 strucMan.deleteDevice(intDevice);
1134 trashDevices.add(new TrashDevice(intDevice));
1139 public void registerTotalPowerConsumptionListener(TotalPowerConsumptionListener totalPowerConsumptionListener) {
1140 this.totalPowerConsumptionListener = totalPowerConsumptionListener;
1144 public void unregisterTotalPowerConsumptionListener() {
1145 this.totalPowerConsumptionListener = null;
1149 public void registerSceneListener(SceneStatusListener sceneListener) {
1150 this.sceneMan.registerSceneListener(sceneListener);
1154 public void unregisterSceneListener(SceneStatusListener sceneListener) {
1155 this.sceneMan.unregisterSceneListener(sceneListener);
1159 public void registerStatusListener(ManagerStatusListener statusListener) {
1160 this.statusListener = statusListener;
1161 this.sceneMan.registerStatusListener(statusListener);
1165 public void unregisterStatusListener() {
1166 this.statusListener = null;
1167 this.sceneMan.unregisterStatusListener();
1171 public void registerConnectionListener(ConnectionListener connectionListener) {
1172 this.connMan.registerConnectionListener(connectionListener);
1176 public void unregisterConnectionListener() {
1177 this.connMan.unregisterConnectionListener();
1181 public int getTotalPowerConsumption() {
1182 List<CachedMeteringValue> cachedConsumptionMeteringValues = digitalSTROMClient
1183 .getLatest(connMan.getSessionToken(), MeteringTypeEnum.CONSUMPTION, DsAPI.ALL_METERS, null);
1184 if (cachedConsumptionMeteringValues != null) {
1185 tempConsumption = 0;
1186 for (CachedMeteringValue value : cachedConsumptionMeteringValues) {
1187 tempConsumption += value.getValue();
1188 if (strucMan.getCircuitByDSID(value.getDsid()) != null) {
1189 strucMan.getCircuitByDSID(value.getDsid()).addMeteringValue(value);
1190 } else if (strucMan.getCircuitByDSUID(value.getDsuid()) != null) {
1191 strucMan.getCircuitByDSUID(value.getDsuid()).addMeteringValue(value);
1195 return tempConsumption;
1198 private void getMeterData() {
1199 int val = getTotalPowerConsumption();
1200 if (totalPowerConsumptionListener != null) {
1201 totalPowerConsumptionListener.onTotalPowerConsumptionChanged(val);
1203 val = getTotalEnergyMeterValue();
1204 if (totalPowerConsumptionListener != null) {
1205 totalPowerConsumptionListener.onEnergyMeterValueChanged(val);
1210 public int getTotalEnergyMeterValue() {
1211 List<CachedMeteringValue> cachedEnergyMeteringValues = digitalSTROMClient.getLatest(connMan.getSessionToken(),
1212 MeteringTypeEnum.ENERGY, DsAPI.ALL_METERS, null);
1213 if (cachedEnergyMeteringValues != null) {
1214 tempEnergyMeter = 0;
1215 for (CachedMeteringValue value : cachedEnergyMeteringValues) {
1216 tempEnergyMeter += value.getValue();
1217 if (strucMan.getCircuitByDSID(value.getDsid()) != null) {
1218 strucMan.getCircuitByDSID(value.getDsid()).addMeteringValue(value);
1219 } else if (strucMan.getCircuitByDSUID(value.getDsuid()) != null) {
1220 strucMan.getCircuitByDSUID(value.getDsuid()).addMeteringValue(value);
1224 return tempEnergyMeter;
1228 public int getTotalEnergyMeterWsValue() {
1229 List<CachedMeteringValue> cachedEnergyMeteringValues = digitalSTROMClient.getLatest(connMan.getSessionToken(),
1230 MeteringTypeEnum.ENERGY, DsAPI.ALL_METERS, MeteringUnitsEnum.WS);
1231 if (cachedEnergyMeteringValues != null) {
1232 tempEnergyMeterWs = 0;
1233 for (CachedMeteringValue value : cachedEnergyMeteringValues) {
1234 tempEnergyMeterWs += value.getValue();
1235 if (strucMan.getCircuitByDSID(value.getDsid()) != null) {
1236 strucMan.getCircuitByDSID(value.getDsid()).addMeteringValue(value);
1237 } else if (strucMan.getCircuitByDSUID(value.getDsuid()) != null) {
1238 strucMan.getCircuitByDSUID(value.getDsuid()).addMeteringValue(value);
1242 return tempEnergyMeterWs;
1245 private void setInizialStateWithLastCallScenes() {
1246 if (sceneMan == null) {
1249 JsonObject response = connMan.getDigitalSTROMAPI().query2(connMan.getSessionToken(), LAST_CALL_SCENE_QUERY);
1250 if (!response.isJsonObject()) {
1253 for (Entry<String, JsonElement> entry : response.entrySet()) {
1254 if (!entry.getValue().isJsonObject()) {
1257 JsonObject zone = entry.getValue().getAsJsonObject();
1261 if (zone.get(JSONApiResponseKeysEnum.ZONE_ID.getKey()) != null) {
1262 zoneID = zone.get(JSONApiResponseKeysEnum.ZONE_ID.getKey()).getAsInt();
1264 for (Entry<String, JsonElement> groupEntry : zone.entrySet()) {
1265 if (groupEntry.getKey().startsWith("group") && groupEntry.getValue().isJsonObject()) {
1266 JsonObject group = groupEntry.getValue().getAsJsonObject();
1267 if (group.get(JSONApiResponseKeysEnum.DEVICES.getKey()) != null) {
1268 if (group.get(JSONApiResponseKeysEnum.GROUP.getKey()) != null) {
1269 groupID = group.get(JSONApiResponseKeysEnum.GROUP.getKey()).getAsShort();
1271 if (group.get(JSONApiResponseKeysEnum.LAST_CALL_SCENE.getKey()) != null) {
1272 sceneID = group.get(JSONApiResponseKeysEnum.LAST_CALL_SCENE.getKey()).getAsShort();
1274 if (zoneID > -1 && groupID > -1 && sceneID > -1) {
1275 logger.debug("initial state, call scene {}-{}-{}", zoneID, groupID, sceneID);
1276 sceneMan.callInternalSceneWithoutDiscovery(zoneID, groupID, sceneID);
1285 public void handleEvent(EventItem eventItem) {
1287 if (EventNames.DEVICE_SENSOR_VALUE.equals(eventItem.getName())
1288 || EventNames.DEVICE_BINARY_INPUT_EVENT.equals(eventItem.getName())) {
1289 logger.debug("Detect {} eventItem = {}", eventItem.getName(), eventItem.toString());
1290 Device dev = getDeviceOfEvent(eventItem);
1292 if (EventNames.DEVICE_SENSOR_VALUE.equals(eventItem.getName())) {
1293 dev.setDeviceSensorByEvent(eventItem);
1295 DeviceBinarayInputEnum binaryInputType = DeviceBinarayInputEnum.getdeviceBinarayInput(Short
1296 .parseShort(eventItem.getProperties().getOrDefault(EventResponseEnum.INPUT_TYPE, "")));
1297 Short newState = Short
1298 .parseShort(eventItem.getProperties().getOrDefault(EventResponseEnum.INPUT_STATE, ""));
1299 if (binaryInputType != null) {
1300 dev.setBinaryInputState(binaryInputType, newState);
1305 } catch (NumberFormatException e) {
1306 logger.debug("Unexpected missing or invalid number while handling event", e);
1310 private Device getDeviceOfEvent(EventItem eventItem) {
1311 if (eventItem.getSource().get(EventResponseEnum.DSID) != null) {
1312 String dSID = eventItem.getSource().get(EventResponseEnum.DSID);
1313 Device dev = strucMan.getDeviceByDSID(dSID);
1315 dev = strucMan.getDeviceByDSUID(dSID);
1323 public List<String> getSupportedEvents() {
1324 return SUPPORTED_EVENTS;
1328 public boolean supportsEvent(String eventName) {
1329 return SUPPORTED_EVENTS.contains(eventName);
1333 public String getUID() {
1334 return getClass().getName();
1338 public void setEventListener(EventListener eventListener) {
1339 if (this.eventListener != null) {
1340 this.eventListener.removeEventHandler(this);
1342 this.eventListener = eventListener;
1346 public void unsetEventListener(EventListener eventListener) {
1347 if (this.eventListener != null) {
1348 this.eventListener.removeEventHandler(this);
1350 this.eventListener = null;