2 * Copyright (c) 2010-2020 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.concurrent.ScheduledExecutorService;
23 import java.util.concurrent.ScheduledFuture;
24 import java.util.concurrent.TimeUnit;
26 import org.openhab.binding.digitalstrom.internal.lib.GeneralLibConstance;
27 import org.openhab.binding.digitalstrom.internal.lib.config.Config;
28 import org.openhab.binding.digitalstrom.internal.lib.event.EventListener;
29 import org.openhab.binding.digitalstrom.internal.lib.event.constants.EventNames;
30 import org.openhab.binding.digitalstrom.internal.lib.event.constants.EventResponseEnum;
31 import org.openhab.binding.digitalstrom.internal.lib.event.types.EventItem;
32 import org.openhab.binding.digitalstrom.internal.lib.listener.ConnectionListener;
33 import org.openhab.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
34 import org.openhab.binding.digitalstrom.internal.lib.listener.ManagerStatusListener;
35 import org.openhab.binding.digitalstrom.internal.lib.listener.SceneStatusListener;
36 import org.openhab.binding.digitalstrom.internal.lib.listener.TotalPowerConsumptionListener;
37 import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerStates;
38 import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerTypes;
39 import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
40 import org.openhab.binding.digitalstrom.internal.lib.manager.DeviceStatusManager;
41 import org.openhab.binding.digitalstrom.internal.lib.manager.SceneManager;
42 import org.openhab.binding.digitalstrom.internal.lib.manager.StructureManager;
43 import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.SceneReadingJobExecutor;
44 import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.SensorJobExecutor;
45 import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.SensorJob;
46 import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.impl.DeviceConsumptionSensorJob;
47 import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.impl.DeviceOutputValueSensorJob;
48 import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.impl.SceneConfigReadingJob;
49 import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.impl.SceneOutputValueReadingJob;
50 import org.openhab.binding.digitalstrom.internal.lib.serverconnection.DsAPI;
51 import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
52 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Circuit;
53 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
54 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.CachedMeteringValue;
55 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceConstants;
56 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
57 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.DeviceBinarayInputEnum;
58 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringTypeEnum;
59 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringUnitsEnum;
60 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputModeEnum;
61 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
62 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
63 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DeviceStateUpdateImpl;
64 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.impl.DeviceImpl;
65 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
66 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.ApartmentSceneEnum;
67 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.SceneEnum;
68 import org.openhab.core.common.ThreadPoolManager;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
72 import com.google.gson.JsonElement;
73 import com.google.gson.JsonObject;
76 * The {@link DeviceStatusManagerImpl} is the implementation of the {@link DeviceStatusManager}.
78 * @author Michael Ochel - Initial contribution
79 * @author Matthias Siegele - Initial contribution
81 public class DeviceStatusManagerImpl implements DeviceStatusManager {
83 private final Logger logger = LoggerFactory.getLogger(DeviceStatusManagerImpl.class);
86 * Contains all supported event-types.
88 public static final List<String> SUPPORTED_EVENTS = Arrays.asList(EventNames.DEVICE_SENSOR_VALUE,
89 EventNames.DEVICE_BINARY_INPUT_EVENT);
91 private final ScheduledExecutorService scheduler = ThreadPoolManager.getScheduledPool(Config.THREADPOOL_NAME);
92 private ScheduledFuture<?> pollingScheduler;
95 * Query to get all {@link Device}'s with more informations than {@link DsAPI#getApartmentDevices(String)}. Can be
96 * executed with {@link DsAPI#query(String, String)} or {@link DsAPI#query2(String, String)}.
98 public static final String GET_DETAILD_DEVICES = "/apartment/zones/zone0(*)/devices/*(*)/*(*)/*(*)";
100 * Query to get the last called scenes of all groups in digitalSTROM. Can be executed with
101 * {@link DsAPI#query(String, String)} or
102 * {@link DsAPI#query2(String, String)}.
104 public static final String LAST_CALL_SCENE_QUERY = "/apartment/zones/*(*)/groups/*(*)/*(*)";
106 private ConnectionManager connMan;
107 private StructureManager strucMan;
108 private SceneManager sceneMan;
109 private DsAPI digitalSTROMClient;
110 private Config config;
112 private SensorJobExecutor sensorJobExecutor;
113 private SceneReadingJobExecutor sceneJobExecutor;
114 private EventListener eventListener;
116 private final List<TrashDevice> trashDevices = new LinkedList<>();
118 private long lastBinCheck = 0;
119 private ManagerStates state = ManagerStates.STOPPED;
121 private int tempConsumption = 0;
122 private int tempEnergyMeter = 0;
123 private int tempEnergyMeterWs = 0;
125 private DeviceStatusListener deviceDiscovery;
126 private TotalPowerConsumptionListener totalPowerConsumptionListener;
127 private ManagerStatusListener statusListener;
130 * Creates a new {@link DeviceStatusManagerImpl} through the given {@link Config} object, which has to be contains
131 * all needed parameters like host address, authentication data and so on. This constructor the
132 * {@link DeviceStatusManagerImpl} will be create all needed managers itself.
134 * @param config (must not be null)
136 public DeviceStatusManagerImpl(Config config) {
137 init(new ConnectionManagerImpl(config), null, null, null, null);
141 * Creates a new {@link DeviceStatusManagerImpl}. The given fields needed to create {@link ConnectionManager}
142 * through the constructor {@link ConnectionManagerImpl#ConnectionManagerImpl(String, String, String, String)}. All
143 * other needed manager will be automatically created, too.
145 * @param hostAddress (must not be null)
146 * @param user (can be null, if appToken is set)
147 * @param password (can be null, if appToken is set)
148 * @param appToken (can be null, if user and password is set)
150 public DeviceStatusManagerImpl(String hostAddress, String user, String password, String appToken) {
151 init(new ConnectionManagerImpl(hostAddress, user, password, false), null, null, null, null);
155 * Creates a new {@link DeviceStatusManagerImpl} with the given managers. If the {@link StructureManager} or
156 * {@link SceneManager} is null, they will be automatically created.
158 * @param connMan (must not be null)
159 * @param strucMan (can be null)
160 * @param sceneMan (can be null)
162 public DeviceStatusManagerImpl(ConnectionManager connMan, StructureManager strucMan, SceneManager sceneMan) {
163 init(connMan, strucMan, sceneMan, null, null);
167 * Same constructor like {@link #DeviceStatusManagerImpl(ConnectionManager, StructureManager, SceneManager)}, but a
168 * {@link ManagerStatusListener} can be set, too.
170 * @param connMan (must not be null)
171 * @param strucMan (can be null)
172 * @param sceneMan (can be null)
173 * @param statusListener (can be null)
174 * @see #DeviceStatusManagerImpl(ConnectionManager, StructureManager, SceneManager)
176 public DeviceStatusManagerImpl(ConnectionManager connMan, StructureManager strucMan, SceneManager sceneMan,
177 ManagerStatusListener statusListener) {
178 init(connMan, strucMan, sceneMan, statusListener, null);
182 * Same constructor like
183 * {@link #DeviceStatusManagerImpl(ConnectionManager, StructureManager, SceneManager, ManagerStatusListener)}, but a
184 * {@link EventListener} can be set, too.
186 * @param connMan (must not be null)
187 * @param strucMan (can be null)
188 * @param sceneMan (can be null)
189 * @param statusListener (can be null)
190 * @param eventListener (can be null)
191 * @see #DeviceStatusManagerImpl(ConnectionManager, StructureManager, SceneManager, ManagerStatusListener)
193 public DeviceStatusManagerImpl(ConnectionManager connMan, StructureManager strucMan, SceneManager sceneMan,
194 ManagerStatusListener statusListener, EventListener eventListener) {
195 init(connMan, strucMan, sceneMan, statusListener, eventListener);
199 * Creates a new {@link DeviceStatusManagerImpl} with the given {@link ConnectionManager}. The
200 * {@link StructureManager} and
201 * {@link SceneManager} will be automatically created.
203 * @param connMan (must not be null)
205 public DeviceStatusManagerImpl(ConnectionManager connMan) {
206 init(connMan, null, null, null, null);
209 private void init(ConnectionManager connMan, StructureManager strucMan, SceneManager sceneMan,
210 ManagerStatusListener statusListener, EventListener eventListener) {
211 this.connMan = connMan;
212 this.digitalSTROMClient = connMan.getDigitalSTROMAPI();
213 this.config = connMan.getConfig();
214 if (strucMan != null) {
215 this.strucMan = strucMan;
217 this.strucMan = new StructureManagerImpl();
219 if (sceneMan != null) {
220 this.sceneMan = sceneMan;
222 this.sceneMan = new SceneManagerImpl(connMan, strucMan, statusListener);
224 this.statusListener = statusListener;
225 this.eventListener = eventListener;
229 * Check and updates the {@link Device} structure, configurations and status.
231 * @author Michael Ochel - initial contributer
232 * @author Matthias Siegele - initial contributer
234 private class PollingRunnable implements Runnable {
235 private boolean devicesLoaded = false;
236 private long nextSensorUpdate = 0;
240 if (!getManagerState().equals(ManagerStates.RUNNING)) {
241 logger.debug("Thread started");
243 stateChanged(ManagerStates.RUNNING);
245 stateChanged(ManagerStates.INITIALIZING);
248 Map<DSID, Device> tempDeviceMap;
249 if (strucMan.getDeviceMap() != null) {
250 tempDeviceMap = strucMan.getDeviceMap();
252 tempDeviceMap = new HashMap<>();
255 List<Device> currentDeviceList = getDetailedDevices();
257 // update the current total power consumption
258 if (nextSensorUpdate <= System.currentTimeMillis()) {
260 List<Circuit> circuits = digitalSTROMClient.getApartmentCircuits(connMan.getSessionToken());
261 for (Circuit circuit : circuits) {
262 if (strucMan.getCircuitByDSID(circuit.getDSID()) != null) {
263 if (!circuit.equals(strucMan.getCircuitByDSID(circuit.getDSID()))) {
264 strucMan.updateCircuitConfig(circuit);
267 strucMan.addCircuit(circuit);
268 if (deviceDiscovery != null) {
269 deviceDiscovery.onDeviceAdded(circuit);
274 nextSensorUpdate = System.currentTimeMillis() + config.getTotalPowerUpdateInterval();
277 while (!currentDeviceList.isEmpty()) {
278 Device currentDevice = currentDeviceList.remove(0);
279 DSID currentDeviceDSID = currentDevice.getDSID();
280 Device device = tempDeviceMap.remove(currentDeviceDSID);
282 if (device != null) {
283 checkDeviceConfig(currentDevice, device);
285 if (device.isPresent()) {
286 // check device state updates
287 while (!device.isDeviceUpToDate()) {
288 DeviceStateUpdate deviceStateUpdate = device.getNextDeviceUpdateState();
289 if (deviceStateUpdate != null) {
290 switch (deviceStateUpdate.getType()) {
291 case DeviceStateUpdate.OUTPUT:
292 case DeviceStateUpdate.SLAT_ANGLE_INCREASE:
293 case DeviceStateUpdate.SLAT_ANGLE_DECREASE:
294 filterCommand(deviceStateUpdate, device);
296 case DeviceStateUpdate.UPDATE_SCENE_CONFIG:
297 case DeviceStateUpdate.UPDATE_SCENE_OUTPUT:
298 updateSceneData(device, deviceStateUpdate);
300 case DeviceStateUpdate.UPDATE_OUTPUT_VALUE:
301 if (deviceStateUpdate.getValueAsInteger() > -1) {
302 readOutputValue(device);
304 removeSensorJob(device, deviceStateUpdate);
308 sendComandsToDSS(device, deviceStateUpdate);
315 logger.debug("Found new device!");
316 if (trashDevices.isEmpty()) {
317 currentDevice.setConfig(config);
318 strucMan.addDeviceToStructure(currentDevice);
319 logger.debug("trashDevices are empty, add Device with dSID {} to the deviceMap!",
320 currentDevice.getDSID());
322 logger.debug("Search device in trashDevices.");
323 TrashDevice foundTrashDevice = null;
324 for (TrashDevice trashDevice : trashDevices) {
325 if (trashDevice != null) {
326 if (trashDevice.getDevice().equals(currentDevice)) {
327 foundTrashDevice = trashDevice;
329 "Found device in trashDevices, add TrashDevice with dSID {} to the StructureManager!",
334 if (foundTrashDevice != null) {
335 trashDevices.remove(foundTrashDevice);
336 strucMan.addDeviceToStructure(foundTrashDevice.getDevice());
338 strucMan.addDeviceToStructure(currentDevice);
340 "Can't find device in trashDevices, add Device with dSID: {} to the StructureManager!",
344 if (deviceDiscovery != null) {
345 // only informs discovery, if the device is a output or a sensor device
346 deviceDiscovery.onDeviceAdded(currentDevice);
347 logger.debug("inform DeviceStatusListener: {} about added device with dSID {}",
348 DeviceStatusListener.DEVICE_DISCOVERY, currentDevice.getDSID().getValue());
351 "The device discovery is not registrated, can't inform device discovery about found device.");
356 if (!devicesLoaded && strucMan.getDeviceMap() != null) {
357 if (!strucMan.getDeviceMap().values().isEmpty()) {
358 logger.debug("Devices loaded");
359 devicesLoaded = true;
360 setInizialStateWithLastCallScenes();
361 stateChanged(ManagerStates.RUNNING);
363 logger.debug("No devices found");
367 if (!sceneMan.scenesGenerated() && devicesLoaded
368 && !sceneMan.getManagerState().equals(ManagerStates.GENERATING_SCENES)) {
369 logger.debug("{}", sceneMan.getManagerState());
370 sceneMan.generateScenes();
373 for (Device device : tempDeviceMap.values()) {
374 logger.debug("Found removed devices.");
376 trashDevices.add(new TrashDevice(device));
377 DeviceStatusListener listener = device.unregisterDeviceStatusListener();
378 if (listener != null) {
379 listener.onDeviceRemoved(null);
381 strucMan.deleteDevice(device);
382 logger.debug("Add device with dSID {} to trashDevices", device.getDSID().getValue());
384 if (deviceDiscovery != null) {
385 deviceDiscovery.onDeviceRemoved(device);
386 logger.debug("inform DeviceStatusListener: {} about removed device with dSID {}",
387 DeviceStatusListener.DEVICE_DISCOVERY, device.getDSID().getValue());
390 "The device-Discovery is not registrated, can't inform device discovery about removed device.");
394 if (!trashDevices.isEmpty() && (lastBinCheck + config.getBinCheckTime() < System.currentTimeMillis())) {
395 for (TrashDevice trashDevice : trashDevices) {
396 if (trashDevice.isTimeToDelete(Calendar.getInstance().get(Calendar.DAY_OF_YEAR))) {
397 logger.debug("Found trashDevice that have to delete!");
398 trashDevices.remove(trashDevice);
399 logger.debug("Delete trashDevice: {}", trashDevice.getDevice().getDSID().getValue());
402 lastBinCheck = System.currentTimeMillis();
406 private List<Device> getDetailedDevices() {
407 List<Device> deviceList = new LinkedList<>();
408 JsonObject result = connMan.getDigitalSTROMAPI().query2(connMan.getSessionToken(), GET_DETAILD_DEVICES);
409 if (result != null && result.isJsonObject()) {
410 if (result.getAsJsonObject().get(GeneralLibConstance.QUERY_BROADCAST_ZONE_STRING).isJsonObject()) {
411 result = result.getAsJsonObject().get(GeneralLibConstance.QUERY_BROADCAST_ZONE_STRING)
413 for (Entry<String, JsonElement> entry : result.entrySet()) {
414 if (!(entry.getKey().equals(JSONApiResponseKeysEnum.ZONE_ID.getKey())
415 && entry.getKey().equals(JSONApiResponseKeysEnum.NAME.getKey()))
416 && entry.getValue().isJsonObject()) {
417 deviceList.add(new DeviceImpl(entry.getValue().getAsJsonObject()));
425 private void filterCommand(DeviceStateUpdate deviceStateUpdate, Device device) {
426 DeviceStateUpdate intDeviceStateUpdate = deviceStateUpdate;
427 String stateUpdateType = intDeviceStateUpdate.getType();
429 if (stateUpdateType.equals(DeviceStateUpdate.SLAT_ANGLE_INCREASE)
430 || stateUpdateType.equals(DeviceStateUpdate.SLAT_ANGLE_DECREASE)) {
431 newAngle = device.getAnglePosition();
433 DeviceStateUpdate nextDeviceStateUpdate = device.getNextDeviceUpdateState();
434 while (nextDeviceStateUpdate != null && nextDeviceStateUpdate.getType().equals(stateUpdateType)) {
435 switch (stateUpdateType) {
436 case DeviceStateUpdate.OUTPUT:
437 intDeviceStateUpdate = nextDeviceStateUpdate;
438 nextDeviceStateUpdate = device.getNextDeviceUpdateState();
440 case DeviceStateUpdate.SLAT_ANGLE_INCREASE:
441 if (intDeviceStateUpdate.getValueAsInteger() == 1) {
442 newAngle = (short) (newAngle + DeviceConstants.ANGLE_STEP_SLAT);
445 case DeviceStateUpdate.SLAT_ANGLE_DECREASE:
446 if (intDeviceStateUpdate.getValueAsInteger() == 1) {
447 newAngle = (short) (newAngle - DeviceConstants.ANGLE_STEP_SLAT);
452 if (stateUpdateType.equals(DeviceStateUpdate.SLAT_ANGLE_INCREASE)
453 || stateUpdateType.equals(DeviceStateUpdate.SLAT_ANGLE_DECREASE)) {
454 if (newAngle > device.getMaxSlatAngle()) {
455 newAngle = (short) device.getMaxSlatAngle();
457 if (newAngle < device.getMinSlatAngle()) {
458 newAngle = (short) device.getMinSlatAngle();
460 if (!(stateUpdateType.equals(DeviceStateUpdate.SLAT_ANGLE_INCREASE) && checkAngleIsMinMax(device) == 1)
461 || !(stateUpdateType.equals(DeviceStateUpdate.SLAT_ANGLE_DECREASE)
462 && checkAngleIsMinMax(device) == 0)) {
463 intDeviceStateUpdate = new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE, newAngle);
466 sendComandsToDSS(device, intDeviceStateUpdate);
467 if (nextDeviceStateUpdate != null) {
468 if (intDeviceStateUpdate.getType() == DeviceStateUpdate.UPDATE_SCENE_CONFIG
469 || intDeviceStateUpdate.getType() == DeviceStateUpdate.UPDATE_SCENE_OUTPUT) {
470 updateSceneData(device, intDeviceStateUpdate);
472 sendComandsToDSS(device, intDeviceStateUpdate);
478 private void removeSensorJob(Device device, DeviceStateUpdate deviceStateUpdate) {
479 switch (deviceStateUpdate.getType()) {
480 case DeviceStateUpdate.UPDATE_SCENE_CONFIG:
481 if (sceneJobExecutor != null) {
482 sceneJobExecutor.removeSensorJob(device,
483 SceneConfigReadingJob.getID(device, deviceStateUpdate.getSceneId()));
486 case DeviceStateUpdate.UPDATE_SCENE_OUTPUT:
487 if (sceneJobExecutor != null) {
488 sceneJobExecutor.removeSensorJob(device,
489 SceneOutputValueReadingJob.getID(device, deviceStateUpdate.getSceneId()));
492 case DeviceStateUpdate.UPDATE_OUTPUT_VALUE:
493 if (sensorJobExecutor != null) {
494 sensorJobExecutor.removeSensorJob(device, DeviceOutputValueSensorJob.getID(device));
498 if (deviceStateUpdate.isSensorUpdateType()) {
499 if (sensorJobExecutor != null) {
500 logger.debug("remove SensorJob with ID: {}",
501 DeviceConsumptionSensorJob.getID(device, deviceStateUpdate.getTypeAsSensorEnum()));
502 sensorJobExecutor.removeSensorJob(device,
503 DeviceConsumptionSensorJob.getID(device, deviceStateUpdate.getTypeAsSensorEnum()));
509 public ManagerTypes getManagerType() {
510 return ManagerTypes.DEVICE_STATUS_MANAGER;
514 public synchronized ManagerStates getManagerState() {
518 private synchronized void stateChanged(ManagerStates state) {
519 if (statusListener != null) {
521 statusListener.onStatusChanged(ManagerTypes.DEVICE_STATUS_MANAGER, state);
526 public synchronized void start() {
527 logger.debug("start DeviceStatusManager");
528 if (pollingScheduler == null || pollingScheduler.isCancelled()) {
529 pollingScheduler = scheduler.scheduleWithFixedDelay(new PollingRunnable(), 0, config.getPollingFrequency(),
530 TimeUnit.MILLISECONDS);
531 logger.debug("start pollingScheduler");
534 if (sceneJobExecutor != null) {
535 this.sceneJobExecutor.startExecutor();
538 if (sensorJobExecutor != null) {
539 this.sensorJobExecutor.startExecutor();
541 if (eventListener != null) {
542 eventListener.addEventHandler(this);
544 eventListener = new EventListener(connMan, this);
545 eventListener.start();
550 public synchronized void stop() {
551 logger.debug("stop DeviceStatusManager");
552 stateChanged(ManagerStates.STOPPED);
553 if (sceneMan != null) {
556 if (pollingScheduler != null && !pollingScheduler.isCancelled()) {
557 pollingScheduler.cancel(true);
558 pollingScheduler = null;
559 logger.debug("stop pollingScheduler");
561 if (sceneJobExecutor != null) {
562 this.sceneJobExecutor.shutdown();
564 if (sensorJobExecutor != null) {
565 this.sensorJobExecutor.shutdown();
567 if (eventListener != null) {
568 eventListener.removeEventHandler(this);
573 * The {@link TrashDevice} saves not present {@link Device}'s, but at this point not deleted from the
574 * digitalSTROM-System, temporary to get back the configuration of the {@link Device}'s faster.
576 * @author Michael Ochel - Initial contribution
577 * @author Matthias Siegele - Initial contribution
579 private class TrashDevice {
580 private final Device device;
581 private final int timestamp;
584 * Creates a new {@link TrashDevice}.
586 * @param device to put in {@link TrashDevice}
588 public TrashDevice(Device device) {
589 this.device = device;
590 this.timestamp = Calendar.getInstance().get(Calendar.DAY_OF_YEAR);
594 * Returns the saved {@link Device}.
598 public Device getDevice() {
603 * Returns true if the time for the {@link TrashDevice} is over and it can be deleted.
605 * @param dayOfYear day of the current year
606 * @return true = time to delete | false = not time to delete
608 public boolean isTimeToDelete(int dayOfYear) {
609 return this.timestamp + config.getTrashDeviceDeleteTime() <= dayOfYear;
613 public boolean equals(Object object) {
614 return object instanceof TrashDevice
615 ? this.device.getDSID().equals(((TrashDevice) object).getDevice().getDSID())
620 private void checkDeviceConfig(Device newDevice, Device internalDevice) {
621 if (newDevice == null || internalDevice == null) {
624 // check device availability has changed and informs the deviceStatusListener about the change.
626 // The device is not availability for the digitalSTROM-Server, it has not been deleted and therefore it is set
629 // An alternate algorithm is responsible for deletion.
630 if (newDevice.isPresent() != internalDevice.isPresent()) {
631 internalDevice.setIsPresent(newDevice.isPresent());
633 if (newDevice.getMeterDSID() != null && !newDevice.getMeterDSID().equals(internalDevice.getMeterDSID())) {
634 internalDevice.setMeterDSID(newDevice.getMeterDSID().getValue());
636 if (newDevice.getFunctionalColorGroup() != null
637 && !newDevice.getFunctionalColorGroup().equals(internalDevice.getFunctionalColorGroup())) {
638 internalDevice.setFunctionalColorGroup(newDevice.getFunctionalColorGroup());
640 if (newDevice.getName() != null && !newDevice.getName().equals(internalDevice.getName())) {
641 internalDevice.setName(newDevice.getName());
643 if (newDevice.getOutputMode() != null && !newDevice.getOutputMode().equals(internalDevice.getOutputMode())) {
644 if (deviceDiscovery != null) {
645 if (OutputModeEnum.DISABLED.equals(internalDevice.getOutputMode())
646 || OutputModeEnum.outputModeIsTemperationControlled(internalDevice.getOutputMode())) {
647 deviceDiscovery.onDeviceAdded(newDevice);
649 if (OutputModeEnum.DISABLED.equals(newDevice.getOutputMode())
650 || OutputModeEnum.outputModeIsTemperationControlled(newDevice.getOutputMode())) {
651 deviceDiscovery.onDeviceRemoved(newDevice);
654 internalDevice.setOutputMode(newDevice.getOutputMode());
656 if (!newDevice.getBinaryInputs().equals(internalDevice.getBinaryInputs())) {
657 internalDevice.setBinaryInputs(newDevice.getBinaryInputs());
659 strucMan.updateDevice(newDevice);
662 private long lastSceneCall = 0;
663 private long sleepTime = 0;
666 public synchronized void sendSceneComandsToDSS(InternalScene scene, boolean call_undo) {
668 if (lastSceneCall + 1000 > System.currentTimeMillis()) {
669 sleepTime = System.currentTimeMillis() - lastSceneCall;
671 Thread.sleep(sleepTime);
672 } catch (InterruptedException e) {
673 logger.debug("An InterruptedException occurred", e);
676 lastSceneCall = System.currentTimeMillis();
677 boolean requestSuccessful = false;
678 if (scene.getZoneID() == 0) {
680 logger.debug("{} {} {}", scene.getGroupID(), scene.getSceneID(),
681 ApartmentSceneEnum.getApartmentScene(scene.getSceneID()));
682 requestSuccessful = this.digitalSTROMClient.callApartmentScene(connMan.getSessionToken(),
683 scene.getGroupID(), null, ApartmentSceneEnum.getApartmentScene(scene.getSceneID()), false);
685 requestSuccessful = this.digitalSTROMClient.undoApartmentScene(connMan.getSessionToken(),
686 scene.getGroupID(), null, ApartmentSceneEnum.getApartmentScene(scene.getSceneID()));
690 requestSuccessful = this.digitalSTROMClient.callZoneScene(connMan.getSessionToken(),
691 scene.getZoneID(), null, scene.getGroupID(), null, SceneEnum.getScene(scene.getSceneID()),
694 requestSuccessful = this.digitalSTROMClient.undoZoneScene(connMan.getSessionToken(),
695 scene.getZoneID(), null, scene.getGroupID(), null, SceneEnum.getScene(scene.getSceneID()));
699 logger.debug("Was the scene call succsessful?: {}", requestSuccessful);
700 if (requestSuccessful) {
701 this.sceneMan.addEcho(scene.getID());
703 scene.activateScene();
705 scene.deactivateScene();
712 public synchronized void sendStopComandsToDSS(final Device device) {
713 scheduler.execute(new Runnable() {
717 if (digitalSTROMClient.callDeviceScene(connMan.getSessionToken(), device.getDSID(), null, null,
718 SceneEnum.STOP, true)) {
719 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.STOP.getSceneNumber());
720 readOutputValue(device);
726 private void readOutputValue(Device device) {
727 short outputIndex = DeviceConstants.DEVICE_SENSOR_OUTPUT;
728 if (device.isShade()) {
729 outputIndex = DeviceConstants.DEVICE_SENSOR_SLAT_POSITION_OUTPUT;
732 int outputValue = this.digitalSTROMClient.getDeviceOutputValue(connMan.getSessionToken(), device.getDSID(),
733 null, null, outputIndex);
734 if (outputValue != -1) {
735 if (!device.isShade()) {
736 device.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT, outputValue));
738 device.updateInternalDeviceState(
739 new DeviceStateUpdateImpl(DeviceStateUpdate.SLATPOSITION, outputValue));
740 if (device.isBlind()) {
741 outputValue = this.digitalSTROMClient.getDeviceOutputValue(connMan.getSessionToken(),
742 device.getDSID(), null, null, DeviceConstants.DEVICE_SENSOR_SLAT_ANGLE_OUTPUT);
743 device.updateInternalDeviceState(
744 new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE, outputValue));
751 * Updates the {@link Device} status of the given {@link Device} with handling outstanding commands, which are saved
752 * as {@link DeviceStateUpdate}'s.
754 * @param device to update
756 public synchronized void updateDevice(Device device) {
757 logger.debug("Check device updates");
758 // check device state updates
759 while (!device.isDeviceUpToDate()) {
760 DeviceStateUpdate deviceStateUpdate = device.getNextDeviceUpdateState();
761 if (deviceStateUpdate != null) {
762 if (deviceStateUpdate.getType() != DeviceStateUpdate.OUTPUT) {
763 if (deviceStateUpdate.getType() == DeviceStateUpdate.UPDATE_SCENE_CONFIG
764 || deviceStateUpdate.getType() == DeviceStateUpdate.UPDATE_SCENE_OUTPUT) {
765 updateSceneData(device, deviceStateUpdate);
767 sendComandsToDSS(device, deviceStateUpdate);
770 DeviceStateUpdate nextDeviceStateUpdate = device.getNextDeviceUpdateState();
771 while (nextDeviceStateUpdate != null
772 && nextDeviceStateUpdate.getType() == DeviceStateUpdate.OUTPUT) {
773 deviceStateUpdate = nextDeviceStateUpdate;
774 nextDeviceStateUpdate = device.getNextDeviceUpdateState();
776 sendComandsToDSS(device, deviceStateUpdate);
777 if (nextDeviceStateUpdate != null) {
778 if (deviceStateUpdate.getType() == DeviceStateUpdate.UPDATE_SCENE_CONFIG
779 || deviceStateUpdate.getType() == DeviceStateUpdate.UPDATE_SCENE_OUTPUT) {
780 updateSceneData(device, deviceStateUpdate);
782 sendComandsToDSS(device, deviceStateUpdate);
791 * Checks the output value of a {@link Device} and return 0, if the output value or slat position is min and 1, if
792 * the output value or slat position is max, otherwise it returns -1.
795 * @return 0 = output value is min, 1 device value is min, otherwise -1
797 private short checkIsAllreadyMinMax(Device device) {
798 if (device.isShade()) {
799 if (device.getSlatPosition() == device.getMaxSlatPosition()) {
800 if (device.isBlind()) {
801 if (device.getAnglePosition() == device.getMaxSlatAngle()) {
809 if (device.getSlatPosition() == device.getMinSlatPosition()) {
810 if (device.isBlind()) {
811 if (device.getAnglePosition() == device.getMinSlatAngle()) {
820 if (device.getOutputValue() == device.getMaxOutputValue()) {
823 if (device.getOutputValue() == device.getMinOutputValue() || device.getOutputValue() <= 0) {
831 * Checks the angle value of a {@link Device} and return 0, if the angle value is min and 1, if the angle value is
832 * max, otherwise it returns -1.
835 * @return 0 = angle value is min, 1 angle value is min, otherwise -1
837 private short checkAngleIsMinMax(Device device) {
838 if (device.getAnglePosition() == device.getMaxSlatAngle()) {
841 if (device.getAnglePosition() == device.getMinSlatAngle()) {
848 public synchronized void sendComandsToDSS(Device device, DeviceStateUpdate deviceStateUpdate) {
849 boolean requestSuccsessful = false;
850 boolean commandHasNoEffect = false;
851 if (deviceStateUpdate != null) {
852 if (deviceStateUpdate.isSensorUpdateType()) {
853 SensorEnum sensorType = deviceStateUpdate.getTypeAsSensorEnum();
854 if (deviceStateUpdate.getValueAsInteger() == 0) {
855 updateSensorData(new DeviceConsumptionSensorJob(device, sensorType),
856 device.getPowerSensorRefreshPriority(sensorType));
858 } else if (deviceStateUpdate.getValueAsInteger() < 0) {
859 removeSensorJob(device, deviceStateUpdate);
862 int consumption = this.digitalSTROMClient.getDeviceSensorValue(connMan.getSessionToken(),
863 device.getDSID(), null, null, device.getSensorIndex(sensorType));
864 if (consumption >= 0) {
865 device.setDeviceSensorDsValueBySensorJob(sensorType, consumption);
866 requestSuccsessful = true;
870 switch (deviceStateUpdate.getType()) {
871 case DeviceStateUpdate.OUTPUT_DECREASE:
872 case DeviceStateUpdate.SLAT_DECREASE:
873 if (checkIsAllreadyMinMax(device) != 0) {
874 requestSuccsessful = digitalSTROMClient.decreaseValue(connMan.getSessionToken(),
875 device.getDSID(), null, null);
876 if (requestSuccsessful) {
877 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.DECREMENT.getSceneNumber());
880 commandHasNoEffect = true;
883 case DeviceStateUpdate.OUTPUT_INCREASE:
884 case DeviceStateUpdate.SLAT_INCREASE:
885 if (checkIsAllreadyMinMax(device) != 1) {
886 requestSuccsessful = digitalSTROMClient.increaseValue(connMan.getSessionToken(),
887 device.getDSID(), null, null);
888 if (requestSuccsessful) {
889 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.INCREMENT.getSceneNumber());
892 commandHasNoEffect = true;
895 case DeviceStateUpdate.OUTPUT:
896 if (device.getOutputValue() != deviceStateUpdate.getValueAsInteger()) {
897 requestSuccsessful = digitalSTROMClient.setDeviceValue(connMan.getSessionToken(),
898 device.getDSID(), null, null, deviceStateUpdate.getValueAsInteger());
900 commandHasNoEffect = true;
903 case DeviceStateUpdate.OPEN_CLOSE:
904 case DeviceStateUpdate.ON_OFF:
905 if (deviceStateUpdate.getValueAsInteger() > 0) {
906 if (checkIsAllreadyMinMax(device) != 1) {
907 requestSuccsessful = digitalSTROMClient.turnDeviceOn(connMan.getSessionToken(),
908 device.getDSID(), null, null);
909 if (requestSuccsessful) {
910 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.MAXIMUM.getSceneNumber());
913 commandHasNoEffect = true;
916 if (checkIsAllreadyMinMax(device) != 0) {
917 requestSuccsessful = digitalSTROMClient.turnDeviceOff(connMan.getSessionToken(),
918 device.getDSID(), null, null);
919 if (requestSuccsessful) {
920 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.MINIMUM.getSceneNumber());
923 commandHasNoEffect = true;
927 case DeviceStateUpdate.SLATPOSITION:
928 if (device.getSlatPosition() != deviceStateUpdate.getValueAsInteger()) {
929 requestSuccsessful = digitalSTROMClient.setDeviceOutputValue(connMan.getSessionToken(),
930 device.getDSID(), null, null, DeviceConstants.DEVICE_SENSOR_SLAT_POSITION_OUTPUT,
931 deviceStateUpdate.getValueAsInteger());
933 commandHasNoEffect = true;
936 case DeviceStateUpdate.SLAT_STOP:
937 this.sendStopComandsToDSS(device);
939 case DeviceStateUpdate.SLAT_MOVE:
940 if (deviceStateUpdate.getValueAsInteger() > 0) {
941 requestSuccsessful = digitalSTROMClient.turnDeviceOn(connMan.getSessionToken(),
942 device.getDSID(), null, null);
943 if (requestSuccsessful) {
944 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.MAXIMUM.getSceneNumber());
947 requestSuccsessful = digitalSTROMClient.turnDeviceOff(connMan.getSessionToken(),
948 device.getDSID(), null, null);
949 if (requestSuccsessful) {
950 sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.MINIMUM.getSceneNumber());
952 if (sensorJobExecutor != null) {
953 sensorJobExecutor.removeSensorJobs(device);
957 case DeviceStateUpdate.UPDATE_CALL_SCENE:
958 if (SceneEnum.getScene((short) deviceStateUpdate.getValue()) != null) {
959 requestSuccsessful = digitalSTROMClient.callDeviceScene(connMan.getSessionToken(),
960 device.getDSID(), null, null,
961 SceneEnum.getScene((short) deviceStateUpdate.getValue()), true);
964 case DeviceStateUpdate.UPDATE_UNDO_SCENE:
965 if (SceneEnum.getScene((short) deviceStateUpdate.getValue()) != null) {
966 requestSuccsessful = digitalSTROMClient.undoDeviceScene(connMan.getSessionToken(),
967 device.getDSID(), null, null,
968 SceneEnum.getScene((short) deviceStateUpdate.getValue()));
971 case DeviceStateUpdate.SLAT_ANGLE_DECREASE:
972 // By UPDATE_SLAT_ANGLE_DECREASE, UPDATE_SLAT_ANGLE_INCREASE with value unequal 1 which will
973 // handled in the pollingRunnable and UPDATE_OPEN_CLOSE_ANGLE the value will be set without
974 // checking, because it was triggered by setting the slat position.
975 requestSuccsessful = true;
977 case DeviceStateUpdate.SLAT_ANGLE_INCREASE:
978 requestSuccsessful = true;
980 case DeviceStateUpdate.OPEN_CLOSE_ANGLE:
981 requestSuccsessful = true;
983 case DeviceStateUpdate.SLAT_ANGLE:
984 if (device.getAnglePosition() != deviceStateUpdate.getValueAsInteger()) {
985 requestSuccsessful = digitalSTROMClient.setDeviceOutputValue(connMan.getSessionToken(),
986 device.getDSID(), null, null, DeviceConstants.DEVICE_SENSOR_SLAT_ANGLE_OUTPUT,
987 deviceStateUpdate.getValueAsInteger());
989 commandHasNoEffect = true;
992 case DeviceStateUpdate.REFRESH_OUTPUT:
993 readOutputValue(device);
994 logger.debug("Inizalize output value reading for device with dSID {}.",
995 device.getDSID().getValue());
1001 if (commandHasNoEffect) {
1002 logger.debug("Command {} for device with dSID {} not send to dSS, because it has no effect!",
1003 deviceStateUpdate.getType(), device.getDSID().getValue());
1006 if (requestSuccsessful) {
1007 logger.debug("Send {} command to dSS and updateInternalDeviceState for device with dSID {}.",
1008 deviceStateUpdate.getType(), device.getDSID().getValue());
1009 device.updateInternalDeviceState(deviceStateUpdate);
1011 logger.debug("Can't send {} command for device with dSID {} to dSS!", deviceStateUpdate.getType(),
1012 device.getDSID().getValue());
1018 public void updateSensorData(SensorJob sensorJob, String priority) {
1019 if (sensorJobExecutor == null) {
1020 sensorJobExecutor = new SensorJobExecutor(connMan);
1021 this.sensorJobExecutor.startExecutor();
1023 if (sensorJob != null && priority != null) {
1025 case Config.REFRESH_PRIORITY_HIGH:
1026 sensorJobExecutor.addHighPriorityJob(sensorJob);
1028 case Config.REFRESH_PRIORITY_MEDIUM:
1029 sensorJobExecutor.addMediumPriorityJob(sensorJob);
1031 case Config.REFRESH_PRIORITY_LOW:
1032 sensorJobExecutor.addLowPriorityJob(sensorJob);
1036 long prio = Long.parseLong(priority);
1037 sensorJobExecutor.addPriorityJob(sensorJob, prio);
1038 } catch (NumberFormatException e) {
1039 logger.debug("Sensor data update priority do not exist! Please check the input!");
1043 logger.debug("Add new sensorJob {} with priority: {} to sensorJobExecuter", sensorJob.toString(), priority);
1048 public void updateSceneData(Device device, DeviceStateUpdate deviceStateUpdate) {
1049 if (sceneJobExecutor == null) {
1050 sceneJobExecutor = new SceneReadingJobExecutor(connMan);
1051 this.sceneJobExecutor.startExecutor();
1054 if (deviceStateUpdate != null) {
1055 if (deviceStateUpdate.getScenePriority() > -1) {
1056 if (deviceStateUpdate.getType().equals(DeviceStateUpdate.UPDATE_SCENE_OUTPUT)) {
1057 sceneJobExecutor.addPriorityJob(
1058 new SceneOutputValueReadingJob(device, deviceStateUpdate.getSceneId()),
1059 deviceStateUpdate.getScenePriority().longValue());
1061 sceneJobExecutor.addPriorityJob(new SceneConfigReadingJob(device, deviceStateUpdate.getSceneId()),
1062 deviceStateUpdate.getScenePriority().longValue());
1064 if (deviceStateUpdate.getScenePriority() == 0) {
1065 updateSensorData(new DeviceOutputValueSensorJob(device), "0");
1067 logger.debug("Add new sceneReadingJob with priority: {} to SceneReadingJobExecuter",
1068 deviceStateUpdate.getScenePriority());
1070 removeSensorJob(device, deviceStateUpdate);
1076 public void registerDeviceListener(DeviceStatusListener deviceListener) {
1077 if (deviceListener != null) {
1078 String id = deviceListener.getDeviceStatusListenerID();
1079 if (id.equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
1080 this.deviceDiscovery = deviceListener;
1081 logger.debug("register Device-Discovery ");
1082 for (Device device : strucMan.getDeviceMap().values()) {
1083 deviceDiscovery.onDeviceAdded(device);
1085 for (Circuit circuit : strucMan.getCircuitMap().values()) {
1086 deviceDiscovery.onDeviceAdded(circuit);
1089 Device intDevice = strucMan.getDeviceByDSID(deviceListener.getDeviceStatusListenerID());
1090 if (intDevice != null) {
1091 logger.debug("register DeviceListener with id: {} to Device ", id);
1092 intDevice.registerDeviceStatusListener(deviceListener);
1094 Circuit intCircuit = strucMan
1095 .getCircuitByDSID(new DSID(deviceListener.getDeviceStatusListenerID()));
1096 if (intCircuit != null) {
1097 logger.debug("register DeviceListener with id: {} to Circuit ", id);
1098 intCircuit.registerDeviceStatusListener(deviceListener);
1100 deviceListener.onDeviceRemoved(null);
1108 public void unregisterDeviceListener(DeviceStatusListener deviceListener) {
1109 if (deviceListener != null) {
1110 String id = deviceListener.getDeviceStatusListenerID();
1111 logger.debug("unregister DeviceListener with id: {}", id);
1112 if (id.equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
1113 this.deviceDiscovery = null;
1115 Device intDevice = strucMan.getDeviceByDSID(deviceListener.getDeviceStatusListenerID());
1116 if (intDevice != null) {
1117 intDevice.unregisterDeviceStatusListener();
1119 Circuit intCircuit = strucMan
1120 .getCircuitByDSID(new DSID(deviceListener.getDeviceStatusListenerID()));
1121 if (intCircuit != null) {
1122 intCircuit.unregisterDeviceStatusListener();
1123 if (deviceDiscovery != null) {
1124 deviceDiscovery.onDeviceAdded(intCircuit);
1133 public void removeDevice(String dSID) {
1134 Device intDevice = strucMan.getDeviceByDSID(dSID);
1135 if (intDevice != null) {
1136 strucMan.deleteDevice(intDevice);
1137 trashDevices.add(new TrashDevice(intDevice));
1142 public void registerTotalPowerConsumptionListener(TotalPowerConsumptionListener totalPowerConsumptionListener) {
1143 this.totalPowerConsumptionListener = totalPowerConsumptionListener;
1147 public void unregisterTotalPowerConsumptionListener() {
1148 this.totalPowerConsumptionListener = null;
1152 public void registerSceneListener(SceneStatusListener sceneListener) {
1153 this.sceneMan.registerSceneListener(sceneListener);
1157 public void unregisterSceneListener(SceneStatusListener sceneListener) {
1158 this.sceneMan.unregisterSceneListener(sceneListener);
1162 public void registerStatusListener(ManagerStatusListener statusListener) {
1163 this.statusListener = statusListener;
1164 this.sceneMan.registerStatusListener(statusListener);
1168 public void unregisterStatusListener() {
1169 this.statusListener = null;
1170 this.sceneMan.unregisterStatusListener();
1174 public void registerConnectionListener(ConnectionListener connectionListener) {
1175 this.connMan.registerConnectionListener(connectionListener);
1179 public void unregisterConnectionListener() {
1180 this.connMan.unregisterConnectionListener();
1184 public int getTotalPowerConsumption() {
1185 List<CachedMeteringValue> cachedConsumptionMeteringValues = digitalSTROMClient
1186 .getLatest(connMan.getSessionToken(), MeteringTypeEnum.CONSUMPTION, DsAPI.ALL_METERS, null);
1187 if (cachedConsumptionMeteringValues != null) {
1188 tempConsumption = 0;
1189 for (CachedMeteringValue value : cachedConsumptionMeteringValues) {
1190 tempConsumption += value.getValue();
1191 if (strucMan.getCircuitByDSID(value.getDsid()) != null) {
1192 strucMan.getCircuitByDSID(value.getDsid()).addMeteringValue(value);
1196 return tempConsumption;
1199 private void getMeterData() {
1200 int val = getTotalPowerConsumption();
1201 if (totalPowerConsumptionListener != null) {
1202 totalPowerConsumptionListener.onTotalPowerConsumptionChanged(val);
1204 val = getTotalEnergyMeterValue();
1205 if (totalPowerConsumptionListener != null) {
1206 totalPowerConsumptionListener.onEnergyMeterValueChanged(val);
1211 public int getTotalEnergyMeterValue() {
1212 List<CachedMeteringValue> cachedEnergyMeteringValues = digitalSTROMClient.getLatest(connMan.getSessionToken(),
1213 MeteringTypeEnum.ENERGY, DsAPI.ALL_METERS, null);
1214 if (cachedEnergyMeteringValues != null) {
1215 tempEnergyMeter = 0;
1216 for (CachedMeteringValue value : cachedEnergyMeteringValues) {
1217 tempEnergyMeter += value.getValue();
1218 if (strucMan.getCircuitByDSID(value.getDsid()) != null) {
1219 strucMan.getCircuitByDSID(value.getDsid()).addMeteringValue(value);
1223 return tempEnergyMeter;
1227 public int getTotalEnergyMeterWsValue() {
1228 List<CachedMeteringValue> cachedEnergyMeteringValues = digitalSTROMClient.getLatest(connMan.getSessionToken(),
1229 MeteringTypeEnum.ENERGY, DsAPI.ALL_METERS, MeteringUnitsEnum.WS);
1230 if (cachedEnergyMeteringValues != null) {
1231 tempEnergyMeterWs = 0;
1232 for (CachedMeteringValue value : cachedEnergyMeteringValues) {
1233 tempEnergyMeterWs += value.getValue();
1234 if (strucMan.getCircuitByDSID(value.getDsid()) != null) {
1235 strucMan.getCircuitByDSID(value.getDsid()).addMeteringValue(value);
1239 return tempEnergyMeterWs;
1242 private void setInizialStateWithLastCallScenes() {
1243 if (sceneMan == null) {
1246 JsonObject response = connMan.getDigitalSTROMAPI().query2(connMan.getSessionToken(), LAST_CALL_SCENE_QUERY);
1247 if (!response.isJsonObject()) {
1250 for (Entry<String, JsonElement> entry : response.entrySet()) {
1251 if (!entry.getValue().isJsonObject()) {
1254 JsonObject zone = entry.getValue().getAsJsonObject();
1258 if (zone.get(JSONApiResponseKeysEnum.ZONE_ID.getKey()) != null) {
1259 zoneID = zone.get(JSONApiResponseKeysEnum.ZONE_ID.getKey()).getAsInt();
1261 for (Entry<String, JsonElement> groupEntry : zone.entrySet()) {
1262 if (groupEntry.getKey().startsWith("group") && groupEntry.getValue().isJsonObject()) {
1263 JsonObject group = groupEntry.getValue().getAsJsonObject();
1264 if (group.get(JSONApiResponseKeysEnum.DEVICES.getKey()) != null) {
1265 if (group.get(JSONApiResponseKeysEnum.GROUP.getKey()) != null) {
1266 groupID = group.get(JSONApiResponseKeysEnum.GROUP.getKey()).getAsShort();
1268 if (group.get(JSONApiResponseKeysEnum.LAST_CALL_SCENE.getKey()) != null) {
1269 sceneID = group.get(JSONApiResponseKeysEnum.LAST_CALL_SCENE.getKey()).getAsShort();
1271 if (zoneID > -1 && groupID > -1 && sceneID > -1) {
1272 logger.debug("initial state, call scene {}-{}-{}", zoneID, groupID, sceneID);
1273 sceneMan.callInternalSceneWithoutDiscovery(zoneID, groupID, sceneID);
1282 public void handleEvent(EventItem eventItem) {
1284 if (EventNames.DEVICE_SENSOR_VALUE.equals(eventItem.getName())
1285 || EventNames.DEVICE_BINARY_INPUT_EVENT.equals(eventItem.getName())) {
1286 logger.debug("Detect {} eventItem = {}", eventItem.getName(), eventItem.toString());
1287 Device dev = getDeviceOfEvent(eventItem);
1289 if (EventNames.DEVICE_SENSOR_VALUE.equals(eventItem.getName())) {
1290 dev.setDeviceSensorByEvent(eventItem);
1292 DeviceBinarayInputEnum binaryInputType = DeviceBinarayInputEnum.getdeviceBinarayInput(Short
1293 .parseShort(eventItem.getProperties().getOrDefault(EventResponseEnum.INPUT_TYPE, "")));
1294 Short newState = Short
1295 .parseShort(eventItem.getProperties().getOrDefault(EventResponseEnum.INPUT_STATE, ""));
1296 if (binaryInputType != null) {
1297 dev.setBinaryInputState(binaryInputType, newState);
1302 } catch (NumberFormatException e) {
1303 logger.debug("Unexpected missing or invalid number while handling event", e);
1307 private Device getDeviceOfEvent(EventItem eventItem) {
1308 if (eventItem.getSource().get(EventResponseEnum.DSID) != null) {
1309 String dSID = eventItem.getSource().get(EventResponseEnum.DSID);
1310 Device dev = strucMan.getDeviceByDSID(dSID);
1312 dev = strucMan.getDeviceByDSUID(dSID);
1320 public List<String> getSupportedEvents() {
1321 return SUPPORTED_EVENTS;
1325 public boolean supportsEvent(String eventName) {
1326 return SUPPORTED_EVENTS.contains(eventName);
1330 public String getUID() {
1331 return getClass().getName();
1335 public void setEventListener(EventListener eventListener) {
1336 if (this.eventListener != null) {
1337 this.eventListener.removeEventHandler(this);
1339 this.eventListener = eventListener;
1343 public void unsetEventListener(EventListener eventListener) {
1344 if (this.eventListener != null) {
1345 this.eventListener.removeEventHandler(this);
1347 this.eventListener = null;