/**
* Copyright (c) 2014-2017 by the respective copyright holders.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.smarthome.binding.digitalstrom.internal.lib.manager.impl;
import java.util.Calendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.config.Config;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.listener.ConnectionListener;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.listener.ManagerStatusListener;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.listener.SceneStatusListener;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.listener.TotalPowerConsumptionListener;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.listener.stateEnums.ManagerStates;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.listener.stateEnums.ManagerTypes;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.manager.ConnectionManager;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.manager.DeviceStatusManager;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.manager.SceneManager;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.manager.StructureManager;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.sensorJobExecutor.SceneReadingJobExecutor;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.sensorJobExecutor.SensorJobExecutor;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.sensorJobExecutor.sensorJob.SensorJob;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.sensorJobExecutor.sensorJob.impl.DeviceConsumptionSensorJob;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.sensorJobExecutor.sensorJob.impl.DeviceOutputValueSensorJob;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.sensorJobExecutor.sensorJob.impl.SceneConfigReadingJob;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.sensorJobExecutor.sensorJob.impl.SceneOutputValueReadingJob;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.serverConnection.DsAPI;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.Device;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.deviceParameters.CachedMeteringValue;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.deviceParameters.DSID;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.deviceParameters.DeviceConstants;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.deviceParameters.DeviceStateUpdate;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.deviceParameters.DeviceStateUpdateImpl;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.deviceParameters.MeteringTypeEnum;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.deviceParameters.MeteringUnitsEnum;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.deviceParameters.SensorEnum;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.scene.constants.ApartmentSceneEnum;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.scene.constants.SceneEnum;
import org.eclipse.smarthome.core.common.ThreadPoolManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DeviceStatusManagerImpl} is the implementation of the the {@link DeviceStatusManager}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class DeviceStatusManagerImpl implements DeviceStatusManager {
private Logger logger = LoggerFactory.getLogger(DeviceStatusManagerImpl.class);
private final ScheduledExecutorService scheduler = ThreadPoolManager.getScheduledPool(Config.THREADPOOL_NAME);
private ScheduledFuture<?> pollingScheduler = null;
private ConnectionManager connMan;
private StructureManager strucMan;
private SceneManager sceneMan;
private DsAPI digitalSTROMClient;
private Config config;
private SensorJobExecutor sensorJobExecutor = null;
private SceneReadingJobExecutor sceneJobExecutor = null;
private List<String> meters = null;
private List<TrashDevice> trashDevices = new LinkedList<TrashDevice>();
private long lastBinCheck = 0;
private ManagerStates state = ManagerStates.STOPPED;
private int tempConsumption = 0;
private int totalPowerConsumption = 0;
private int tempEnergyMeter = 0;
private int totalEnergyMeter = 0;
private DeviceStatusListener deviceDiscovery = null;
private TotalPowerConsumptionListener totalPowerConsumptionListener = null;
private ManagerStatusListener statusListener = null;
public DeviceStatusManagerImpl(Config config) {
init(new ConnectionManagerImpl(config), null, null, null);
}
public DeviceStatusManagerImpl(String hostAddress, String user, String password, String appToken) {
init(new ConnectionManagerImpl(hostAddress, user, password, false), null, null, null);
}
public DeviceStatusManagerImpl(ConnectionManager connMan, StructureManager strucMan, SceneManager sceneMan) {
init(connMan, strucMan, sceneMan, null);
}
public DeviceStatusManagerImpl(ConnectionManager connMan, StructureManager strucMan, SceneManager sceneMan,
ManagerStatusListener statusListener) {
init(connMan, strucMan, sceneMan, statusListener);
}
public DeviceStatusManagerImpl(ConnectionManager connMan) {
init(connMan, null, null, null);
}
private void init(ConnectionManager connMan, StructureManager strucMan, SceneManager sceneMan,
ManagerStatusListener statusListener) {
this.connMan = connMan;
this.digitalSTROMClient = connMan.getDigitalSTROMAPI();
this.config = connMan.getConfig();
if (strucMan != null) {
this.strucMan = strucMan;
} else {
this.strucMan = new StructureManagerImpl();
}
if (sceneMan != null) {
this.sceneMan = sceneMan;
} else {
this.sceneMan = new SceneManagerImpl(connMan, strucMan, statusListener);
}
this.statusListener = statusListener;
}
private class PollingRunnable implements Runnable {
private boolean devicesLoaded = false;
private long nextSensorUpdate = 0;
@Override
public void run() {
if (connMan.checkConnection()) {
if (!getManagerState().equals(ManagerStates.RUNNING)) {
logger.debug("Thread started");
if (devicesLoaded) {
stateChanged(ManagerStates.RUNNING);
} else {
stateChanged(ManagerStates.INITIALIZING);
}
}
HashMap<DSID, Device> tempDeviceMap;
if (strucMan.getDeviceMap() != null) {
tempDeviceMap = (HashMap<DSID, Device>) strucMan.getDeviceMap();
} else {
tempDeviceMap = new HashMap<DSID, Device>();
}
List<Device> currentDeviceList = digitalSTROMClient.getApartmentDevices(connMan.getSessionToken(),
false);
// update the current total power consumption
if (totalPowerConsumptionListener != null && nextSensorUpdate <= System.currentTimeMillis()) {
meters = digitalSTROMClient.getMeterList(connMan.getSessionToken());
totalPowerConsumptionListener.onTotalPowerConsumptionChanged(getTotalPowerConsumption());
totalPowerConsumptionListener.onEnergyMeterValueChanged(getTotalEnergyMeterValue());
nextSensorUpdate = System.currentTimeMillis() + config.getTotalPowerUpdateInterval();
}
while (!currentDeviceList.isEmpty()) {
Device currentDevice = currentDeviceList.remove(0);
DSID currentDeviceDSID = currentDevice.getDSID();
Device eshDevice = tempDeviceMap.remove(currentDeviceDSID);
if (eshDevice != null) {
checkDeviceConfig(currentDevice, eshDevice);
if (eshDevice.isPresent()) {
// check device state updates
while (!eshDevice.isDeviceUpToDate()) {
DeviceStateUpdate deviceStateUpdate = eshDevice.getNextDeviceUpdateState();
if (deviceStateUpdate != null) {
switch (deviceStateUpdate.getType()) {
case DeviceStateUpdate.UPDATE_BRIGHTNESS:
case DeviceStateUpdate.UPDATE_SLAT_ANGLE_INCREASE:
case DeviceStateUpdate.UPDATE_SLAT_ANGLE_DECREASE:
filterCommand(deviceStateUpdate, eshDevice);
break;
case DeviceStateUpdate.UPDATE_SCENE_CONFIG:
case DeviceStateUpdate.UPDATE_SCENE_OUTPUT:
updateSceneData(eshDevice, deviceStateUpdate);
break;
case DeviceStateUpdate.UPDATE_OUTPUT_VALUE:
readOutputValue(eshDevice);
break;
default:
sendComandsToDSS(eshDevice, deviceStateUpdate);
}
}
}
}
} else {
logger.debug("Found new device!");
if (trashDevices.isEmpty()) {
currentDevice.setConfig(config);
strucMan.addDeviceToStructure(currentDevice);
logger.debug("trashDevices are empty, add Device with dSID "
+ currentDevice.getDSID().toString() + " to the deviceMap!");
} else {
logger.debug("Search device in trashDevices.");
TrashDevice foundTrashDevice = null;
for (TrashDevice trashDevice : trashDevices) {
if (trashDevice != null) {
if (trashDevice.getDevice().equals(currentDevice)) {
foundTrashDevice = trashDevice;
logger.debug(
"Found device in trashDevices, add TrashDevice with dSID {} to the StructureManager!",
currentDeviceDSID);
}
}
}
if (foundTrashDevice != null) {
trashDevices.remove(foundTrashDevice);
strucMan.addDeviceToStructure(foundTrashDevice.getDevice());
} else {
strucMan.addDeviceToStructure(currentDevice);
logger.debug(
"Can't find device in trashDevices, add Device with dSID: {} to the StructureManager!",
currentDeviceDSID);
}
}
if (deviceDiscovery != null) {
if (currentDevice.isDeviceWithOutput()) {
deviceDiscovery.onDeviceAdded(currentDevice);
logger.debug("inform DeviceStatusListener: {} about removed device with dSID {}",
DeviceStatusListener.DEVICE_DISCOVERY, currentDevice.getDSID().getValue());
}
} else {
logger.debug(
"The device discovery is not registrated, can't inform device discovery about found device.");
}
}
}
if (!devicesLoaded && strucMan.getDeviceMap() != null) {
if (!strucMan.getDeviceMap().values().isEmpty()) {
logger.debug("Devices loaded");
devicesLoaded = true;
stateChanged(ManagerStates.RUNNING);
}
}
if (!sceneMan.scenesGenerated()
&& !sceneMan.getManagerState().equals(ManagerStates.GENERATING_SCENES)) {
logger.debug(sceneMan.getManagerState().toString());
sceneMan.generateScenes();
}
for (Device device : tempDeviceMap.values()) {
logger.debug("Found removed devices.");
trashDevices.add(new TrashDevice(device));
DeviceStatusListener listener = device.unregisterDeviceStateListener();
if (listener != null) {
listener.onDeviceRemoved(null);
}
strucMan.deleteDevice(device);
logger.debug("Add device with dSID {} to trashDevices", device.getDSID().getValue());
if (deviceDiscovery != null) {
deviceDiscovery.onDeviceRemoved(device);
logger.debug("inform DeviceStatusListener: {} about removed device with dSID {}",
DeviceStatusListener.DEVICE_DISCOVERY, device.getDSID().getValue());
} else {
logger.debug(
"The device-Discovery is not registrated, can't inform device discovery about removed device.");
}
}
if (!trashDevices.isEmpty() && (lastBinCheck + config.getBinCheckTime() < System.currentTimeMillis())) {
for (TrashDevice trashDevice : trashDevices) {
if (trashDevice.isTimeToDelete(Calendar.getInstance().get(Calendar.DAY_OF_YEAR))) {
logger.debug("Found trashDevice that have to delete!");
trashDevices.remove(trashDevice);
logger.debug("Delete trashDevice: " + trashDevice.getDevice().getDSID().getValue());
}
}
lastBinCheck = System.currentTimeMillis();
}
}
}
private void filterCommand(DeviceStateUpdate deviceStateUpdate, Device device) {
String stateUpdateType = deviceStateUpdate.getType();
short newAngle = 0;
if (stateUpdateType.equals(DeviceStateUpdate.UPDATE_SLAT_ANGLE_INCREASE)
|| stateUpdateType.equals(DeviceStateUpdate.UPDATE_SLAT_ANGLE_DECREASE)) {
newAngle = device.getAnglePosition();
}
DeviceStateUpdate nextDeviceStateUpdate = device.getNextDeviceUpdateState();
while (nextDeviceStateUpdate != null && nextDeviceStateUpdate.getType().equals(stateUpdateType)) {
switch (stateUpdateType) {
case DeviceStateUpdate.UPDATE_BRIGHTNESS:
deviceStateUpdate = nextDeviceStateUpdate;
nextDeviceStateUpdate = device.getNextDeviceUpdateState();
break;
case DeviceStateUpdate.UPDATE_SLAT_ANGLE_INCREASE:
if (deviceStateUpdate.getValue() == 1) {
newAngle = (short) (newAngle + DeviceConstants.ANGLE_STEP_SLAT);
}
break;
case DeviceStateUpdate.UPDATE_SLAT_ANGLE_DECREASE:
if (deviceStateUpdate.getValue() == 1) {
newAngle = (short) (newAngle - DeviceConstants.ANGLE_STEP_SLAT);
}
break;
}
}
if (stateUpdateType.equals(DeviceStateUpdate.UPDATE_SLAT_ANGLE_INCREASE)
|| stateUpdateType.equals(DeviceStateUpdate.UPDATE_SLAT_ANGLE_DECREASE)) {
if (newAngle > device.getMaxSlatAngle()) {
newAngle = (short) device.getMaxSlatAngle();
}
if (newAngle < device.getMinSlatAngle()) {
newAngle = (short) device.getMinSlatAngle();
}
if (!(stateUpdateType.equals(DeviceStateUpdate.UPDATE_SLAT_ANGLE_INCREASE)
&& checkAngleIsMinMax(device) == 1)
|| !(stateUpdateType.equals(DeviceStateUpdate.UPDATE_SLAT_ANGLE_DECREASE)
&& checkAngleIsMinMax(device) == 0)) {
deviceStateUpdate = new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_SLAT_ANGLE, newAngle);
}
}
sendComandsToDSS(device, deviceStateUpdate);
if (nextDeviceStateUpdate != null) {
if (deviceStateUpdate.getType() == DeviceStateUpdate.UPDATE_SCENE_CONFIG
|| deviceStateUpdate.getType() == DeviceStateUpdate.UPDATE_SCENE_OUTPUT) {
updateSceneData(device, deviceStateUpdate);
} else {
sendComandsToDSS(device, deviceStateUpdate);
}
}
}
};
@Override
public ManagerTypes getManagerType() {
return ManagerTypes.DEVICE_STATUS_MANAGER;
}
@Override
public ManagerStates getManagerState() {
return state;
}
private synchronized void stateChanged(ManagerStates state) {
if (statusListener != null) {
this.state = state;
statusListener.onStatusChanged(ManagerTypes.DEVICE_STATUS_MANAGER, state);
}
}
@Override
public synchronized void start() {
logger.debug("start pollingScheduler");
if (pollingScheduler == null || pollingScheduler.isCancelled()) {
pollingScheduler = scheduler.scheduleAtFixedRate(new PollingRunnable(), 0, config.getPollingFrequency(),
TimeUnit.MILLISECONDS);
sceneMan.start();
}
if (sceneJobExecutor != null) {
this.sceneJobExecutor.startExecutor();
}
if (sensorJobExecutor != null) {
this.sensorJobExecutor.startExecutor();
}
}
@Override
public synchronized void stop() {
logger.debug("stop pollingScheduler");
if (sceneMan != null) {
sceneMan.stop();
}
if (pollingScheduler != null && !pollingScheduler.isCancelled()) {
pollingScheduler.cancel(true);
pollingScheduler = null;
stateChanged(ManagerStates.STOPPED);
}
if (sceneJobExecutor != null) {
this.sceneJobExecutor.shutdown();
}
if (sensorJobExecutor != null) {
this.sensorJobExecutor.shutdown();
}
}
/**
* The {@link TrashDevice} saves not present {@link Device}'s, but at this point not deleted from the
* digitalSTROM-System, temporary to get back the configuration of the {@link Device}'s faster.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
private class TrashDevice {
private Device device;
private int timeStamp;
/**
* Creates a new {@link TrashDevice}.
*
* @param device
*/
public TrashDevice(Device device) {
this.device = device;
this.timeStamp = Calendar.getInstance().get(Calendar.DAY_OF_YEAR);
}
/**
* Returns the saved {@link Device}.
*
* @return device
*/
public Device getDevice() {
return device;
}
/**
* Returns true if the time for the {@link TrashDevice} is over and it can be deleted.
*
* @param dayOfYear
* @return true = time to delete | false = not time to delete
*/
public boolean isTimeToDelete(int dayOfYear) {
return this.timeStamp + config.getTrashDeviceDeleteTime() <= dayOfYear;
}
@Override
public boolean equals(Object object) {
return object instanceof TrashDevice
? this.device.getDSID().equals(((TrashDevice) object).getDevice().getDSID()) : false;
}
}
private void checkDeviceConfig(Device newDevice, Device internalDevice) {
if (newDevice == null || internalDevice == null) {
return;
}
// check device availability has changed and inform the deviceStatusListener about the change.
// NOTE:
// The device is not availability for the digitalSTROM-Server, it has not been deleted and are therefore set to
// OFFLINE.
// To delete an alternate algorithm is responsible.
if (newDevice.isPresent() != internalDevice.isPresent()) {
internalDevice.setIsPresent(newDevice.isPresent());
}
if (newDevice.getMeterDSID() != null && !newDevice.getMeterDSID().equals(internalDevice.getMeterDSID())) {
internalDevice.setMeterDSID(newDevice.getMeterDSID().getValue());
}
if (newDevice.getFunctionalColorGroup() != null
&& !newDevice.getFunctionalColorGroup().equals(internalDevice.getFunctionalColorGroup())) {
internalDevice.setFunctionalColorGroup(newDevice.getFunctionalColorGroup());
}
if (newDevice.getName() != null && !newDevice.getName().equals(internalDevice.getName())) {
internalDevice.setName(newDevice.getName());
}
if (newDevice.getOutputMode() != null && !newDevice.getOutputMode().equals(internalDevice.getOutputMode())) {
internalDevice.setOutputMode(newDevice.getOutputMode());
}
strucMan.updateDevice(newDevice);
}
private long lastSceneCall = 0;
private long sleepTime = 0;
@Override
public synchronized void sendSceneComandsToDSS(InternalScene scene, boolean call_undo) {
if (scene != null) {
if (lastSceneCall + 1000 > System.currentTimeMillis()) {
sleepTime = System.currentTimeMillis() - lastSceneCall;
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
logger.error("An exception occurred", e);
}
}
if (this.connMan.checkConnection()) {
lastSceneCall = System.currentTimeMillis();
boolean requestSuccsessfull = false;
if (scene.getZoneID() == 0) {
if (call_undo) {
logger.debug(scene.getGroupID() + " " + scene.getSceneID() + " "
+ ApartmentSceneEnum.getApartmentScene(scene.getSceneID()));
requestSuccsessfull = this.digitalSTROMClient.callApartmentScene(connMan.getSessionToken(),
scene.getGroupID(), null, ApartmentSceneEnum.getApartmentScene(scene.getSceneID()),
false);
} else {
requestSuccsessfull = this.digitalSTROMClient.undoApartmentScene(connMan.getSessionToken(),
scene.getGroupID(), null, ApartmentSceneEnum.getApartmentScene(scene.getSceneID()));
}
} else {
if (call_undo) {
requestSuccsessfull = this.digitalSTROMClient.callZoneScene(connMan.getSessionToken(),
scene.getZoneID(), null, scene.getGroupID(), null,
SceneEnum.getScene(scene.getSceneID()), false);
} else {
requestSuccsessfull = this.digitalSTROMClient.undoZoneScene(connMan.getSessionToken(),
scene.getZoneID(), null, scene.getGroupID(), null,
SceneEnum.getScene(scene.getSceneID()));
}
}
logger.debug("Was the scene call succsessful?: " + requestSuccsessfull);
if (requestSuccsessfull) {
this.sceneMan.addEcho(scene.getID());
if (call_undo) {
scene.activateScene();
} else {
scene.deactivateScene();
}
}
}
}
}
@Override
public synchronized void sendStopComandsToDSS(final Device device) {
scheduler.execute(new Runnable() {
@Override
public void run() {
if (connMan.checkConnection()) {
}
if (digitalSTROMClient.callDeviceScene(connMan.getSessionToken(), device.getDSID(), null,
SceneEnum.STOP, true)) {
sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.STOP.getSceneNumber());
readOutputValue(device);
}
}
});
}
private void readOutputValue(Device device) {
short outputIndex = DeviceConstants.DEVICE_SENSOR_OUTPUT;
if (device.isShade()) {
outputIndex = DeviceConstants.DEVICE_SENSOR_SLAT_POSITION_OUTPUT;
}
int outputValue = this.digitalSTROMClient.getDeviceOutputValue(connMan.getSessionToken(), device.getDSID(),
null, outputIndex);
if (outputValue != -1) {
if (!device.isShade()) {
device.updateInternalDeviceState(
new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_BRIGHTNESS, outputValue));
} else {
device.updateInternalDeviceState(
new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_SLATPOSITION, outputValue));
if (device.isBlind()) {
outputValue = this.digitalSTROMClient.getDeviceOutputValue(connMan.getSessionToken(),
device.getDSID(), null, DeviceConstants.DEVICE_SENSOR_SLAT_ANGLE_OUTPUT);
device.updateInternalDeviceState(
new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_SLAT_ANGLE, outputValue));
}
}
}
}
public synchronized void updateDevice(Device eshDevice) {
logger.debug("Check device updates");
// check device state updates
while (!eshDevice.isDeviceUpToDate()) {
DeviceStateUpdate deviceStateUpdate = eshDevice.getNextDeviceUpdateState();
if (deviceStateUpdate != null) {
if (deviceStateUpdate.getType() != DeviceStateUpdate.UPDATE_BRIGHTNESS) {
if (deviceStateUpdate.getType() == DeviceStateUpdate.UPDATE_SCENE_CONFIG
|| deviceStateUpdate.getType() == DeviceStateUpdate.UPDATE_SCENE_OUTPUT) {
updateSceneData(eshDevice, deviceStateUpdate);
} else {
sendComandsToDSS(eshDevice, deviceStateUpdate);
}
} else {
DeviceStateUpdate nextDeviceStateUpdate = eshDevice.getNextDeviceUpdateState();
while (nextDeviceStateUpdate != null
&& nextDeviceStateUpdate.getType() == DeviceStateUpdate.UPDATE_BRIGHTNESS) {
deviceStateUpdate = nextDeviceStateUpdate;
nextDeviceStateUpdate = eshDevice.getNextDeviceUpdateState();
}
sendComandsToDSS(eshDevice, deviceStateUpdate);
if (nextDeviceStateUpdate != null) {
if (deviceStateUpdate.getType() == DeviceStateUpdate.UPDATE_SCENE_CONFIG
|| deviceStateUpdate.getType() == DeviceStateUpdate.UPDATE_SCENE_OUTPUT) {
updateSceneData(eshDevice, deviceStateUpdate);
} else {
sendComandsToDSS(eshDevice, deviceStateUpdate);
}
}
}
}
}
}
/**
* Checks the output value of a {@link Device} and return 0, if the output value or slat position is min and 1, if
* the output value or slat position is max, otherwise it returns -1.
*
* @param device
* @return 0 = output value is min, 1 device value is min, otherwise -1
*/
private short checkIsAllreadyMinMax(Device device) {
if (device.isShade()) {
if (device.getSlatPosition() == device.getMaxSlatPosition()) {
if (device.isBlind()) {
if (device.getAnglePosition() == device.getMaxSlatAngle()) {
return 1;
} else {
return -1;
}
}
return 1;
}
if (device.getSlatPosition() == device.getMinSlatPosition()) {
if (device.isBlind()) {
if (device.getAnglePosition() == device.getMinSlatAngle()) {
return 0;
} else {
return -1;
}
}
return 0;
}
} else {
if (device.getOutputValue() == device.getMaxOutputValue()) {
return 1;
}
if (device.getOutputValue() == device.getMinOutputValue() || device.getOutputValue() <= 0) {
return 0;
}
}
return -1;
}
/**
* Checks the angle value of a {@link Device} and return 0, if the angle value is min and 1, if the angle value is
* max, otherwise it returns -1.
*
* @param device
* @return 0 = angle value is min, 1 angle value is min, otherwise -1
*/
private short checkAngleIsMinMax(Device device) {
if (device.getAnglePosition() == device.getMaxSlatAngle()) {
return 1;
}
if (device.getAnglePosition() == device.getMinSlatAngle()) {
return 1;
}
return -1;
}
@Override
public synchronized void sendComandsToDSS(Device device, DeviceStateUpdate deviceStateUpdate) {
if (connMan.checkConnection()) {
boolean requestSuccsessful = false;
boolean commandHaveNoEffect = false;
if (deviceStateUpdate != null) {
switch (deviceStateUpdate.getType()) {
case DeviceStateUpdate.UPDATE_BRIGHTNESS_DECREASE:
case DeviceStateUpdate.UPDATE_SLAT_DECREASE:
if (checkIsAllreadyMinMax(device) != 0) {
requestSuccsessful = digitalSTROMClient.decreaseValue(connMan.getSessionToken(),
device.getDSID());
if (requestSuccsessful) {
sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.DECREMENT.getSceneNumber());
}
} else {
commandHaveNoEffect = true;
}
break;
case DeviceStateUpdate.UPDATE_BRIGHTNESS_INCREASE:
case DeviceStateUpdate.UPDATE_SLAT_INCREASE:
if (checkIsAllreadyMinMax(device) != 1) {
requestSuccsessful = digitalSTROMClient.increaseValue(connMan.getSessionToken(),
device.getDSID());
if (requestSuccsessful) {
sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.INCREMENT.getSceneNumber());
}
} else {
commandHaveNoEffect = true;
}
break;
case DeviceStateUpdate.UPDATE_BRIGHTNESS:
if (device.getOutputValue() != deviceStateUpdate.getValue()) {
requestSuccsessful = digitalSTROMClient.setDeviceValue(connMan.getSessionToken(),
device.getDSID(), null, deviceStateUpdate.getValue());
} else {
commandHaveNoEffect = true;
}
break;
case DeviceStateUpdate.UPDATE_OPEN_CLOSE:
case DeviceStateUpdate.UPDATE_ON_OFF:
if (deviceStateUpdate.getValue() > 0) {
if (checkIsAllreadyMinMax(device) != 1) {
requestSuccsessful = digitalSTROMClient.turnDeviceOn(connMan.getSessionToken(),
device.getDSID(), null);
if (requestSuccsessful) {
sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.MAXIMUM.getSceneNumber());
}
} else {
commandHaveNoEffect = true;
}
} else {
if (checkIsAllreadyMinMax(device) != 0) {
requestSuccsessful = digitalSTROMClient.turnDeviceOff(connMan.getSessionToken(),
device.getDSID(), null);
if (requestSuccsessful) {
sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.MINIMUM.getSceneNumber());
}
if (sensorJobExecutor != null) {
sensorJobExecutor.removeSensorJobs(device);
}
} else {
commandHaveNoEffect = true;
}
}
break;
case DeviceStateUpdate.UPDATE_SLATPOSITION:
if (device.getSlatPosition() != deviceStateUpdate.getValue()) {
requestSuccsessful = digitalSTROMClient.setDeviceOutputValue(connMan.getSessionToken(),
device.getDSID(), null, DeviceConstants.DEVICE_SENSOR_SLAT_POSITION_OUTPUT,
deviceStateUpdate.getValue());
} else {
commandHaveNoEffect = true;
}
break;
case DeviceStateUpdate.UPDATE_SLAT_STOP:
this.sendStopComandsToDSS(device);
break;
case DeviceStateUpdate.UPDATE_SLAT_MOVE:
if (deviceStateUpdate.getValue() > 0) {
requestSuccsessful = digitalSTROMClient.turnDeviceOn(connMan.getSessionToken(),
device.getDSID(), null);
if (requestSuccsessful) {
sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.MAXIMUM.getSceneNumber());
}
} else {
requestSuccsessful = digitalSTROMClient.turnDeviceOff(connMan.getSessionToken(),
device.getDSID(), null);
if (requestSuccsessful) {
sceneMan.addEcho(device.getDSID().getValue(), SceneEnum.MINIMUM.getSceneNumber());
}
if (sensorJobExecutor != null) {
sensorJobExecutor.removeSensorJobs(device);
}
}
break;
case DeviceStateUpdate.UPDATE_CALL_SCENE:
if (SceneEnum.getScene((short) deviceStateUpdate.getValue()) != null) {
requestSuccsessful = digitalSTROMClient.callDeviceScene(connMan.getSessionToken(),
device.getDSID(), null, SceneEnum.getScene((short) deviceStateUpdate.getValue()),
true);
}
break;
case DeviceStateUpdate.UPDATE_UNDO_SCENE:
if (SceneEnum.getScene((short) deviceStateUpdate.getValue()) != null) {
requestSuccsessful = digitalSTROMClient.undoDeviceScene(connMan.getSessionToken(),
device.getDSID(), SceneEnum.getScene((short) deviceStateUpdate.getValue()));
}
break;
case DeviceStateUpdate.UPDATE_ACTIVE_POWER:
if (deviceStateUpdate.getValue() == 0) {
logger.debug("Device need active power SensorData update");
updateSensorData(new DeviceConsumptionSensorJob(device, SensorEnum.ACTIVE_POWER),
device.getActivePowerRefreshPriority());
return;
} else {
int consumption = this.digitalSTROMClient.getDeviceSensorValue(connMan.getSessionToken(),
device.getDSID(), null, SensorEnum.ACTIVE_POWER);
if (consumption >= 0) {
device.updateInternalDeviceState(
new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_ACTIVE_POWER, consumption));
requestSuccsessful = true;
}
}
case DeviceStateUpdate.UPDATE_OUTPUT_CURRENT:
if (deviceStateUpdate.getValue() == 0) {
logger.debug("Device need output current SensorData update");
updateSensorData(new DeviceConsumptionSensorJob(device, SensorEnum.OUTPUT_CURRENT),
device.getOutputCurrentRefreshPriority());
return;
} else {
int consumption = this.digitalSTROMClient.getDeviceSensorValue(connMan.getSessionToken(),
device.getDSID(), null, SensorEnum.OUTPUT_CURRENT);
if (consumption >= 0) {
device.updateInternalDeviceState(new DeviceStateUpdateImpl(
DeviceStateUpdate.UPDATE_OUTPUT_CURRENT, consumption));
requestSuccsessful = true;
}
}
case DeviceStateUpdate.UPDATE_ELECTRIC_METER:
if (deviceStateUpdate.getValue() == 0) {
logger.debug("Device need electric meter SensorData update");
updateSensorData(new DeviceConsumptionSensorJob(device, SensorEnum.ELECTRIC_METER),
device.getElectricMeterRefreshPriority());
return;
} else {
int consumption = this.digitalSTROMClient.getDeviceSensorValue(connMan.getSessionToken(),
device.getDSID(), null, SensorEnum.ELECTRIC_METER);
if (consumption >= 0) {
device.updateInternalDeviceState(new DeviceStateUpdateImpl(
DeviceStateUpdate.UPDATE_ELECTRIC_METER, consumption));
requestSuccsessful = true;
}
}
case DeviceStateUpdate.UPDATE_SLAT_ANGLE_DECREASE:
// By UPDATE_SLAT_ANGLE_DECREASE, UPDATE_SLAT_ANGLE_INCREASE with value unequal 1 which will
// handle in the pollingRunnable and UPDATE_OPEN_CLOSE_ANGLE the value will be set without
// checking, because it was triggered by setting the slat position.
requestSuccsessful = true;
break;
case DeviceStateUpdate.UPDATE_SLAT_ANGLE_INCREASE:
requestSuccsessful = true;
break;
case DeviceStateUpdate.UPDATE_OPEN_CLOSE_ANGLE:
requestSuccsessful = true;
break;
case DeviceStateUpdate.UPDATE_SLAT_ANGLE:
if (device.getAnglePosition() != deviceStateUpdate.getValue()) {
requestSuccsessful = digitalSTROMClient.setDeviceOutputValue(connMan.getSessionToken(),
device.getDSID(), null, DeviceConstants.DEVICE_SENSOR_SLAT_ANGLE_OUTPUT,
deviceStateUpdate.getValue());
} else {
commandHaveNoEffect = true;
}
break;
case DeviceStateUpdate.REFRESH_OUTPUT:
readOutputValue(device);
logger.debug("Inizalize output value reading for device with dSID {}.",
device.getDSID().getValue());
return;
default:
return;
}
if (commandHaveNoEffect) {
logger.debug("Command {} for device with dSID {} not send to dSS, because it has no effect!",
deviceStateUpdate.getType(), device.getDSID().getValue());
return;
}
if (requestSuccsessful) {
logger.debug("Send {} command to dSS and updateInternalDeviceState for device with dSID {}.",
deviceStateUpdate.getType(), device.getDSID().getValue());
device.updateInternalDeviceState(deviceStateUpdate);
} else {
logger.debug("Can't send {} command for device with dSID {} to dSS!", deviceStateUpdate.getType(),
device.getDSID().getValue());
}
}
}
}
@Override
public void updateSensorData(SensorJob sensorJob, String priority) {
if (sensorJobExecutor == null) {
sensorJobExecutor = new SensorJobExecutor(connMan);
this.sensorJobExecutor.startExecutor();
}
if (sensorJob != null && priority != null) {
if (priority.contains(Config.REFRESH_PRIORITY_HIGH)) {
sensorJobExecutor.addHighPriorityJob(sensorJob);
} else if (priority.contains(Config.REFRESH_PRIORITY_MEDIUM)) {
sensorJobExecutor.addMediumPriorityJob(sensorJob);
} else if (priority.contains(Config.REFRESH_PRIORITY_LOW)) {
sensorJobExecutor.addLowPriorityJob(sensorJob);
} else {
logger.debug("Sensor data update priority do {} not exist! Please check the input!", priority);
return;
}
logger.debug("Add new sensorJob {} with priority: {} to sensorJobExecuter", sensorJob.toString(), priority);
}
}
@Override
public void updateSceneData(Device device, DeviceStateUpdate deviceStateUpdate) {
if (sceneJobExecutor == null) {
sceneJobExecutor = new SceneReadingJobExecutor(connMan);
this.sceneJobExecutor.startExecutor();
}
if (deviceStateUpdate != null) {
if (deviceStateUpdate.getValue() < 1000) {
if (deviceStateUpdate.getType().equals(DeviceStateUpdate.UPDATE_SCENE_OUTPUT)) {
sceneJobExecutor.addHighPriorityJob(
new SceneOutputValueReadingJob(device, (short) deviceStateUpdate.getValue()));
DeviceOutputValueSensorJob devOutJob = new DeviceOutputValueSensorJob(device);
devOutJob.setInitalisationTime(0);
updateSensorData(devOutJob, Config.REFRESH_PRIORITY_HIGH);
} else {
sceneJobExecutor.addHighPriorityJob(
new SceneConfigReadingJob(device, (short) deviceStateUpdate.getValue()));
}
} else if (deviceStateUpdate.getValue() < 2000) {
if (deviceStateUpdate.getType().equals(DeviceStateUpdate.UPDATE_SCENE_OUTPUT)) {
sceneJobExecutor.addMediumPriorityJob(
new SceneOutputValueReadingJob(device, (short) (deviceStateUpdate.getValue() - 1000)));
} else {
sceneJobExecutor.addMediumPriorityJob(
new SceneConfigReadingJob(device, (short) (deviceStateUpdate.getValue() - 1000)));
}
} else if (deviceStateUpdate.getValue() >= 2000 && deviceStateUpdate.getValue() < 3000) {
if (deviceStateUpdate.getType().equals(DeviceStateUpdate.UPDATE_SCENE_OUTPUT)) {
sceneJobExecutor.addLowPriorityJob(
new SceneOutputValueReadingJob(device, (short) (deviceStateUpdate.getValue() - 2000)));
} else {
sceneJobExecutor.addLowPriorityJob(
new SceneConfigReadingJob(device, (short) (deviceStateUpdate.getValue() - 2000)));
}
} else {
logger.debug("Device state update value {} is out of range. Please check the input!",
deviceStateUpdate.getValue());
return;
}
logger.debug("Add new sceneReadingJob with priority: {} to SceneReadingJobExecuter",
new Integer(deviceStateUpdate.getValue()).toString().charAt(0));
}
}
@Override
public void registerDeviceListener(DeviceStatusListener deviceListener) {
if (deviceListener != null) {
String id = deviceListener.getDeviceStatusListenerID();
logger.debug("register DeviceListener with id: " + id);
if (id.equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
this.deviceDiscovery = deviceListener;
for (Device device : strucMan.getDeviceMap().values()) {
deviceDiscovery.onDeviceAdded(device);
}
} else {
Device intDevice = strucMan.getDeviceByDSID(deviceListener.getDeviceStatusListenerID());
if (intDevice != null) {
intDevice.registerDeviceStateListener(deviceListener);
} else {
deviceListener.onDeviceRemoved(null);
}
}
}
}
@Override
public void unregisterDeviceListener(DeviceStatusListener deviceListener) {
if (deviceListener != null) {
String id = deviceListener.getDeviceStatusListenerID();
if (id.equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
this.deviceDiscovery = null;
} else {
Device intDevice = strucMan.getDeviceByDSID(deviceListener.getDeviceStatusListenerID());
if (intDevice != null) {
intDevice.unregisterDeviceStateListener();
}
}
}
}
@Override
public void removeDevice(String dSID) {
Device intDevice = strucMan.getDeviceByDSID(dSID);
if (intDevice != null) {
strucMan.deleteDevice(intDevice);
trashDevices.add(new TrashDevice(intDevice));
}
}
@Override
public void registerTotalPowerConsumptionListener(TotalPowerConsumptionListener totalPowerConsumptionListener) {
this.totalPowerConsumptionListener = totalPowerConsumptionListener;
}
@Override
public void unregisterTotalPowerConsumptionListener() {
this.totalPowerConsumptionListener = null;
}
@Override
public void registerSceneListener(SceneStatusListener sceneListener) {
this.sceneMan.registerSceneListener(sceneListener);
}
@Override
public void unregisterSceneListener(SceneStatusListener sceneListener) {
this.sceneMan.unregisterSceneListener(sceneListener);
}
@Override
public void registerStatusListener(ManagerStatusListener statusListener) {
this.statusListener = statusListener;
this.sceneMan.registerStatusListener(statusListener);
}
@Override
public void unregisterStatusListener() {
this.statusListener = null;
this.sceneMan.unregisterStatusListener();
}
@Override
public void registerConnectionListener(ConnectionListener connectionListener) {
this.connMan.registerConnectionListener(connectionListener);
}
@Override
public void unregisterConnectionListener() {
this.connMan.unregisterConnectionListener();
}
@Override
public int getTotalPowerConsumption() {
List<CachedMeteringValue> cachedConsumptionMeteringValues = digitalSTROMClient
.getLatest(connMan.getSessionToken(), MeteringTypeEnum.consumption, meters, MeteringUnitsEnum.W);
if (cachedConsumptionMeteringValues != null) {
tempConsumption = 0;
for (CachedMeteringValue value : cachedConsumptionMeteringValues) {
tempConsumption += value.getValue();
}
if (tempConsumption != totalPowerConsumption) {
totalPowerConsumption = tempConsumption;
}
}
return totalPowerConsumption;
}
@Override
public int getTotalEnergyMeterValue() {
List<CachedMeteringValue> cachedEnergyMeteringValues = digitalSTROMClient.getLatest(connMan.getSessionToken(),
MeteringTypeEnum.energy, meters, MeteringUnitsEnum.Wh);
if (cachedEnergyMeteringValues != null) {
tempEnergyMeter = 0;
for (CachedMeteringValue value : cachedEnergyMeteringValues) {
tempEnergyMeter += value.getValue();
}
if (tempEnergyMeter != totalEnergyMeter) {
totalEnergyMeter = tempEnergyMeter;
}
}
return totalEnergyMeter;
}
}