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
614 ? this.device.getDSID().equals(((TrashDevice) object).getDevice().getDSID())
619 private void checkDeviceConfig(Device newDevice, Device internalDevice) {
620 if (newDevice == null || internalDevice == null) {
623 // check device availability has changed and informs the deviceStatusListener about the change.
625 // The device is not availability for the digitalSTROM-Server, it has not been deleted and therefore it is set
628 // An alternate algorithm is responsible for deletion.
629 if (!Objects.equals(newDevice.isPresent(), internalDevice.isPresent())) {
630 internalDevice.setIsPresent(newDevice.isPresent());
632 if (newDevice.getMeterDSID() != null && !newDevice.getMeterDSID().equals(internalDevice.getMeterDSID())) {
633 internalDevice.setMeterDSID(newDevice.getMeterDSID().getValue());
635 if (newDevice.getFunctionalColorGroup() != null
636 && !newDevice.getFunctionalColorGroup().equals(internalDevice.getFunctionalColorGroup())) {
637 internalDevice.setFunctionalColorGroup(newDevice.getFunctionalColorGroup());
639 if (newDevice.getName() != null && !newDevice.getName().equals(internalDevice.getName())) {
640 internalDevice.setName(newDevice.getName());
642 if (newDevice.getOutputMode() != null && !newDevice.getOutputMode().equals(internalDevice.getOutputMode())) {
643 if (deviceDiscovery != null) {
644 if (OutputModeEnum.DISABLED.equals(internalDevice.getOutputMode())
645 || OutputModeEnum.outputModeIsTemperationControlled(internalDevice.getOutputMode())) {
646 deviceDiscovery.onDeviceAdded(newDevice);
648 if (OutputModeEnum.DISABLED.equals(newDevice.getOutputMode())
649 || OutputModeEnum.outputModeIsTemperationControlled(newDevice.getOutputMode())) {
650 deviceDiscovery.onDeviceRemoved(newDevice);
653 internalDevice.setOutputMode(newDevice.getOutputMode());
655 if (!newDevice.getBinaryInputs().equals(internalDevice.getBinaryInputs())) {
656 internalDevice.setBinaryInputs(newDevice.getBinaryInputs());
658 strucMan.updateDevice(newDevice);
661 private long lastSceneCall = 0;
662 private long sleepTime = 0;
665 public synchronized void sendSceneComandsToDSS(InternalScene scene, boolean call_undo) {
667 if (lastSceneCall + 1000 > System.currentTimeMillis()) {
668 sleepTime = System.currentTimeMillis() - lastSceneCall;
670 Thread.sleep(sleepTime);
671 } catch (InterruptedException e) {
672 logger.debug("An InterruptedException occurred", e);
675 lastSceneCall = System.currentTimeMillis();
676 boolean requestSuccessful = false;
677 if (scene.getZoneID() == 0) {
679 logger.debug("{} {} {}", scene.getGroupID(), scene.getSceneID(),
680 ApartmentSceneEnum.getApartmentScene(scene.getSceneID()));
681 requestSuccessful = this.digitalSTROMClient.callApartmentScene(connMan.getSessionToken(),
682 scene.getGroupID(), null, ApartmentSceneEnum.getApartmentScene(scene.getSceneID()), false);
684 requestSuccessful = this.digitalSTROMClient.undoApartmentScene(connMan.getSessionToken(),
685 scene.getGroupID(), null, ApartmentSceneEnum.getApartmentScene(scene.getSceneID()));
689 requestSuccessful = this.digitalSTROMClient.callZoneScene(connMan.getSessionToken(),
690 scene.getZoneID(), null, scene.getGroupID(), null, SceneEnum.getScene(scene.getSceneID()),
693 requestSuccessful = this.digitalSTROMClient.undoZoneScene(connMan.getSessionToken(),
694 scene.getZoneID(), null, scene.getGroupID(), null, SceneEnum.getScene(scene.getSceneID()));
698 logger.debug("Was the scene call succsessful?: {}", requestSuccessful);
699 if (requestSuccessful) {
700 this.sceneMan.addEcho(scene.getID());
702 scene.activateScene();
704 scene.deactivateScene();
711 public synchronized void sendStopComandsToDSS(final Device device) {
712 scheduler.execute(new Runnable() {
716 if (digitalSTROMClient.callDeviceScene(connMan.getSessionToken(), device.getDSID(), null, null,
717 SceneEnum.STOP, true)) {
718 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.STOP.getSceneNumber());
719 readOutputValue(device);
725 private void readOutputValue(Device device) {
726 short outputIndex = DeviceConstants.DEVICE_SENSOR_OUTPUT;
727 if (device.isShade()) {
728 outputIndex = DeviceConstants.DEVICE_SENSOR_SLAT_POSITION_OUTPUT;
731 int outputValue = this.digitalSTROMClient.getDeviceOutputValue(connMan.getSessionToken(), device.getDSID(),
732 null, null, outputIndex);
733 if (outputValue != -1) {
734 if (!device.isShade()) {
735 device.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT, outputValue));
737 device.updateInternalDeviceState(
738 new DeviceStateUpdateImpl(DeviceStateUpdate.SLATPOSITION, outputValue));
739 if (device.isBlind()) {
740 outputValue = this.digitalSTROMClient.getDeviceOutputValue(connMan.getSessionToken(),
741 device.getDSID(), null, null, DeviceConstants.DEVICE_SENSOR_SLAT_ANGLE_OUTPUT);
742 device.updateInternalDeviceState(
743 new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE, outputValue));
750 * Updates the {@link Device} status of the given {@link Device} with handling outstanding commands, which are saved
751 * as {@link DeviceStateUpdate}'s.
753 * @param device to update
755 public synchronized void updateDevice(Device device) {
756 logger.debug("Check device updates");
757 // check device state updates
758 while (!device.isDeviceUpToDate()) {
759 DeviceStateUpdate deviceStateUpdate = device.getNextDeviceUpdateState();
760 if (deviceStateUpdate != null) {
761 if (!DeviceStateUpdate.OUTPUT.equals(deviceStateUpdate.getType())) {
762 if (DeviceStateUpdate.UPDATE_SCENE_CONFIG.equals(deviceStateUpdate.getType())
763 || DeviceStateUpdate.UPDATE_SCENE_OUTPUT.equals(deviceStateUpdate.getType())) {
764 updateSceneData(device, deviceStateUpdate);
766 sendComandsToDSS(device, deviceStateUpdate);
769 DeviceStateUpdate nextDeviceStateUpdate = device.getNextDeviceUpdateState();
770 while (nextDeviceStateUpdate != null
771 && DeviceStateUpdate.OUTPUT.equals(nextDeviceStateUpdate.getType())) {
772 deviceStateUpdate = nextDeviceStateUpdate;
773 nextDeviceStateUpdate = device.getNextDeviceUpdateState();
775 sendComandsToDSS(device, deviceStateUpdate);
776 if (nextDeviceStateUpdate != null) {
777 if (DeviceStateUpdate.UPDATE_SCENE_CONFIG.equals(deviceStateUpdate.getType())
778 || DeviceStateUpdate.UPDATE_SCENE_OUTPUT.equals(deviceStateUpdate.getType())) {
779 updateSceneData(device, deviceStateUpdate);
781 sendComandsToDSS(device, deviceStateUpdate);
790 * Checks the output value of a {@link Device} and return 0, if the output value or slat position is min and 1, if
791 * the output value or slat position is max, otherwise it returns -1.
794 * @return 0 = output value is min, 1 device value is min, otherwise -1
796 private short checkIsAllreadyMinMax(Device device) {
797 if (device.isShade()) {
798 if (device.getSlatPosition() == device.getMaxSlatPosition()) {
799 if (device.isBlind()) {
800 if (device.getAnglePosition() == device.getMaxSlatAngle()) {
808 if (device.getSlatPosition() == device.getMinSlatPosition()) {
809 if (device.isBlind()) {
810 if (device.getAnglePosition() == device.getMinSlatAngle()) {
819 if (device.getOutputValue() == device.getMaxOutputValue()) {
822 if (device.getOutputValue() == device.getMinOutputValue() || device.getOutputValue() <= 0) {
830 * Checks the angle value of a {@link Device} and return 0, if the angle value is min and 1, if the angle value is
831 * max, otherwise it returns -1.
834 * @return 0 = angle value is min, 1 angle value is min, otherwise -1
836 private short checkAngleIsMinMax(Device device) {
837 if (device.getAnglePosition() == device.getMaxSlatAngle()) {
840 if (device.getAnglePosition() == device.getMinSlatAngle()) {
847 public synchronized void sendComandsToDSS(Device device, DeviceStateUpdate deviceStateUpdate) {
848 boolean requestSuccsessful = false;
849 boolean commandHasNoEffect = false;
850 if (deviceStateUpdate != null) {
851 if (deviceStateUpdate.isSensorUpdateType()) {
852 SensorEnum sensorType = deviceStateUpdate.getTypeAsSensorEnum();
853 if (deviceStateUpdate.getValueAsInteger() == 0) {
854 updateSensorData(new DeviceConsumptionSensorJob(device, sensorType),
855 device.getPowerSensorRefreshPriority(sensorType));
857 } else if (deviceStateUpdate.getValueAsInteger() < 0) {
858 removeSensorJob(device, deviceStateUpdate);
861 int consumption = this.digitalSTROMClient.getDeviceSensorValue(connMan.getSessionToken(),
862 device.getDSID(), null, null, device.getSensorIndex(sensorType));
863 if (consumption >= 0) {
864 device.setDeviceSensorDsValueBySensorJob(sensorType, consumption);
865 requestSuccsessful = true;
869 switch (deviceStateUpdate.getType()) {
870 case DeviceStateUpdate.OUTPUT_DECREASE:
871 case DeviceStateUpdate.SLAT_DECREASE:
872 if (checkIsAllreadyMinMax(device) != 0) {
873 requestSuccsessful = digitalSTROMClient.decreaseValue(connMan.getSessionToken(),
874 device.getDSID(), null, null);
875 if (requestSuccsessful) {
876 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.DECREMENT.getSceneNumber());
879 commandHasNoEffect = true;
882 case DeviceStateUpdate.OUTPUT_INCREASE:
883 case DeviceStateUpdate.SLAT_INCREASE:
884 if (checkIsAllreadyMinMax(device) != 1) {
885 requestSuccsessful = digitalSTROMClient.increaseValue(connMan.getSessionToken(),
886 device.getDSID(), null, null);
887 if (requestSuccsessful) {
888 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.INCREMENT.getSceneNumber());
891 commandHasNoEffect = true;
894 case DeviceStateUpdate.OUTPUT:
895 if (device.getOutputValue() != deviceStateUpdate.getValueAsInteger()) {
896 requestSuccsessful = digitalSTROMClient.setDeviceValue(connMan.getSessionToken(),
897 device.getDSID(), null, null, deviceStateUpdate.getValueAsInteger());
899 commandHasNoEffect = true;
902 case DeviceStateUpdate.OPEN_CLOSE:
903 case DeviceStateUpdate.ON_OFF:
904 if (deviceStateUpdate.getValueAsInteger() > 0) {
905 if (checkIsAllreadyMinMax(device) != 1) {
906 requestSuccsessful = digitalSTROMClient.turnDeviceOn(connMan.getSessionToken(),
907 device.getDSID(), null, null);
908 if (requestSuccsessful) {
909 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.MAXIMUM.getSceneNumber());
912 commandHasNoEffect = true;
915 if (checkIsAllreadyMinMax(device) != 0) {
916 requestSuccsessful = digitalSTROMClient.turnDeviceOff(connMan.getSessionToken(),
917 device.getDSID(), null, null);
918 if (requestSuccsessful) {
919 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.MINIMUM.getSceneNumber());
922 commandHasNoEffect = true;
926 case DeviceStateUpdate.SLATPOSITION:
927 if (device.getSlatPosition() != deviceStateUpdate.getValueAsInteger()) {
928 requestSuccsessful = digitalSTROMClient.setDeviceOutputValue(connMan.getSessionToken(),
929 device.getDSID(), null, null, DeviceConstants.DEVICE_SENSOR_SLAT_POSITION_OUTPUT,
930 deviceStateUpdate.getValueAsInteger());
932 commandHasNoEffect = true;
935 case DeviceStateUpdate.SLAT_STOP:
936 this.sendStopComandsToDSS(device);
938 case DeviceStateUpdate.SLAT_MOVE:
939 if (deviceStateUpdate.getValueAsInteger() > 0) {
940 requestSuccsessful = digitalSTROMClient.turnDeviceOn(connMan.getSessionToken(),
941 device.getDSID(), null, null);
942 if (requestSuccsessful) {
943 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.MAXIMUM.getSceneNumber());
946 requestSuccsessful = digitalSTROMClient.turnDeviceOff(connMan.getSessionToken(),
947 device.getDSID(), null, null);
948 if (requestSuccsessful) {
949 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.MINIMUM.getSceneNumber());
951 if (sensorJobExecutor != null) {
952 sensorJobExecutor.removeSensorJobs(device);
956 case DeviceStateUpdate.UPDATE_CALL_SCENE:
957 if (SceneEnum.getScene((short) deviceStateUpdate.getValue()) != null) {
958 requestSuccsessful = digitalSTROMClient.callDeviceScene(connMan.getSessionToken(),
959 device.getDSID(), null, null,
960 SceneEnum.getScene((short) deviceStateUpdate.getValue()), true);
963 case DeviceStateUpdate.UPDATE_UNDO_SCENE:
964 if (SceneEnum.getScene((short) deviceStateUpdate.getValue()) != null) {
965 requestSuccsessful = digitalSTROMClient.undoDeviceScene(connMan.getSessionToken(),
966 device.getDSID(), null, null,
967 SceneEnum.getScene((short) deviceStateUpdate.getValue()));
970 case DeviceStateUpdate.SLAT_ANGLE_DECREASE:
971 // By UPDATE_SLAT_ANGLE_DECREASE, UPDATE_SLAT_ANGLE_INCREASE with value unequal 1 which will
972 // handled in the pollingRunnable and UPDATE_OPEN_CLOSE_ANGLE the value will be set without
973 // checking, because it was triggered by setting the slat position.
974 requestSuccsessful = true;
976 case DeviceStateUpdate.SLAT_ANGLE_INCREASE:
977 requestSuccsessful = true;
979 case DeviceStateUpdate.OPEN_CLOSE_ANGLE:
980 requestSuccsessful = true;
982 case DeviceStateUpdate.SLAT_ANGLE:
983 if (device.getAnglePosition() != deviceStateUpdate.getValueAsInteger()) {
984 requestSuccsessful = digitalSTROMClient.setDeviceOutputValue(connMan.getSessionToken(),
985 device.getDSID(), null, null, DeviceConstants.DEVICE_SENSOR_SLAT_ANGLE_OUTPUT,
986 deviceStateUpdate.getValueAsInteger());
988 commandHasNoEffect = true;
991 case DeviceStateUpdate.REFRESH_OUTPUT:
992 readOutputValue(device);
993 logger.debug("Inizalize output value reading for device with dSID {}.",
994 device.getDSID().getValue());
1000 if (commandHasNoEffect) {
1001 logger.debug("Command {} for device with dSID {} not send to dSS, because it has no effect!",
1002 deviceStateUpdate.getType(), device.getDSID().getValue());
1005 if (requestSuccsessful) {
1006 logger.debug("Send {} command to dSS and updateInternalDeviceState for device with dSID {}.",
1007 deviceStateUpdate.getType(), device.getDSID().getValue());
1008 device.updateInternalDeviceState(deviceStateUpdate);
1010 logger.debug("Can't send {} command for device with dSID {} to dSS!", deviceStateUpdate.getType(),
1011 device.getDSID().getValue());
1017 public void updateSensorData(SensorJob sensorJob, String priority) {
1018 if (sensorJobExecutor == null) {
1019 sensorJobExecutor = new SensorJobExecutor(connMan);
1020 this.sensorJobExecutor.startExecutor();
1022 if (sensorJob != null && priority != null) {
1024 case Config.REFRESH_PRIORITY_HIGH:
1025 sensorJobExecutor.addHighPriorityJob(sensorJob);
1027 case Config.REFRESH_PRIORITY_MEDIUM:
1028 sensorJobExecutor.addMediumPriorityJob(sensorJob);
1030 case Config.REFRESH_PRIORITY_LOW:
1031 sensorJobExecutor.addLowPriorityJob(sensorJob);
1035 long prio = Long.parseLong(priority);
1036 sensorJobExecutor.addPriorityJob(sensorJob, prio);
1037 } catch (NumberFormatException e) {
1038 logger.debug("Sensor data update priority do not exist! Please check the input!");
1042 logger.debug("Add new sensorJob {} with priority: {} to sensorJobExecuter", sensorJob.toString(), priority);
1047 public void updateSceneData(Device device, DeviceStateUpdate deviceStateUpdate) {
1048 if (sceneJobExecutor == null) {
1049 sceneJobExecutor = new SceneReadingJobExecutor(connMan);
1050 this.sceneJobExecutor.startExecutor();
1053 if (deviceStateUpdate != null) {
1054 if (deviceStateUpdate.getScenePriority() > -1) {
1055 if (deviceStateUpdate.getType().equals(DeviceStateUpdate.UPDATE_SCENE_OUTPUT)) {
1056 sceneJobExecutor.addPriorityJob(
1057 new SceneOutputValueReadingJob(device, deviceStateUpdate.getSceneId()),
1058 deviceStateUpdate.getScenePriority().longValue());
1060 sceneJobExecutor.addPriorityJob(new SceneConfigReadingJob(device, deviceStateUpdate.getSceneId()),
1061 deviceStateUpdate.getScenePriority().longValue());
1063 if (deviceStateUpdate.getScenePriority() == 0) {
1064 updateSensorData(new DeviceOutputValueSensorJob(device), "0");
1066 logger.debug("Add new sceneReadingJob with priority: {} to SceneReadingJobExecuter",
1067 deviceStateUpdate.getScenePriority());
1069 removeSensorJob(device, deviceStateUpdate);
1075 public void registerDeviceListener(DeviceStatusListener deviceListener) {
1076 if (deviceListener != null) {
1077 String id = deviceListener.getDeviceStatusListenerID();
1078 if (id.equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
1079 this.deviceDiscovery = deviceListener;
1080 logger.debug("register Device-Discovery ");
1081 for (Device device : strucMan.getDeviceMap().values()) {
1082 deviceDiscovery.onDeviceAdded(device);
1084 for (Circuit circuit : strucMan.getCircuitMap().values()) {
1085 deviceDiscovery.onDeviceAdded(circuit);
1088 Device intDevice = strucMan.getDeviceByDSID(deviceListener.getDeviceStatusListenerID());
1089 if (intDevice != null) {
1090 logger.debug("register DeviceListener with id: {} to Device ", id);
1091 intDevice.registerDeviceStatusListener(deviceListener);
1093 Circuit intCircuit = strucMan
1094 .getCircuitByDSID(new DSID(deviceListener.getDeviceStatusListenerID()));
1095 if (intCircuit != null) {
1096 logger.debug("register DeviceListener with id: {} to Circuit ", id);
1097 intCircuit.registerDeviceStatusListener(deviceListener);
1099 deviceListener.onDeviceRemoved(null);
1107 public void unregisterDeviceListener(DeviceStatusListener deviceListener) {
1108 if (deviceListener != null) {
1109 String id = deviceListener.getDeviceStatusListenerID();
1110 logger.debug("unregister DeviceListener with id: {}", id);
1111 if (id.equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
1112 this.deviceDiscovery = null;
1114 Device intDevice = strucMan.getDeviceByDSID(deviceListener.getDeviceStatusListenerID());
1115 if (intDevice != null) {
1116 intDevice.unregisterDeviceStatusListener();
1118 Circuit intCircuit = strucMan
1119 .getCircuitByDSID(new DSID(deviceListener.getDeviceStatusListenerID()));
1120 if (intCircuit != null) {
1121 intCircuit.unregisterDeviceStatusListener();
1122 if (deviceDiscovery != null) {
1123 deviceDiscovery.onDeviceAdded(intCircuit);
1132 public void removeDevice(String dSID) {
1133 Device intDevice = strucMan.getDeviceByDSID(dSID);
1134 if (intDevice != null) {
1135 strucMan.deleteDevice(intDevice);
1136 trashDevices.add(new TrashDevice(intDevice));
1141 public void registerTotalPowerConsumptionListener(TotalPowerConsumptionListener totalPowerConsumptionListener) {
1142 this.totalPowerConsumptionListener = totalPowerConsumptionListener;
1146 public void unregisterTotalPowerConsumptionListener() {
1147 this.totalPowerConsumptionListener = null;
1151 public void registerSceneListener(SceneStatusListener sceneListener) {
1152 this.sceneMan.registerSceneListener(sceneListener);
1156 public void unregisterSceneListener(SceneStatusListener sceneListener) {
1157 this.sceneMan.unregisterSceneListener(sceneListener);
1161 public void registerStatusListener(ManagerStatusListener statusListener) {
1162 this.statusListener = statusListener;
1163 this.sceneMan.registerStatusListener(statusListener);
1167 public void unregisterStatusListener() {
1168 this.statusListener = null;
1169 this.sceneMan.unregisterStatusListener();
1173 public void registerConnectionListener(ConnectionListener connectionListener) {
1174 this.connMan.registerConnectionListener(connectionListener);
1178 public void unregisterConnectionListener() {
1179 this.connMan.unregisterConnectionListener();
1183 public int getTotalPowerConsumption() {
1184 List<CachedMeteringValue> cachedConsumptionMeteringValues = digitalSTROMClient
1185 .getLatest(connMan.getSessionToken(), MeteringTypeEnum.CONSUMPTION, DsAPI.ALL_METERS, null);
1186 if (cachedConsumptionMeteringValues != null) {
1187 tempConsumption = 0;
1188 for (CachedMeteringValue value : cachedConsumptionMeteringValues) {
1189 tempConsumption += value.getValue();
1190 if (strucMan.getCircuitByDSID(value.getDsid()) != null) {
1191 strucMan.getCircuitByDSID(value.getDsid()).addMeteringValue(value);
1192 } else if (strucMan.getCircuitByDSUID(value.getDsuid()) != null) {
1193 strucMan.getCircuitByDSUID(value.getDsuid()).addMeteringValue(value);
1197 return tempConsumption;
1200 private void getMeterData() {
1201 int val = getTotalPowerConsumption();
1202 if (totalPowerConsumptionListener != null) {
1203 totalPowerConsumptionListener.onTotalPowerConsumptionChanged(val);
1205 val = getTotalEnergyMeterValue();
1206 if (totalPowerConsumptionListener != null) {
1207 totalPowerConsumptionListener.onEnergyMeterValueChanged(val);
1212 public int getTotalEnergyMeterValue() {
1213 List<CachedMeteringValue> cachedEnergyMeteringValues = digitalSTROMClient.getLatest(connMan.getSessionToken(),
1214 MeteringTypeEnum.ENERGY, DsAPI.ALL_METERS, null);
1215 if (cachedEnergyMeteringValues != null) {
1216 tempEnergyMeter = 0;
1217 for (CachedMeteringValue value : cachedEnergyMeteringValues) {
1218 tempEnergyMeter += value.getValue();
1219 if (strucMan.getCircuitByDSID(value.getDsid()) != null) {
1220 strucMan.getCircuitByDSID(value.getDsid()).addMeteringValue(value);
1221 } else if (strucMan.getCircuitByDSUID(value.getDsuid()) != null) {
1222 strucMan.getCircuitByDSUID(value.getDsuid()).addMeteringValue(value);
1226 return tempEnergyMeter;
1230 public int getTotalEnergyMeterWsValue() {
1231 List<CachedMeteringValue> cachedEnergyMeteringValues = digitalSTROMClient.getLatest(connMan.getSessionToken(),
1232 MeteringTypeEnum.ENERGY, DsAPI.ALL_METERS, MeteringUnitsEnum.WS);
1233 if (cachedEnergyMeteringValues != null) {
1234 tempEnergyMeterWs = 0;
1235 for (CachedMeteringValue value : cachedEnergyMeteringValues) {
1236 tempEnergyMeterWs += value.getValue();
1237 if (strucMan.getCircuitByDSID(value.getDsid()) != null) {
1238 strucMan.getCircuitByDSID(value.getDsid()).addMeteringValue(value);
1239 } else if (strucMan.getCircuitByDSUID(value.getDsuid()) != null) {
1240 strucMan.getCircuitByDSUID(value.getDsuid()).addMeteringValue(value);
1244 return tempEnergyMeterWs;
1247 private void setInizialStateWithLastCallScenes() {
1248 if (sceneMan == null) {
1251 JsonObject response = connMan.getDigitalSTROMAPI().query2(connMan.getSessionToken(), LAST_CALL_SCENE_QUERY);
1252 if (!response.isJsonObject()) {
1255 for (Entry<String, JsonElement> entry : response.entrySet()) {
1256 if (!entry.getValue().isJsonObject()) {
1259 JsonObject zone = entry.getValue().getAsJsonObject();
1263 if (zone.get(JSONApiResponseKeysEnum.ZONE_ID.getKey()) != null) {
1264 zoneID = zone.get(JSONApiResponseKeysEnum.ZONE_ID.getKey()).getAsInt();
1266 for (Entry<String, JsonElement> groupEntry : zone.entrySet()) {
1267 if (groupEntry.getKey().startsWith("group") && groupEntry.getValue().isJsonObject()) {
1268 JsonObject group = groupEntry.getValue().getAsJsonObject();
1269 if (group.get(JSONApiResponseKeysEnum.DEVICES.getKey()) != null) {
1270 if (group.get(JSONApiResponseKeysEnum.GROUP.getKey()) != null) {
1271 groupID = group.get(JSONApiResponseKeysEnum.GROUP.getKey()).getAsShort();
1273 if (group.get(JSONApiResponseKeysEnum.LAST_CALL_SCENE.getKey()) != null) {
1274 sceneID = group.get(JSONApiResponseKeysEnum.LAST_CALL_SCENE.getKey()).getAsShort();
1276 if (zoneID > -1 && groupID > -1 && sceneID > -1) {
1277 logger.debug("initial state, call scene {}-{}-{}", zoneID, groupID, sceneID);
1278 sceneMan.callInternalSceneWithoutDiscovery(zoneID, groupID, sceneID);
1287 public void handleEvent(EventItem eventItem) {
1289 if (EventNames.DEVICE_SENSOR_VALUE.equals(eventItem.getName())
1290 || EventNames.DEVICE_BINARY_INPUT_EVENT.equals(eventItem.getName())) {
1291 logger.debug("Detect {} eventItem = {}", eventItem.getName(), eventItem.toString());
1292 Device dev = getDeviceOfEvent(eventItem);
1294 if (EventNames.DEVICE_SENSOR_VALUE.equals(eventItem.getName())) {
1295 dev.setDeviceSensorByEvent(eventItem);
1297 DeviceBinarayInputEnum binaryInputType = DeviceBinarayInputEnum.getdeviceBinarayInput(Short
1298 .parseShort(eventItem.getProperties().getOrDefault(EventResponseEnum.INPUT_TYPE, "")));
1299 Short newState = Short
1300 .parseShort(eventItem.getProperties().getOrDefault(EventResponseEnum.INPUT_STATE, ""));
1301 if (binaryInputType != null) {
1302 dev.setBinaryInputState(binaryInputType, newState);
1307 } catch (NumberFormatException e) {
1308 logger.debug("Unexpected missing or invalid number while handling event", e);
1312 private Device getDeviceOfEvent(EventItem eventItem) {
1313 if (eventItem.getSource().get(EventResponseEnum.DSID) != null) {
1314 String dSID = eventItem.getSource().get(EventResponseEnum.DSID);
1315 Device dev = strucMan.getDeviceByDSID(dSID);
1317 dev = strucMan.getDeviceByDSUID(dSID);
1325 public List<String> getSupportedEvents() {
1326 return SUPPORTED_EVENTS;
1330 public boolean supportsEvent(String eventName) {
1331 return SUPPORTED_EVENTS.contains(eventName);
1335 public String getUID() {
1336 return getClass().getName();
1340 public void setEventListener(EventListener eventListener) {
1341 if (this.eventListener != null) {
1342 this.eventListener.removeEventHandler(this);
1344 this.eventListener = eventListener;
1348 public void unsetEventListener(EventListener eventListener) {
1349 if (this.eventListener != null) {
1350 this.eventListener.removeEventHandler(this);
1352 this.eventListener = null;