added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.tellstick-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-tellstick" description="Tellstick Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<feature>openhab-transport-serial</feature>
<feature dependency="true">openhab.tp-netty</feature>
<feature dependency="true">openhab.tp-jaxb</feature>
<bundle dependency="true">mvn:net.java.dev.jna/jna/4.5.2</bundle>
<bundle dependency="true">mvn:net.java.dev.jna/jna-platform/4.5.2</bundle>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.tellstick/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,38 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal;
import org.tellstick.device.TellstickException;
/**
* {@link TelldusBindingException} is used when there is exception communicating with Telldus Live.
* This exception extends the Telldus Core exception.
*
* @author Jarle Hjortland - Initial contribution
*/
public class TelldusBindingException extends TellstickException {
private static final long serialVersionUID = 30671795474333158L;
private String msg;
public TelldusBindingException(String message) {
super(null, 0);
this.msg = message;
}
@Override
public String getMessage() {
return msg;
}
}

View File

@@ -0,0 +1,109 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal;
import static org.openhab.core.library.unit.MetricPrefix.*;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.measure.Unit;
import javax.measure.quantity.Angle;
import javax.measure.quantity.Dimensionless;
import javax.measure.quantity.ElectricCurrent;
import javax.measure.quantity.Illuminance;
import javax.measure.quantity.Length;
import javax.measure.quantity.Power;
import javax.measure.quantity.Pressure;
import javax.measure.quantity.Speed;
import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link TellstickBinding} class defines common constants, which are
* used across the whole binding.
*
* @author jarlebh - Initial contribution
*/
@NonNullByDefault
public class TellstickBindingConstants {
public static final String BINDING_ID = "tellstick";
public static final Unit<Dimensionless> HUMIDITY_UNIT = SmartHomeUnits.PERCENT;
public static final Unit<Temperature> TEMPERATURE_UNIT = SIUnits.CELSIUS;
public static final Unit<Pressure> PRESSURE_UNIT = HECTO(SIUnits.PASCAL);
public static final Unit<Speed> WIND_SPEED_UNIT_MS = SmartHomeUnits.METRE_PER_SECOND;
public static final Unit<Angle> WIND_DIRECTION_UNIT = SmartHomeUnits.DEGREE_ANGLE;
public static final Unit<Length> RAIN_UNIT = MILLI(SIUnits.METRE);
public static final Unit<Illuminance> LUX_UNIT = SmartHomeUnits.LUX;
public static final Unit<ElectricCurrent> ELECTRIC_UNIT = SmartHomeUnits.AMPERE;
public static final Unit<Power> POWER_UNIT = KILO(SmartHomeUnits.WATT);
public static final String CONFIGPATH_ID = "location";
public static final String DEVICE_ID = "deviceId";
public static final String DEVICE_PROTOCOL = "protocol";
public static final String DEVICE_MODEL = "model";
public static final String DEVICE_NAME = "name";
public static final String DEVICE_RESEND_COUNT = "repeat";
public static final String DEVICE_ISDIMMER = "dimmer";
public static final String BRIDGE_TELLDUS_CORE = "telldus-core";
public static final String BRIDGE_TELLDUS_LIVE = "telldus-live";
public static final String DEVICE_SENSOR = "sensor";
public static final String DEVICE_WINDSENSOR = "windsensor";
public static final String DEVICE_RAINSENSOR = "rainsensor";
public static final String DEVICE_POWERSENSOR = "powersensor";
public static final String DEVICE_DIMMER = "dimmer";
public static final String DEVICE_SWITCH = "switch";
// List of all Thing Type UIDs
public static final ThingTypeUID DIMMER_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_DIMMER);
public static final ThingTypeUID SWITCH_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_SWITCH);
public static final ThingTypeUID SENSOR_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_SENSOR);
public static final ThingTypeUID RAINSENSOR_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_RAINSENSOR);
public static final ThingTypeUID POWERSENSOR_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_POWERSENSOR);
public static final ThingTypeUID WINDSENSOR_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_WINDSENSOR);
public static final ThingTypeUID TELLDUSBRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID, BRIDGE_TELLDUS_CORE);
public static final ThingTypeUID TELLDUSCOREBRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID, BRIDGE_TELLDUS_CORE);
public static final ThingTypeUID TELLDUSLIVEBRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID, BRIDGE_TELLDUS_LIVE);
// List of all Channel ids
public static final String CHANNEL_DIMMER = "dimmer";
public static final String CHANNEL_STATE = "state";
public static final String CHANNEL_HUMIDITY = "humidity";
public static final String CHANNEL_TIMESTAMP = "timestamp";
public static final String CHANNEL_TEMPERATURE = "temperature";
public static final String CHANNEL_RAINTOTAL = "raintotal";
public static final String CHANNEL_RAINRATE = "rainrate";
public static final String CHANNEL_WINDAVERAGE = "windaverage";
public static final String CHANNEL_WINDDIRECTION = "winddirection";
public static final String CHANNEL_WINDGUST = "windgust";
public static final String CHANNEL_WATT = "watt";
public static final String CHANNEL_AMPERE = "ampere";
public static final String CHANNEL_LUX = "lux";
public static final Set<ThingTypeUID> SUPPORTED_BRIDGE_THING_TYPES_UIDS = Collections.unmodifiableSet(
Stream.of(TELLDUSCOREBRIDGE_THING_TYPE, TELLDUSLIVEBRIDGE_THING_TYPE).collect(Collectors.toSet()));
public static final Set<ThingTypeUID> SUPPORTED_DEVICE_THING_TYPES_UIDS = Collections
.unmodifiableSet(Stream.of(DIMMER_THING_TYPE, SWITCH_THING_TYPE, SENSOR_THING_TYPE, RAINSENSOR_THING_TYPE,
WINDSENSOR_THING_TYPE, POWERSENSOR_THING_TYPE).collect(Collectors.toSet()));
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.unmodifiableSet(Stream
.of(DIMMER_THING_TYPE, SWITCH_THING_TYPE, SENSOR_THING_TYPE, RAINSENSOR_THING_TYPE, WINDSENSOR_THING_TYPE,
POWERSENSOR_THING_TYPE, TELLDUSCOREBRIDGE_THING_TYPE, TELLDUSLIVEBRIDGE_THING_TYPE)
.collect(Collectors.toSet()));
}

View File

@@ -0,0 +1,78 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal;
import static org.openhab.binding.tellstick.internal.TellstickBindingConstants.*;
import java.util.Hashtable;
import org.openhab.binding.tellstick.internal.core.TelldusCoreBridgeHandler;
import org.openhab.binding.tellstick.internal.discovery.TellstickDiscoveryService;
import org.openhab.binding.tellstick.internal.handler.TelldusBridgeHandler;
import org.openhab.binding.tellstick.internal.handler.TelldusDevicesHandler;
import org.openhab.binding.tellstick.internal.live.TelldusLiveBridgeHandler;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link TellstickHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Jarle Hjortland - Initial contribution
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.tellstick")
public class TellstickHandlerFactory extends BaseThingHandlerFactory {
private final Logger logger = LoggerFactory.getLogger(TellstickHandlerFactory.class);
private TellstickDiscoveryService discoveryService = null;
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
private void registerDeviceDiscoveryService(TelldusBridgeHandler tellstickBridgeHandler) {
if (discoveryService == null) {
discoveryService = new TellstickDiscoveryService(tellstickBridgeHandler);
discoveryService.activate();
bundleContext.registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable<>());
} else {
discoveryService.addBridgeHandler(tellstickBridgeHandler);
}
}
@Override
protected ThingHandler createHandler(Thing thing) {
if (thing.getThingTypeUID().equals(TELLDUSCOREBRIDGE_THING_TYPE)) {
TelldusCoreBridgeHandler handler = new TelldusCoreBridgeHandler((Bridge) thing);
registerDeviceDiscoveryService(handler);
return handler;
} else if (thing.getThingTypeUID().equals(TELLDUSLIVEBRIDGE_THING_TYPE)) {
TelldusLiveBridgeHandler handler = new TelldusLiveBridgeHandler((Bridge) thing);
registerDeviceDiscoveryService(handler);
return handler;
} else if (supportsThingType(thing.getThingTypeUID())) {
return new TelldusDevicesHandler(thing);
} else {
logger.debug("ThingHandler not found for {}", thing.getThingTypeUID());
return null;
}
}
}

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal;
/**
* Runtime exception in tellstick binding.
*
* @author Jarle Hjortland - Initial contribution
*/
public class TellstickRuntimeException extends RuntimeException {
private static final long serialVersionUID = -1644730263645760297L;
public TellstickRuntimeException(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.conf;
/**
* Configuration class for {@link TellstickBridge} bridge used to connect to the
* Tellus Live service.
*
* @author Jarle Hjortland - Initial contribution
*/
public class TelldusLiveConfiguration {
public String publicKey;
public String privateKey;
public String token;
public String tokenSecret;
public long refreshInterval;
}

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.conf;
/**
* Configuration class for {@link TellstickBridge} bridge used to connect to the
* Telldus Core service on the local machine.
*
* @author Jarle Hjortland - Initial contribution
*/
public class TellstickBridgeConfiguration {
public int resendInterval;
public String libraryPath;
}

View File

@@ -0,0 +1,280 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.core;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;
import org.openhab.binding.tellstick.internal.conf.TellstickBridgeConfiguration;
import org.openhab.binding.tellstick.internal.handler.DeviceStatusListener;
import org.openhab.binding.tellstick.internal.handler.TelldusBridgeHandler;
import org.openhab.binding.tellstick.internal.handler.TelldusDeviceController;
import org.openhab.binding.tellstick.internal.handler.TelldusDevicesHandler;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tellstick.JNA;
import org.tellstick.device.SupportedMethodsException;
import org.tellstick.device.TellstickDevice;
import org.tellstick.device.TellstickDeviceEvent;
import org.tellstick.device.TellstickEventHandler;
import org.tellstick.device.TellstickSensor;
import org.tellstick.device.TellstickSensorEvent;
import org.tellstick.device.iface.Device;
import org.tellstick.device.iface.DeviceChangeListener;
import org.tellstick.device.iface.SensorListener;
import org.tellstick.enums.ChangeType;
import org.tellstick.enums.DataType;
/**
* {@link TelldusCoreBridgeHandler} is the handler for Telldus Core (Duo and Basic) and connects it
* to the framework. All {@link TelldusDevicesHandler}s use the
* {@link TelldusCoreDeviceController} to execute the actual commands.
*
* @author Jarle Hjortland - Initial contribution
*/
public class TelldusCoreBridgeHandler extends BaseBridgeHandler
implements DeviceChangeListener, SensorListener, TelldusBridgeHandler {
public TelldusCoreBridgeHandler(Bridge br) {
super(br);
}
private Logger logger = LoggerFactory.getLogger(TelldusCoreBridgeHandler.class);
private TelldusDeviceController deviceController = null;
private List<TellstickDevice> deviceList = new Vector<>();
private List<TellstickSensor> sensorList = new Vector<>();
private TellstickEventHandler eventHandler;
private static boolean initialized = false;
private List<DeviceStatusListener> deviceStatusListeners = new CopyOnWriteArrayList<>();
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
logger.debug("Refresh command received.");
rescanTelldusDevices();
} else {
logger.warn("No bridge commands defined.");
}
}
@Override
public void dispose() {
logger.debug("Telldus Core Handler disposed.");
if (deviceController != null) {
deviceController.dispose();
deviceController = null;
}
if (eventHandler != null) {
eventHandler.remove();
eventHandler = null;
}
clearDeviceList();
initialized = false;
JNA.CLibrary.INSTANCE.tdClose();
super.dispose();
}
private String init(String libraryPath) {
if (!initialized) {
if (libraryPath != null) {
logger.info("Loading {} from {}", JNA.nativeLibrary, libraryPath);
System.setProperty("jna.library.path", libraryPath);
} else {
logger.info("Loading {} from system default paths", JNA.nativeLibrary);
}
TellstickDevice.setSupportedMethods(JNA.CLibrary.TELLSTICK_BELL | JNA.CLibrary.TELLSTICK_TURNOFF
| JNA.CLibrary.TELLSTICK_TURNON | JNA.CLibrary.TELLSTICK_DIM);
JNA.CLibrary.INSTANCE.tdInit();
initialized = true;
}
return libraryPath;
}
@Override
public void initialize() {
logger.debug("Initializing Tellstick bridge handler.");
TellstickBridgeConfiguration configuration = getConfigAs(TellstickBridgeConfiguration.class);
init(configuration.libraryPath);
scheduler.submit(() -> {
rescanTelldusDevices();
setupListeners();
setupDeviceController(configuration);
updateStatus(ThingStatus.ONLINE);
});
updateStatus(ThingStatus.UNKNOWN);
}
private void setupDeviceController(TellstickBridgeConfiguration configuration) {
deviceController = new TelldusCoreDeviceController(configuration.resendInterval);
eventHandler.addListener((TelldusCoreDeviceController) deviceController);
}
@Override
public void rescanTelldusDevices() {
try {
deviceList = Collections.synchronizedList(TellstickDevice.getDevices());
for (TellstickDevice device : deviceList) {
for (DeviceStatusListener listener : deviceStatusListeners) {
listener.onDeviceAdded(getThing(), device);
}
for (DeviceStatusListener listener : deviceStatusListeners) {
listener.onDeviceStateChanged(getThing(), device,
new TellstickDeviceEvent(device, null, null, null, System.currentTimeMillis()));
}
}
sensorList = Collections.synchronizedList(TellstickSensor.getAllSensors());
for (TellstickSensor sensor : sensorList) {
for (DeviceStatusListener listener : deviceStatusListeners) {
listener.onDeviceAdded(getThing(), sensor);
}
for (DeviceStatusListener listener : deviceStatusListeners) {
for (DataType type : sensor.getData().keySet()) {
listener.onDeviceStateChanged(getThing(), sensor,
new TellstickSensorEvent(sensor.getId(), sensor.getData(type), type,
sensor.getProtocol(), sensor.getModel(), System.currentTimeMillis()));
}
}
}
} catch (SupportedMethodsException e) {
logger.error("Failed to get devices ", e);
}
}
private synchronized void setupListeners() {
eventHandler = new TellstickEventHandler(deviceList);
eventHandler.addListener(this);
}
public void onConnectionLost() {
logger.debug("Bridge connection lost. Updating thing status to OFFLINE.");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
}
public void onConnection() {
logger.debug("Bridge connected. Updating thing status to ONLINE.");
updateStatus(ThingStatus.ONLINE);
}
@Override
public boolean registerDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
if (deviceStatusListener == null) {
throw new IllegalArgumentException("It's not allowed to pass a null deviceStatusListener.");
}
return deviceStatusListeners.add(deviceStatusListener);
}
@Override
public boolean unregisterDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
return deviceStatusListeners.remove(deviceStatusListener);
}
public void clearDeviceList() {
deviceList.clear();
sensorList.clear();
}
private Device getDevice(String id, List<TellstickDevice> devices) {
for (Device device : devices) {
if (device.getId() == Integer.valueOf(id)) {
return device;
}
}
return null;
}
@Override
public Device getDevice(String serialNumber) {
return getDevice(serialNumber, deviceList);
}
@Override
public void onRequest(TellstickSensorEvent newEvent) {
String uuid = TellstickSensor.createUUId(newEvent.getSensorId(), newEvent.getModel(), newEvent.getProtocol());
Device device = getSensor(uuid);
logger.debug("Sensor Event for {} event {}", device, newEvent);
if (device == null) {
TellstickSensor sensor = new TellstickSensor(newEvent.getSensorId(), newEvent.getProtocol(),
newEvent.getModel());
sensor.setData(newEvent.getDataType(), newEvent.getData());
sensorList.add(sensor);
for (DeviceStatusListener listener : deviceStatusListeners) {
listener.onDeviceAdded(getThing(), sensor);
}
} else {
TellstickSensor useSensor = (TellstickSensor) device;
String currentValue = useSensor.getData(newEvent.getDataType());
Calendar compdate = Calendar.getInstance();
compdate.add(Calendar.MINUTE, -1);
logger.debug("Update curr {} new {}", currentValue, newEvent.getData());
if (currentValue == null || !currentValue.equals(newEvent.getData())
|| useSensor.getTimeStamp().before(compdate.getTime())) {
// Changed or more than 1 minute since update
useSensor.setData(newEvent.getDataType(), newEvent.getData());
useSensor.setTimeStamp(new Date(newEvent.getTimestamp()));
for (DeviceStatusListener listener : deviceStatusListeners) {
listener.onDeviceStateChanged(getThing(), useSensor, newEvent);
}
} else {
logger.trace("Ignored update {}", newEvent);
}
}
}
@Override
public void onRequest(TellstickDeviceEvent newEvent) {
if (newEvent.getChangeType() == ChangeType.ADDED) {
for (DeviceStatusListener listener : deviceStatusListeners) {
listener.onDeviceAdded(getThing(), newEvent.getDevice());
}
} else if (newEvent.getChangeType() == ChangeType.REMOVED) {
for (DeviceStatusListener listener : deviceStatusListeners) {
listener.onDeviceRemoved(getThing(), newEvent.getDevice());
}
} else {
for (DeviceStatusListener listener : deviceStatusListeners) {
listener.onDeviceStateChanged(getThing(), newEvent.getDevice(), newEvent);
}
}
}
@Override
public Device getSensor(String deviceUUId) {
for (Device device : sensorList) {
if (device.getUUId().equals(deviceUUId)) {
return device;
}
}
return null;
}
@Override
public TelldusDeviceController getController() {
return this.deviceController;
}
}

View File

@@ -0,0 +1,328 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.core;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.SortedMap;
import java.util.TreeMap;
import org.openhab.binding.tellstick.internal.TelldusBindingException;
import org.openhab.binding.tellstick.internal.handler.TelldusDeviceController;
import org.openhab.core.library.types.IncreaseDecreaseType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tellstick.JNA;
import org.tellstick.device.TellstickDevice;
import org.tellstick.device.TellstickDeviceEvent;
import org.tellstick.device.TellstickException;
import org.tellstick.device.TellstickSensorEvent;
import org.tellstick.device.iface.Device;
import org.tellstick.device.iface.DeviceChangeListener;
import org.tellstick.device.iface.DimmableDevice;
import org.tellstick.device.iface.SensorListener;
import org.tellstick.device.iface.SwitchableDevice;
/**
* Device controller for telldus core (Basic and Duo).
* This communicates with the telldus DLL using the javatellstick
* library.
*
* @author Jarle Hjortland, Elias Gabrielsson - Initial contribution
*/
public class TelldusCoreDeviceController implements DeviceChangeListener, SensorListener, TelldusDeviceController {
private final Logger logger = LoggerFactory.getLogger(TelldusCoreDeviceController.class);
private long lastSend = 0;
long resendInterval = 100;
public static final long DEFAULT_INTERVAL_BETWEEN_SEND = 250;
private TelldusCoreWorker telldusCoreWorker;
private Thread workerThread;
private SortedMap<Device, TelldusCoreSendEvent> messageQue;
public TelldusCoreDeviceController(long resendInterval) {
this.resendInterval = resendInterval;
messageQue = Collections.synchronizedSortedMap(new TreeMap<>());
telldusCoreWorker = new TelldusCoreWorker(messageQue);
workerThread = new Thread(telldusCoreWorker);
}
@Override
public void dispose() {
workerThread.interrupt();
}
@Override
public void handleSendEvent(Device device, int resendCount, boolean isDimmer, Command command)
throws TellstickException {
if (!workerThread.isAlive()) {
workerThread.start();
}
Long eventTime = System.currentTimeMillis();
synchronized (messageQue) {
messageQue.put(device, new TelldusCoreSendEvent(device, resendCount, isDimmer, command, eventTime));
messageQue.notify();
}
}
@Override
public State calcState(Device dev) {
TellstickDevice device = (TellstickDevice) dev;
State st = null;
switch (device.getStatus()) {
case JNA.CLibrary.TELLSTICK_TURNON:
st = OnOffType.ON;
break;
case JNA.CLibrary.TELLSTICK_TURNOFF:
st = OnOffType.OFF;
break;
case JNA.CLibrary.TELLSTICK_DIM:
BigDecimal dimValue = new BigDecimal(device.getData());
if (dimValue.intValue() == 0) {
st = OnOffType.OFF;
} else if (dimValue.intValue() >= 255) {
st = OnOffType.ON;
} else {
st = OnOffType.ON;
}
break;
default:
logger.warn("Could not handle {} for {}", device.getStatus(), device);
}
return st;
}
@Override
public BigDecimal calcDimValue(Device device) {
BigDecimal dimValue = new BigDecimal(0);
switch (((TellstickDevice) device).getStatus()) {
case JNA.CLibrary.TELLSTICK_TURNON:
dimValue = new BigDecimal(100);
break;
case JNA.CLibrary.TELLSTICK_TURNOFF:
break;
case JNA.CLibrary.TELLSTICK_DIM:
dimValue = new BigDecimal(((TellstickDevice) device).getData());
dimValue = dimValue.multiply(new BigDecimal(100));
dimValue = dimValue.divide(new BigDecimal(255), 0, BigDecimal.ROUND_HALF_UP);
break;
default:
logger.warn("Could not handle {} for {}", ((TellstickDevice) device).getStatus(), device);
}
return dimValue;
}
public long getLastSend() {
return lastSend;
}
public void setLastSend(long currentTimeMillis) {
lastSend = currentTimeMillis;
}
@Override
public void onRequest(TellstickSensorEvent newDevices) {
setLastSend(newDevices.getTimestamp());
}
@Override
public void onRequest(TellstickDeviceEvent newDevices) {
setLastSend(newDevices.getTimestamp());
}
private void sendEvent(Device device, int resendCount, boolean isdimmer, Command command)
throws TellstickException {
for (int i = 0; i < resendCount; i++) {
checkLastAndWait(resendInterval);
logger.debug("Send {} to {} times={}", command, device, i);
if (device instanceof DimmableDevice) {
if (command == OnOffType.ON) {
turnOn(device);
} else if (command == OnOffType.OFF) {
turnOff(device);
} else if (command instanceof PercentType) {
dim(device, (PercentType) command);
} else if (command instanceof IncreaseDecreaseType) {
increaseDecrease(device, ((IncreaseDecreaseType) command));
}
} else if (device instanceof SwitchableDevice) {
if (command == OnOffType.ON) {
if (isdimmer) {
logger.debug("Turn off first in case it is allready on");
turnOff(device);
checkLastAndWait(resendInterval);
}
turnOn(device);
} else if (command == OnOffType.OFF) {
turnOff(device);
}
} else {
logger.warn("Cannot send to {}", device);
}
}
}
private void increaseDecrease(Device dev, IncreaseDecreaseType increaseDecreaseType) throws TellstickException {
String strValue = ((TellstickDevice) dev).getData();
double value = 0;
if (strValue != null) {
value = Double.valueOf(strValue);
}
int percent = (int) Math.round((value / 255) * 100);
if (IncreaseDecreaseType.INCREASE == increaseDecreaseType) {
percent = Math.min(percent + 10, 100);
} else if (IncreaseDecreaseType.DECREASE == increaseDecreaseType) {
percent = Math.max(percent - 10, 0);
}
dim(dev, new PercentType(percent));
}
private void dim(Device dev, PercentType command) throws TellstickException {
double value = command.doubleValue();
// 0 means OFF and 100 means ON
if (value == 0 && dev instanceof SwitchableDevice) {
((SwitchableDevice) dev).off();
} else if (value == 100 && dev instanceof SwitchableDevice) {
((SwitchableDevice) dev).on();
} else if (dev instanceof DimmableDevice) {
long tdVal = Math.round((value / 100) * 255);
((DimmableDevice) dev).dim((int) tdVal);
} else {
throw new TelldusBindingException("Cannot send DIM to " + dev);
}
}
private void turnOff(Device dev) throws TellstickException {
if (dev instanceof SwitchableDevice) {
((SwitchableDevice) dev).off();
} else {
throw new TelldusBindingException("Cannot send OFF to " + dev);
}
}
private void turnOn(Device dev) throws TellstickException {
if (dev instanceof SwitchableDevice) {
((SwitchableDevice) dev).on();
} else {
throw new TelldusBindingException("Cannot send ON to " + dev);
}
}
private void checkLastAndWait(long resendInterval) {
while ((System.currentTimeMillis() - lastSend) < resendInterval) {
logger.debug("Wait for {} millisec", resendInterval);
try {
Thread.sleep(resendInterval);
} catch (InterruptedException e) {
logger.error("Failed to sleep", e);
}
}
lastSend = System.currentTimeMillis();
}
/**
* This class is a worker which execute the commands sent to the TelldusCoreDeviceController.
* This enables separation between Telldus Core and openHAB for preventing latency on the bus.
* The Tellstick have an send pace of 4 Hz which is far slower then the bus itself.
*
* @author Elias Gabrielsson
*
*/
private class TelldusCoreWorker implements Runnable {
private SortedMap<Device, TelldusCoreSendEvent> messageQue;
public TelldusCoreWorker(SortedMap<Device, TelldusCoreSendEvent> messageQue) {
this.messageQue = messageQue;
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
TelldusCoreSendEvent sendEvent;
// Get event to send
synchronized (messageQue) {
while (messageQue.isEmpty()) {
messageQue.wait();
}
sendEvent = messageQue.remove(messageQue.firstKey());
}
// Send event
try {
sendEvent(sendEvent.getDevice(), sendEvent.getResendCount(), sendEvent.getDimmer(),
sendEvent.getCommand());
} catch (TellstickException e) {
logger.error("Failed to send msg:{} to {}", sendEvent.getCommand(), sendEvent.getDevice(), e);
}
} catch (InterruptedException ie) {
break; // Terminate
}
}
}
}
/**
* This is a wrapper class to enable queuing of send events between the controller and the working thread.
*
* @author Elias Gabrielsson
*
*/
private class TelldusCoreSendEvent implements Comparable<TelldusCoreSendEvent> {
private Device device;
private int resendCount;
private boolean isDimmer;
private Command command;
private Long eventTime;
public TelldusCoreSendEvent(Device device, int resendCount, boolean isDimmer, Command command, Long eventTime) {
this.device = device;
this.resendCount = resendCount;
this.isDimmer = isDimmer;
this.command = command;
this.eventTime = eventTime;
}
public Device getDevice() {
return device;
}
public int getResendCount() {
return resendCount;
}
public boolean getDimmer() {
return isDimmer;
}
public Command getCommand() {
return command;
}
public Long getEventTime() {
return eventTime;
}
@Override
public int compareTo(TelldusCoreSendEvent o) {
return eventTime.compareTo(o.getEventTime());
}
}
}

View File

@@ -0,0 +1,106 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.discovery;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.openhab.binding.tellstick.internal.TellstickBindingConstants;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tellstick.device.TellstickController;
/**
* The {@link TellstickBridgeDiscovery} is responsible for discovering new Telldus gateway devices on the network
*
* @author Jarle Hjortland - Initial contribution
*
*/
@Component(service = DiscoveryService.class, immediate = true, configurationPid = "discovery.tellstick")
public class TellstickBridgeDiscovery extends AbstractDiscoveryService {
private final Logger logger = LoggerFactory.getLogger(TellstickBridgeDiscovery.class);
static boolean discoveryRunning = false;
static boolean initilized = false;
public TellstickBridgeDiscovery() {
super(TellstickBindingConstants.SUPPORTED_BRIDGE_THING_TYPES_UIDS, 15);
}
@Override
public Set<ThingTypeUID> getSupportedThingTypes() {
return TellstickBindingConstants.SUPPORTED_BRIDGE_THING_TYPES_UIDS;
}
@Override
public void startScan() {
discoverController();
}
@Override
protected void startBackgroundDiscovery() {
discoverController();
}
@Override
public boolean isBackgroundDiscoveryEnabled() {
return true;
}
private synchronized void discoverController() {
if (!discoveryRunning) {
discoveryRunning = true;
listBridge();
}
}
private void listBridge() {
try {
List<TellstickController> cntrls = TellstickController.getControllers();
for (TellstickController contrl : cntrls) {
discoveryResultSubmission(contrl);
}
} catch (UnsatisfiedLinkError e) {
logger.error(
"Could not load telldus core, please make sure Telldus is installed and correct 32/64 bit java.",
e);
} catch (NoClassDefFoundError e) {
logger.error(
"Could not load telldus core, please make sure Telldus is installed and correct 32/64 bit java.",
e);
} finally {
// Close the port!
discoveryRunning = false;
}
}
private void discoveryResultSubmission(TellstickController controller) {
if (controller != null && controller.isOnline()) {
logger.trace("Adding new Telldus Controller {}", controller);
Map<String, Object> properties = new HashMap<>(2);
ThingUID uid = new ThingUID(TellstickBindingConstants.TELLDUSCOREBRIDGE_THING_TYPE,
Integer.toString(controller.getId()));
thingDiscovered(DiscoveryResultBuilder.create(uid).withProperties(properties)
.withLabel(controller.getType().name() + ": " + controller.getName()).build());
}
}
}

View File

@@ -0,0 +1,186 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.discovery;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import org.openhab.binding.tellstick.internal.TellstickBindingConstants;
import org.openhab.binding.tellstick.internal.handler.DeviceStatusListener;
import org.openhab.binding.tellstick.internal.handler.TelldusBridgeHandler;
import org.openhab.binding.tellstick.internal.live.xml.LiveDataType;
import org.openhab.binding.tellstick.internal.live.xml.TellstickNetDevice;
import org.openhab.binding.tellstick.internal.live.xml.TellstickNetSensor;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tellstick.JNA;
import org.tellstick.device.TellstickSensor;
import org.tellstick.device.iface.Device;
import org.tellstick.device.iface.DimmableDevice;
import org.tellstick.device.iface.SwitchableDevice;
import org.tellstick.device.iface.TellstickEvent;
import org.tellstick.enums.DataType;
/**
* The {@link TellstickDiscoveryService} class is used to discover Tellstick
* devices that are connected to the Lan gateway.
*
* @author Jarle Hjortland - Initial contribution
*/
public class TellstickDiscoveryService extends AbstractDiscoveryService implements DeviceStatusListener {
private static final long DEFAULT_TTL = 60 * 60; // 1 Hour
public TellstickDiscoveryService(int timeout) throws IllegalArgumentException {
super(timeout);
}
private final Logger logger = LoggerFactory.getLogger(TellstickDiscoveryService.class);
private List<TelldusBridgeHandler> telldusBridgeHandlers = new Vector<>();
public TellstickDiscoveryService(TelldusBridgeHandler telldusBridgeHandler) {
super(TellstickBindingConstants.SUPPORTED_DEVICE_THING_TYPES_UIDS, 10, true);
this.telldusBridgeHandlers.add(telldusBridgeHandler);
}
public void activate() {
for (TelldusBridgeHandler telldusBridgeHandler : telldusBridgeHandlers) {
telldusBridgeHandler.registerDeviceStatusListener(this);
}
}
@Override
public void deactivate() {
for (TelldusBridgeHandler telldusBridgeHandler : telldusBridgeHandlers) {
telldusBridgeHandler.unregisterDeviceStatusListener(this);
}
}
@Override
public Set<ThingTypeUID> getSupportedThingTypes() {
return TellstickBindingConstants.SUPPORTED_DEVICE_THING_TYPES_UIDS;
}
@Override
public void onDeviceAdded(Bridge bridge, Device device) {
logger.debug("Adding new TellstickDevice! '{}' with id '{}' and type '{}' to smarthome inbox", device,
device.getId(), device.getDeviceType());
ThingUID thingUID = getThingUID(bridge, device);
logger.debug("Detected thingUID: {}", thingUID);
if (thingUID != null) {
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withTTL(DEFAULT_TTL)
.withProperty(TellstickBindingConstants.DEVICE_ID, device.getUUId())
.withProperty(TellstickBindingConstants.DEVICE_NAME, device.getName()).withBridge(bridge.getUID())
.withLabel(device.getDeviceType() + ": " + device.getName()).build();
thingDiscovered(discoveryResult);
} else {
logger.warn("Discovered Tellstick! device is unsupported: type '{}' with id '{}'", device.getDeviceType(),
device.getId());
}
}
@Override
protected void startScan() {
for (TelldusBridgeHandler telldusBridgeHandler : telldusBridgeHandlers) {
telldusBridgeHandler.rescanTelldusDevices();
}
}
@Override
public void onDeviceStateChanged(Bridge bridge, Device device, TellstickEvent event) {
// this can be ignored here
}
@Override
public void onDeviceRemoved(Bridge bridge, Device device) {
ThingUID thingUID = getThingUID(bridge, device);
if (thingUID != null) {
thingRemoved(thingUID);
} else {
logger.warn("Removed Tellstick! device is unsupported: type '{}' with id '{}'", device.getDeviceType(),
device.getId());
}
}
private ThingUID getThingUID(Bridge bridge, Device device) {
ThingUID thingUID = null;
switch (device.getDeviceType()) {
case SENSOR:
ThingTypeUID sensorThingId = findSensorType(device);
thingUID = new ThingUID(sensorThingId, bridge.getUID(), device.getUUId());
break;
case DEVICE:
if (device instanceof DimmableDevice) {
thingUID = new ThingUID(TellstickBindingConstants.DIMMER_THING_TYPE, bridge.getUID(),
device.getUUId());
} else if (device instanceof SwitchableDevice) {
thingUID = new ThingUID(TellstickBindingConstants.SWITCH_THING_TYPE, bridge.getUID(),
device.getUUId());
} else if (device instanceof TellstickNetDevice) {
if ((((TellstickNetDevice) device).getMethods() & JNA.CLibrary.TELLSTICK_DIM) > 0) {
thingUID = new ThingUID(TellstickBindingConstants.DIMMER_THING_TYPE, bridge.getUID(),
device.getUUId());
} else {
thingUID = new ThingUID(TellstickBindingConstants.SWITCH_THING_TYPE, bridge.getUID(),
device.getUUId());
}
}
break;
default:
break;
}
return thingUID;
}
private ThingTypeUID findSensorType(Device device) {
logger.debug("Device: {}", device);
ThingTypeUID sensorThingId;
if (device instanceof TellstickSensor) {
TellstickSensor sensor = (TellstickSensor) device;
logger.debug("Sensor: {}", device);
if (sensor.getData(DataType.WINDAVERAGE) != null || sensor.getData(DataType.WINDGUST) != null
|| sensor.getData(DataType.WINDDIRECTION) != null) {
sensorThingId = TellstickBindingConstants.WINDSENSOR_THING_TYPE;
} else if (sensor.getData(DataType.RAINTOTAL) != null || sensor.getData(DataType.RAINRATE) != null) {
sensorThingId = TellstickBindingConstants.RAINSENSOR_THING_TYPE;
} else {
sensorThingId = TellstickBindingConstants.SENSOR_THING_TYPE;
}
} else {
TellstickNetSensor sensor = (TellstickNetSensor) device;
if (sensor.isSensorOfType(LiveDataType.WINDAVERAGE) || sensor.isSensorOfType(LiveDataType.WINDDIRECTION)
|| sensor.isSensorOfType(LiveDataType.WINDGUST)) {
sensorThingId = TellstickBindingConstants.WINDSENSOR_THING_TYPE;
} else if (sensor.isSensorOfType(LiveDataType.RAINRATE) || sensor.isSensorOfType(LiveDataType.RAINTOTAL)) {
sensorThingId = TellstickBindingConstants.RAINSENSOR_THING_TYPE;
} else if (sensor.isSensorOfType(LiveDataType.WATT)) {
sensorThingId = TellstickBindingConstants.POWERSENSOR_THING_TYPE;
} else {
sensorThingId = TellstickBindingConstants.SENSOR_THING_TYPE;
}
}
return sensorThingId;
}
public void addBridgeHandler(TelldusBridgeHandler tellstickBridgeHandler) {
telldusBridgeHandlers.add(tellstickBridgeHandler);
tellstickBridgeHandler.registerDeviceStatusListener(this);
}
}

View File

@@ -0,0 +1,57 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.handler;
import org.openhab.core.thing.Bridge;
import org.tellstick.device.iface.Device;
import org.tellstick.device.iface.TellstickEvent;
/**
* The {@link DeviceStatusListener} is notified when a device status has changed
* or a device has been removed or added.
*
* @author Jarle Hjortland - Initial contribution
*/
public interface DeviceStatusListener {
/**
* This method is called whenever the state of the given device has changed.
* The new state can be obtained by {@link FullLight#getState()}.
*
* @param bridge
* The Tellstick bridge the changed device is connected to.
* @param device
* The device which received the state update.
*/
public void onDeviceStateChanged(Bridge bridge, Device device, TellstickEvent deviceEvent);
/**
* This method us called whenever a device is removed.
*
* @param bridge
* The Tellstick bridge the removed device was connected to.
* @param device
* The device which is removed.
*/
public void onDeviceRemoved(Bridge bridge, Device device);
/**
* This method us called whenever a device is added.
*
* @param bridge
* The Tellstick bridge the added device was connected to.
* @param device
* The device which is added.
*/
public void onDeviceAdded(Bridge bridge, Device device);
}

View File

@@ -0,0 +1,79 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.handler;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.types.Command;
import org.tellstick.device.iface.Device;
/**
* Interface for the telldus bridge modules
*
* @author Jarle Hjortland - Initial contribution
*/
public interface TelldusBridgeHandler {
/**
* TelldusDeviceController
* Add a status listener.
*
* @param deviceStatusListener
* @return
*/
boolean registerDeviceStatusListener(DeviceStatusListener deviceStatusListener);
/**
* Remove a status listener.
*
* @param deviceStatusListener
* @return
*/
boolean unregisterDeviceStatusListener(DeviceStatusListener deviceStatusListener);
/**
* Get a device from the bridgehandler.
*
* @param serialNumber
* @return
*/
Device getDevice(String serialNumber);
/**
* Get a sensor from the bridgehandler.
*
* @param serialNumber
* @return
*/
Device getSensor(String deviceUUId);
/**
* Tell the bridge to rescan for new devices.
*
*/
void rescanTelldusDevices();
/**
* Get the controller to communicate with devices.
*
* @return
*/
TelldusDeviceController getController();
/**
* Send a command to the controller.
*
* @param channelUID
* @param command
*/
void handleCommand(ChannelUID channelUID, Command command);
}

View File

@@ -0,0 +1,62 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.handler;
import java.math.BigDecimal;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.tellstick.device.TellstickException;
import org.tellstick.device.iface.Device;
/**
* Interface for telldus controllers. This is used to send and get status of devices from the controller.
*
* @author Jarle Hjortland - Initial contribution
*/
public interface TelldusDeviceController {
/**
* Send an event to the controller.
*
* @param device
* @param resendCount
* @param isdimmer
* @param command
* @throws TellstickException
*/
void handleSendEvent(Device device, int resendCount, boolean isdimmer, Command command) throws TellstickException;
/**
* Get the state of the given device.
*
* @param dev
* @return
*/
State calcState(Device dev);
/**
* Get the current dim state for a device.
*
* @param device
* @return
*/
BigDecimal calcDimValue(Device device);
/**
*
* Clean up the device controller before shutdown.
*
*/
void dispose();
}

View File

@@ -0,0 +1,377 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.handler;
import static org.openhab.binding.tellstick.internal.TellstickBindingConstants.*;
import java.math.BigDecimal;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Calendar;
import org.openhab.binding.tellstick.internal.TellstickBindingConstants;
import org.openhab.binding.tellstick.internal.live.xml.DataTypeValue;
import org.openhab.binding.tellstick.internal.live.xml.TellstickNetSensor;
import org.openhab.binding.tellstick.internal.live.xml.TellstickNetSensorEvent;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tellstick.device.TellstickDeviceEvent;
import org.tellstick.device.TellstickException;
import org.tellstick.device.TellstickSensor;
import org.tellstick.device.TellstickSensorEvent;
import org.tellstick.device.iface.Device;
import org.tellstick.device.iface.DimmableDevice;
import org.tellstick.device.iface.TellstickEvent;
import org.tellstick.enums.DataType;
import org.tellstick.enums.DeviceType;
/**
* Handler for telldus and tellstick devices. This sends the commands to the correct bridge.
*
* @author Jarle Hjortland - Initial contribution
*/
public class TelldusDevicesHandler extends BaseThingHandler implements DeviceStatusListener {
private Logger logger = LoggerFactory.getLogger(TelldusDevicesHandler.class);
private String deviceId;
private Boolean isDimmer = Boolean.FALSE;
private int resend = 1;
private TelldusBridgeHandler bridgeHandler = null;
private final ChannelUID stateChannel;
private final ChannelUID dimChannel;
private final ChannelUID humidityChannel;
private final ChannelUID tempChannel;
private final ChannelUID raintTotChannel;
private final ChannelUID rainRateChannel;
private final ChannelUID windAverageChannel;
private final ChannelUID windDirectionChannel;
private final ChannelUID windGuestChannel;
private final ChannelUID wattChannel;
private final ChannelUID ampereChannel;
private final ChannelUID luxChannel;
private final ChannelUID timestampChannel;
public TelldusDevicesHandler(Thing thing) {
super(thing);
stateChannel = new ChannelUID(getThing().getUID(), CHANNEL_STATE);
dimChannel = new ChannelUID(getThing().getUID(), CHANNEL_DIMMER);
humidityChannel = new ChannelUID(getThing().getUID(), CHANNEL_HUMIDITY);
tempChannel = new ChannelUID(getThing().getUID(), CHANNEL_TEMPERATURE);
raintTotChannel = new ChannelUID(getThing().getUID(), CHANNEL_RAINTOTAL);
rainRateChannel = new ChannelUID(getThing().getUID(), CHANNEL_RAINRATE);
windAverageChannel = new ChannelUID(getThing().getUID(), CHANNEL_WINDAVERAGE);
windDirectionChannel = new ChannelUID(getThing().getUID(), CHANNEL_WINDDIRECTION);
windGuestChannel = new ChannelUID(getThing().getUID(), CHANNEL_WINDGUST);
wattChannel = new ChannelUID(getThing().getUID(), CHANNEL_WATT);
ampereChannel = new ChannelUID(getThing().getUID(), CHANNEL_AMPERE);
timestampChannel = new ChannelUID(getThing().getUID(), CHANNEL_TIMESTAMP);
luxChannel = new ChannelUID(getThing().getUID(), CHANNEL_LUX);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
logger.debug("Handle event {} for {}", command, channelUID);
TelldusBridgeHandler bridgeHandler = getTellstickBridgeHandler();
if (bridgeHandler == null) {
logger.warn("Tellstick bridge handler not found. Cannot handle command without bridge.");
return;
}
Device dev = getDevice(bridgeHandler, deviceId);
if (dev == null) {
logger.warn("Device not found. Can't send command to device '{}'", deviceId);
return;
}
if (command instanceof RefreshType) {
getBridge().getHandler().handleCommand(channelUID, command);
refreshDevice(dev);
return;
}
if (channelUID.getId().equals(CHANNEL_DIMMER) || channelUID.getId().equals(CHANNEL_STATE)) {
try {
if (dev.getDeviceType() == DeviceType.DEVICE) {
getTellstickBridgeHandler().getController().handleSendEvent(dev, resend, isDimmer, command);
} else {
logger.warn("{} is not an updateable device. Read-only", dev);
}
} catch (TellstickException e) {
logger.debug("Failed to send command to tellstick", e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
} catch (Exception e) {
logger.error("Failed to send command to tellstick", e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
} else {
logger.warn("Setting of channel {} not possible. Read-only", channelUID);
}
}
private void refreshDevice(Device dev) {
if (deviceId != null && isSensor()) {
updateSensorStates(dev);
} else if (deviceId != null) {
updateDeviceState(dev);
}
}
@Override
public void initialize() {
Configuration config = getConfig();
logger.debug("Initialize TelldusDeviceHandler {}. class {}", config, config.getClass());
final Object configDeviceId = config.get(TellstickBindingConstants.DEVICE_ID);
if (configDeviceId != null) {
deviceId = configDeviceId.toString();
} else {
logger.debug("Initialized TellStick device missing serialNumber configuration... troubles ahead");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
}
final Boolean isADimmer = (Boolean) config.get(TellstickBindingConstants.DEVICE_ISDIMMER);
if (isADimmer != null) {
this.isDimmer = isADimmer;
}
final BigDecimal repeatCount = (BigDecimal) config.get(TellstickBindingConstants.DEVICE_RESEND_COUNT);
if (repeatCount != null) {
resend = repeatCount.intValue();
}
if (getBridge() != null) {
bridgeStatusChanged(getBridge().getStatusInfo());
}
}
@Override
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
logger.debug("device: {} bridgeStatusChanged: {}", deviceId, bridgeStatusInfo);
if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE) {
try {
TelldusBridgeHandler tellHandler = (TelldusBridgeHandler) getBridge().getHandler();
logger.debug("Init bridge for {}, bridge:{}", deviceId, tellHandler);
if (tellHandler != null) {
this.bridgeHandler = tellHandler;
this.bridgeHandler.registerDeviceStatusListener(this);
Configuration config = editConfiguration();
Device dev = getDevice(tellHandler, deviceId);
if (dev != null) {
if (dev.getName() != null) {
config.put(TellstickBindingConstants.DEVICE_NAME, dev.getName());
}
if (dev.getProtocol() != null) {
config.put(TellstickBindingConstants.DEVICE_PROTOCOL, dev.getProtocol());
}
if (dev.getModel() != null) {
config.put(TellstickBindingConstants.DEVICE_MODEL, dev.getModel());
}
updateConfiguration(config);
updateStatus(ThingStatus.ONLINE);
} else {
logger.warn(
"Could not find {}, please make sure it is defined and that telldus service is running",
deviceId);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
}
}
} catch (Exception e) {
logger.error("Failed to init bridge for {}", deviceId, e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR);
}
} else {
updateStatus(ThingStatus.OFFLINE, bridgeStatusInfo.getStatusDetail());
}
}
private Device getDevice(TelldusBridgeHandler tellHandler, String deviceId) {
Device dev = null;
if (deviceId != null) {
if (isSensor()) {
dev = tellHandler.getSensor(deviceId);
} else {
dev = tellHandler.getDevice(deviceId);
updateDeviceState(dev);
}
}
return dev;
}
private boolean isSensor() {
return (getThing().getThingTypeUID().equals(TellstickBindingConstants.SENSOR_THING_TYPE)
|| getThing().getThingTypeUID().equals(TellstickBindingConstants.RAINSENSOR_THING_TYPE)
|| getThing().getThingTypeUID().equals(TellstickBindingConstants.WINDSENSOR_THING_TYPE)
|| getThing().getThingTypeUID().equals(TellstickBindingConstants.POWERSENSOR_THING_TYPE));
}
private void updateSensorStates(Device dev) {
if (dev instanceof TellstickSensor) {
updateStatus(ThingStatus.ONLINE);
for (DataType type : ((TellstickSensor) dev).getData().keySet()) {
updateSensorDataState(type, ((TellstickSensor) dev).getData(type));
}
} else if (dev instanceof TellstickNetSensor) {
if (((TellstickNetSensor) dev).getOnline()) {
updateStatus(ThingStatus.ONLINE);
} else {
updateStatus(ThingStatus.OFFLINE);
}
for (DataTypeValue type : ((TellstickNetSensor) dev).getData()) {
updateSensorDataState(type);
}
}
}
private synchronized TelldusBridgeHandler getTellstickBridgeHandler() {
if (this.bridgeHandler == null) {
logger.debug("No available bridge handler found for {} bridge {} .", deviceId, getBridge());
}
return this.bridgeHandler;
}
@Override
public void onDeviceStateChanged(Bridge bridge, Device device, TellstickEvent event) {
logger.debug("Updating states of ({} {} ({}) id: {} or {}", device.getDeviceType(), device.getName(),
device.getUUId(), getThing().getUID(), deviceId);
if (device.getUUId().equals(deviceId)) {
if (event instanceof TellstickDeviceEvent) {
updateDeviceState(device);
} else if (event instanceof TellstickNetSensorEvent) {
TellstickNetSensorEvent sensorevent = (TellstickNetSensorEvent) event;
updateSensorDataState(sensorevent.getDataTypeValue());
} else if (event instanceof TellstickSensorEvent) {
TellstickSensorEvent sensorevent = (TellstickSensorEvent) event;
updateSensorDataState(sensorevent.getDataType(), sensorevent.getData());
} else {
logger.debug("Unhandled Device {}.", device.getDeviceType());
}
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(event.getTimestamp());
updateState(timestampChannel,
new DateTimeType(ZonedDateTime.ofInstant(cal.toInstant(), ZoneId.systemDefault())));
}
}
private void updateSensorDataState(DataType dataType, String data) {
switch (dataType) {
case HUMIDITY:
updateState(humidityChannel, new QuantityType<>(new BigDecimal(data), HUMIDITY_UNIT));
break;
case TEMPERATURE:
updateState(tempChannel, new QuantityType<>(new BigDecimal(data), SIUnits.CELSIUS));
break;
case RAINRATE:
updateState(rainRateChannel, new QuantityType<>(new BigDecimal(data), RAIN_UNIT));
break;
case RAINTOTAL:
updateState(raintTotChannel, new QuantityType<>(new BigDecimal(data), RAIN_UNIT));
break;
case WINDAVERAGE:
updateState(windAverageChannel, new QuantityType<>(new BigDecimal(data), WIND_SPEED_UNIT_MS));
break;
case WINDDIRECTION:
updateState(windDirectionChannel, new QuantityType<>(new BigDecimal(data), WIND_DIRECTION_UNIT));
break;
case WINDGUST:
updateState(windGuestChannel, new QuantityType<>(new BigDecimal(data), WIND_SPEED_UNIT_MS));
break;
default:
}
}
private void updateSensorDataState(DataTypeValue dataType) {
switch (dataType.getName()) {
case HUMIDITY:
updateState(humidityChannel, new QuantityType<>(new BigDecimal(dataType.getValue()), HUMIDITY_UNIT));
break;
case TEMPERATURE:
updateState(tempChannel, new QuantityType<>(new BigDecimal(dataType.getValue()), SIUnits.CELSIUS));
break;
case RAINRATE:
updateState(rainRateChannel, new QuantityType<>(new BigDecimal(dataType.getValue()), RAIN_UNIT));
break;
case RAINTOTAL:
updateState(raintTotChannel, new QuantityType<>(new BigDecimal(dataType.getValue()), RAIN_UNIT));
break;
case WINDAVERAGE:
updateState(windAverageChannel,
new QuantityType<>(new BigDecimal(dataType.getValue()), WIND_SPEED_UNIT_MS));
break;
case WINDDIRECTION:
updateState(windDirectionChannel,
new QuantityType<>(new BigDecimal(dataType.getValue()), WIND_DIRECTION_UNIT));
break;
case WINDGUST:
updateState(windGuestChannel,
new QuantityType<>(new BigDecimal(dataType.getValue()), WIND_SPEED_UNIT_MS));
break;
case WATT:
if (dataType.getUnit() != null && dataType.getUnit().equals("A")) {
updateState(ampereChannel, new QuantityType<>(new BigDecimal(dataType.getValue()), ELECTRIC_UNIT));
} else {
updateState(wattChannel, new QuantityType<>(new BigDecimal(dataType.getValue()), POWER_UNIT));
}
break;
case LUMINATION:
updateState(luxChannel, new QuantityType<>(new DecimalType(dataType.getValue()), LUX_UNIT));
break;
default:
}
}
private void updateDeviceState(Device device) {
if (device != null) {
logger.debug("Updating state of {} {} ({}) id: {}", device.getDeviceType(), device.getName(),
device.getUUId(), getThing().getUID());
TelldusBridgeHandler bridgeHandler = getTellstickBridgeHandler();
State st = null;
if (bridgeHandler != null && bridgeHandler.getController() != null) {
st = bridgeHandler.getController().calcState(device);
}
if (st != null && bridgeHandler != null) {
BigDecimal dimValue = bridgeHandler.getController().calcDimValue(device);
updateState(stateChannel, st);
if (device instanceof DimmableDevice) {
updateState(dimChannel, new PercentType(dimValue));
}
updateStatus(ThingStatus.ONLINE);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
}
} else {
updateStatus(ThingStatus.REMOVED);
}
}
@Override
public void onDeviceRemoved(Bridge bridge, Device device) {
if (device.getUUId().equals(deviceId)) {
updateStatus(ThingStatus.REMOVED);
}
}
@Override
public void onDeviceAdded(Bridge bridge, Device device) {
}
}

View File

@@ -0,0 +1,323 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.live;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.openhab.binding.tellstick.internal.conf.TelldusLiveConfiguration;
import org.openhab.binding.tellstick.internal.handler.DeviceStatusListener;
import org.openhab.binding.tellstick.internal.handler.TelldusBridgeHandler;
import org.openhab.binding.tellstick.internal.handler.TelldusDeviceController;
import org.openhab.binding.tellstick.internal.handler.TelldusDevicesHandler;
import org.openhab.binding.tellstick.internal.live.xml.DataTypeValue;
import org.openhab.binding.tellstick.internal.live.xml.TellstickNetDevice;
import org.openhab.binding.tellstick.internal.live.xml.TellstickNetDevices;
import org.openhab.binding.tellstick.internal.live.xml.TellstickNetSensor;
import org.openhab.binding.tellstick.internal.live.xml.TellstickNetSensorEvent;
import org.openhab.binding.tellstick.internal.live.xml.TellstickNetSensors;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tellstick.device.TellstickDeviceEvent;
import org.tellstick.device.TellstickException;
import org.tellstick.device.iface.Device;
/**
* {@link TelldusLiveBridgeHandler} is the handler for Telldus Live service (Tellstick.NET and ZNET) and connects it
* to the framework. All {@link TelldusDevicesHandler}s use the
* {@link TelldusLiveDeviceController} to execute the actual commands.
*
* @author Jarle Hjortland - Initial contribution
*/
public class TelldusLiveBridgeHandler extends BaseBridgeHandler implements TelldusBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(TelldusLiveBridgeHandler.class);
private TellstickNetDevices deviceList = null;
private TellstickNetSensors sensorList = null;
private TelldusLiveDeviceController controller = new TelldusLiveDeviceController();
private List<DeviceStatusListener> deviceStatusListeners = new Vector<>();
private static final int REFRESH_DELAY = 10;
public TelldusLiveBridgeHandler(Bridge bridge) {
super(bridge);
}
private ScheduledFuture<?> pollingJob;
private ScheduledFuture<?> immediateRefreshJob;
@Override
public void dispose() {
logger.debug("Live Handler disposed.");
if (pollingJob != null) {
pollingJob.cancel(true);
}
if (this.controller != null) {
this.controller.dispose();
}
deviceList = null;
sensorList = null;
super.dispose();
}
@Override
public void initialize() {
logger.debug("Initializing TelldusLive bridge handler.");
TelldusLiveConfiguration configuration = getConfigAs(TelldusLiveConfiguration.class);
this.controller = new TelldusLiveDeviceController();
this.controller.connectHttpClient(configuration.publicKey, configuration.privateKey, configuration.token,
configuration.tokenSecret);
startAutomaticRefresh(configuration.refreshInterval);
refreshDeviceList();
updateStatus(ThingStatus.ONLINE);
}
private synchronized void startAutomaticRefresh(long refreshInterval) {
if (pollingJob != null && !pollingJob.isCancelled()) {
pollingJob.cancel(true);
}
pollingJob = scheduler.scheduleWithFixedDelay(this::refreshDeviceList, 0, refreshInterval,
TimeUnit.MILLISECONDS);
}
private void scheduleImmediateRefresh() {
// We schedule in 10 sec, to avoid multiple updates
logger.debug("Current remaining delay {}", pollingJob.getDelay(TimeUnit.SECONDS));
if (pollingJob.getDelay(TimeUnit.SECONDS) > REFRESH_DELAY) {
if (immediateRefreshJob == null || immediateRefreshJob.isDone()) {
immediateRefreshJob = scheduler.schedule(this::refreshDeviceList, REFRESH_DELAY, TimeUnit.SECONDS);
}
}
}
synchronized void refreshDeviceList() {
try {
updateDevices(deviceList);
updateSensors(sensorList);
updateStatus(ThingStatus.ONLINE);
} catch (TellstickException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
logger.error("Failed to update", e);
} catch (Exception e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
logger.error("Failed to update", e);
}
}
private synchronized void updateDevices(TellstickNetDevices previouslist) throws TellstickException {
TellstickNetDevices newList = controller.callRestMethod(TelldusLiveDeviceController.HTTP_TELLDUS_DEVICES,
TellstickNetDevices.class);
logger.debug("Device list {}", newList.getDevices());
if (newList.getDevices() != null) {
if (previouslist == null) {
logger.debug("updateDevices, Creating devices.");
for (TellstickNetDevice device : newList.getDevices()) {
device.setUpdated(true);
for (DeviceStatusListener listener : deviceStatusListeners) {
listener.onDeviceAdded(getThing(), device);
}
}
this.deviceList = newList;
} else {
logger.debug("updateDevices, Updating devices.");
for (TellstickNetDevice device : newList.getDevices()) {
int index = previouslist.getDevices().indexOf(device);
logger.debug("Device:{} found at {}", device, index);
if (index >= 0) {
TellstickNetDevice orgDevice = previouslist.getDevices().get(index);
if (device.getState() != orgDevice.getState()) {
orgDevice.setState(device.getState());
orgDevice.setStatevalue(device.getStatevalue());
orgDevice.setUpdated(true);
}
} else {
logger.debug("New Device - Adding:{}", device);
previouslist.getDevices().add(device);
device.setUpdated(true);
for (DeviceStatusListener listener : deviceStatusListeners) {
listener.onDeviceAdded(getThing(), device);
}
}
}
}
for (TellstickNetDevice device : deviceList.getDevices()) {
if (device.isUpdated()) {
logger.debug("Updated device:{}", device);
for (DeviceStatusListener listener : deviceStatusListeners) {
listener.onDeviceStateChanged(getThing(), device,
new TellstickDeviceEvent(device, null, null, null, System.currentTimeMillis()));
}
device.setUpdated(false);
}
}
}
}
private synchronized void updateSensors(TellstickNetSensors previouslist) throws TellstickException {
TellstickNetSensors newList = controller.callRestMethod(TelldusLiveDeviceController.HTTP_TELLDUS_SENSORS,
TellstickNetSensors.class);
logger.debug("Updated sensors:{}", newList.getSensors());
if (newList.getSensors() != null) {
if (previouslist == null) {
logger.debug("First update of sensors");
this.sensorList = newList;
for (TellstickNetSensor sensor : sensorList.getSensors()) {
sensor.setUpdated(true);
for (DeviceStatusListener listener : deviceStatusListeners) {
listener.onDeviceAdded(getThing(), sensor);
}
}
} else {
logger.debug("Update sensors, reset updated flag");
for (TellstickNetSensor sensor : previouslist.getSensors()) {
sensor.setUpdated(false);
}
logger.debug("Update sensors, reset updated flag1");
for (TellstickNetSensor sensor : newList.getSensors()) {
int index = this.sensorList.getSensors().indexOf(sensor);
if (index >= 0) {
TellstickNetSensor orgSensor = this.sensorList.getSensors().get(index);
logger.debug("Update sensor {}, prev update {}, new update {}", sensor.getId(),
orgSensor.getLastUpdated(), sensor.getLastUpdated());
if (sensor.getLastUpdated() > orgSensor.getLastUpdated()) {
logger.debug("Update for sensor:{}", sensor);
orgSensor.setData(sensor.getData());
orgSensor.setLastUpdated(sensor.getLastUpdated());
orgSensor.setUpdated(true);
sensor.setUpdated(true);
}
} else {
logger.debug("Adding sensor {}, new update {}", sensor.getId(), sensor.getLastUpdated());
this.sensorList.getSensors().add(sensor);
sensor.setUpdated(true);
for (DeviceStatusListener listener : deviceStatusListeners) {
listener.onDeviceAdded(getThing(), sensor);
}
}
}
}
for (TellstickNetSensor sensor : sensorList.getSensors()) {
if (sensor.getData() != null && sensor.isUpdated()) {
for (DeviceStatusListener listener : deviceStatusListeners) {
for (DataTypeValue type : sensor.getData()) {
listener.onDeviceStateChanged(getThing(), sensor,
new TellstickNetSensorEvent(sensor.getId(), type.getValue(), type,
sensor.getProtocol(), sensor.getModel(), System.currentTimeMillis()));
}
}
sensor.setUpdated(false);
}
}
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
scheduleImmediateRefresh();
}
}
@Override
public void handleRemoval() {
super.handleRemoval();
}
@Override
public void handleUpdate(ChannelUID channelUID, State newState) {
super.handleUpdate(channelUID, newState);
}
@Override
public void thingUpdated(Thing thing) {
super.thingUpdated(thing);
}
@Override
public boolean registerDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
if (deviceStatusListener == null) {
throw new IllegalArgumentException("It's not allowed to pass a null deviceStatusListener.");
}
return deviceStatusListeners.add(deviceStatusListener);
}
@Override
public boolean unregisterDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
return deviceStatusListeners.remove(deviceStatusListener);
}
private Device getDevice(String id, List<TellstickNetDevice> devices) {
for (Device device : devices) {
if (device.getId() == Integer.valueOf(id)) {
return device;
}
}
return null;
}
private Device getSensor(String id, List<TellstickNetSensor> sensors) {
for (Device sensor : sensors) {
if (sensor.getId() == Integer.valueOf(id)) {
return sensor;
}
}
return null;
}
@Override
public Device getDevice(String serialNumber) {
return getDevice(serialNumber, getDevices());
}
private List<TellstickNetDevice> getDevices() {
if (deviceList == null) {
refreshDeviceList();
}
return deviceList.getDevices();
}
@Override
public Device getSensor(String deviceUUId) {
Device result = null;
if (sensorList != null) {
result = getSensor(deviceUUId, sensorList.getSensors());
}
return result;
}
@Override
public void rescanTelldusDevices() {
this.deviceList = null;
this.sensorList = null;
refreshDeviceList();
}
@Override
public TelldusDeviceController getController() {
return controller;
}
}

View File

@@ -0,0 +1,328 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.live;
import java.math.BigDecimal;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.asynchttpclient.AsyncHttpClient;
import org.asynchttpclient.AsyncHttpClientConfig;
import org.asynchttpclient.DefaultAsyncHttpClient;
import org.asynchttpclient.DefaultAsyncHttpClientConfig;
import org.asynchttpclient.DefaultAsyncHttpClientConfig.Builder;
import org.asynchttpclient.Response;
import org.asynchttpclient.oauth.ConsumerKey;
import org.asynchttpclient.oauth.OAuthSignatureCalculator;
import org.asynchttpclient.oauth.RequestToken;
import org.openhab.binding.tellstick.internal.TelldusBindingException;
import org.openhab.binding.tellstick.internal.handler.TelldusDeviceController;
import org.openhab.binding.tellstick.internal.live.xml.TelldusLiveResponse;
import org.openhab.binding.tellstick.internal.live.xml.TellstickNetDevice;
import org.openhab.core.library.types.IncreaseDecreaseType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tellstick.JNA;
import org.tellstick.device.TellstickDevice;
import org.tellstick.device.TellstickDeviceEvent;
import org.tellstick.device.TellstickException;
import org.tellstick.device.TellstickSensorEvent;
import org.tellstick.device.iface.Device;
import org.tellstick.device.iface.DeviceChangeListener;
import org.tellstick.device.iface.SensorListener;
import org.tellstick.device.iface.SwitchableDevice;
/**
* {@link TelldusLiveDeviceController} is the communication with Telldus Live service (Tellstick.NET and ZNET)
* This controller uses XML based Rest API to communicate with Telldus Live.
*
* @author Jarle Hjortland - Initial contribution
*/
public class TelldusLiveDeviceController implements DeviceChangeListener, SensorListener, TelldusDeviceController {
private final Logger logger = LoggerFactory.getLogger(TelldusLiveDeviceController.class);
private long lastSend = 0;
public static final long DEFAULT_INTERVAL_BETWEEN_SEND = 250;
static final int REQUEST_TIMEOUT_MS = 5000;
private AsyncHttpClient client;
static final String HTTP_API_TELLDUS_COM_XML = "http://api.telldus.com/xml/";
static final String HTTP_TELLDUS_CLIENTS = HTTP_API_TELLDUS_COM_XML + "clients/list";
static final String HTTP_TELLDUS_DEVICES = HTTP_API_TELLDUS_COM_XML + "devices/list?supportedMethods=19";
static final String HTTP_TELLDUS_SENSORS = HTTP_API_TELLDUS_COM_XML
+ "sensors/list?includeValues=1&includeScale=1&includeUnit=1";
static final String HTTP_TELLDUS_SENSOR_INFO = HTTP_API_TELLDUS_COM_XML + "sensor/info";
static final String HTTP_TELLDUS_DEVICE_DIM = HTTP_API_TELLDUS_COM_XML + "device/dim?id=%d&level=%d";
static final String HTTP_TELLDUS_DEVICE_TURNOFF = HTTP_API_TELLDUS_COM_XML + "device/turnOff?id=%d";
static final String HTTP_TELLDUS_DEVICE_TURNON = HTTP_API_TELLDUS_COM_XML + "device/turnOn?id=%d";
private static final int MAX_RETRIES = 3;
public TelldusLiveDeviceController() {
}
@Override
public void dispose() {
try {
client.close();
} catch (Exception e) {
logger.error("Failed to close client", e);
}
}
void connectHttpClient(String publicKey, String privateKey, String token, String tokenSecret) {
ConsumerKey consumer = new ConsumerKey(publicKey, privateKey);
RequestToken user = new RequestToken(token, tokenSecret);
OAuthSignatureCalculator calc = new OAuthSignatureCalculator(consumer, user);
this.client = new DefaultAsyncHttpClient(createAsyncHttpClientConfig());
try {
this.client.setSignatureCalculator(calc);
Response response = client.prepareGet(HTTP_TELLDUS_CLIENTS).execute().get();
logger.debug("Response {} statusText {}", response.getResponseBody(), response.getStatusText());
} catch (InterruptedException | ExecutionException e) {
logger.error("Failed to connect", e);
}
}
private AsyncHttpClientConfig createAsyncHttpClientConfig() {
Builder builder = new DefaultAsyncHttpClientConfig.Builder();
builder.setConnectTimeout(REQUEST_TIMEOUT_MS);
return builder.build();
}
@Override
public void handleSendEvent(Device device, int resendCount, boolean isdimmer, Command command)
throws TellstickException {
logger.info("Send {} to {}", command, device);
if (device instanceof TellstickNetDevice) {
if (command == OnOffType.ON) {
turnOn(device);
} else if (command == OnOffType.OFF) {
turnOff(device);
} else if (command instanceof PercentType) {
dim(device, (PercentType) command);
} else if (command instanceof IncreaseDecreaseType) {
increaseDecrease(device, ((IncreaseDecreaseType) command));
}
} else if (device instanceof SwitchableDevice) {
if (command == OnOffType.ON) {
if (isdimmer) {
logger.debug("Turn off first in case it is allready on");
turnOff(device);
}
turnOn(device);
} else if (command == OnOffType.OFF) {
turnOff(device);
}
} else {
logger.warn("Cannot send to {}", device);
}
}
private void increaseDecrease(Device dev, IncreaseDecreaseType increaseDecreaseType) throws TellstickException {
String strValue = ((TellstickDevice) dev).getData();
double value = 0;
if (strValue != null) {
value = Double.valueOf(strValue);
}
int percent = (int) Math.round((value / 255) * 100);
if (IncreaseDecreaseType.INCREASE == increaseDecreaseType) {
percent = Math.min(percent + 10, 100);
} else if (IncreaseDecreaseType.DECREASE == increaseDecreaseType) {
percent = Math.max(percent - 10, 0);
}
dim(dev, new PercentType(percent));
}
private void dim(Device dev, PercentType command) throws TellstickException {
double value = command.doubleValue();
// 0 means OFF and 100 means ON
if (value == 0 && dev instanceof TellstickNetDevice) {
turnOff(dev);
} else if (value == 100 && dev instanceof TellstickNetDevice) {
turnOn(dev);
} else if (dev instanceof TellstickNetDevice
&& (((TellstickNetDevice) dev).getMethods() & JNA.CLibrary.TELLSTICK_DIM) > 0) {
long tdVal = Math.round((value / 100) * 255);
TelldusLiveResponse response = callRestMethod(String.format(HTTP_TELLDUS_DEVICE_DIM, dev.getId(), tdVal),
TelldusLiveResponse.class);
handleResponse((TellstickNetDevice) dev, response);
} else {
throw new TelldusBindingException("Cannot send DIM to " + dev);
}
}
private void turnOff(Device dev) throws TellstickException {
if (dev instanceof TellstickNetDevice) {
TelldusLiveResponse response = callRestMethod(String.format(HTTP_TELLDUS_DEVICE_TURNOFF, dev.getId()),
TelldusLiveResponse.class);
handleResponse((TellstickNetDevice) dev, response);
} else {
throw new TelldusBindingException("Cannot send OFF to " + dev);
}
}
private void handleResponse(TellstickNetDevice device, TelldusLiveResponse response) throws TellstickException {
if (response == null || (response.status == null && response.error == null)) {
throw new TelldusBindingException("No response " + response);
} else if (response.error != null) {
if (response.error.equals("The client for this device is currently offline")) {
device.setOnline(false);
device.setUpdated(true);
}
throw new TelldusBindingException("Error " + response.error);
} else if (!response.status.trim().equals("success")) {
throw new TelldusBindingException("Response " + response.status);
}
}
private void turnOn(Device dev) throws TellstickException {
if (dev instanceof TellstickNetDevice) {
TelldusLiveResponse response = callRestMethod(String.format(HTTP_TELLDUS_DEVICE_TURNON, dev.getId()),
TelldusLiveResponse.class);
handleResponse((TellstickNetDevice) dev, response);
} else {
throw new TelldusBindingException("Cannot send ON to " + dev);
}
}
@Override
public State calcState(Device dev) {
TellstickNetDevice device = (TellstickNetDevice) dev;
State st = null;
if (device.getOnline()) {
switch (device.getState()) {
case JNA.CLibrary.TELLSTICK_TURNON:
st = OnOffType.ON;
break;
case JNA.CLibrary.TELLSTICK_TURNOFF:
st = OnOffType.OFF;
break;
case JNA.CLibrary.TELLSTICK_DIM:
BigDecimal dimValue = new BigDecimal(device.getStatevalue());
if (dimValue.intValue() == 0) {
st = OnOffType.OFF;
} else if (dimValue.intValue() >= 255) {
st = OnOffType.ON;
} else {
st = OnOffType.ON;
}
break;
default:
logger.warn("Could not handle {} for {}", device.getState(), device);
}
}
return st;
}
@Override
public BigDecimal calcDimValue(Device device) {
BigDecimal dimValue = new BigDecimal(0);
switch (((TellstickNetDevice) device).getState()) {
case JNA.CLibrary.TELLSTICK_TURNON:
dimValue = new BigDecimal(100);
break;
case JNA.CLibrary.TELLSTICK_TURNOFF:
break;
case JNA.CLibrary.TELLSTICK_DIM:
dimValue = new BigDecimal(((TellstickNetDevice) device).getStatevalue());
dimValue = dimValue.multiply(new BigDecimal(100));
dimValue = dimValue.divide(new BigDecimal(255), 0, BigDecimal.ROUND_HALF_UP);
break;
default:
logger.warn("Could not handle {} for {}", (((TellstickNetDevice) device).getState()), device);
}
return dimValue;
}
public long getLastSend() {
return lastSend;
}
public void setLastSend(long currentTimeMillis) {
lastSend = currentTimeMillis;
}
@Override
public void onRequest(TellstickSensorEvent newDevices) {
setLastSend(newDevices.getTimestamp());
}
@Override
public void onRequest(TellstickDeviceEvent newDevices) {
setLastSend(newDevices.getTimestamp());
}
<T> T callRestMethod(String uri, Class<T> response) throws TelldusLiveException {
T resultObj = null;
try {
for (int i = 0; i < MAX_RETRIES; i++) {
try {
resultObj = innerCallRest(uri, response);
break;
} catch (TimeoutException e) {
logger.warn("TimeoutException error in get", e);
} catch (InterruptedException e) {
logger.warn("InterruptedException error in get", e);
}
}
} catch (JAXBException e) {
logger.warn("Encoding error in get", e);
logResponse(uri, e);
throw new TelldusLiveException(e);
} catch (XMLStreamException e) {
logger.warn("Communication error in get", e);
logResponse(uri, e);
throw new TelldusLiveException(e);
} catch (ExecutionException e) {
logger.warn("ExecutionException error in get", e);
throw new TelldusLiveException(e);
}
return resultObj;
}
private <T> T innerCallRest(String uri, Class<T> response) throws InterruptedException, ExecutionException,
TimeoutException, JAXBException, FactoryConfigurationError, XMLStreamException {
Future<Response> future = client.prepareGet(uri).execute();
Response resp = future.get(REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
// TelldusLiveHandler.logger.info("Devices" + resp.getResponseBody());
JAXBContext jc = JAXBContext.newInstance(response);
XMLInputFactory xif = XMLInputFactory.newInstance();
XMLStreamReader xsr = xif.createXMLStreamReader(resp.getResponseBodyAsStream());
// xsr = new PropertyRenamerDelegate(xsr);
@SuppressWarnings("unchecked")
T obj = (T) jc.createUnmarshaller().unmarshal(xsr);
if (logger.isTraceEnabled()) {
logger.trace("Request [{}] Response:{}", uri, resp.getResponseBody());
}
return obj;
}
private void logResponse(String uri, Exception e) {
if (e != null) {
logger.warn("Request [{}] Failure:{}", uri, e.getMessage());
}
}
}

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.live;
import org.tellstick.device.TellstickException;
/**
* {@link TelldusLiveException} is used when there is exception communicating with Telldus Live.
* This exception extends the Telldus Core exception.
*
* @author Jarle Hjortland - Initial contribution
*/
public class TelldusLiveException extends TellstickException {
public TelldusLiveException(Exception source) {
super(null, 0);
this.initCause(source);
}
private static final long serialVersionUID = 3067179547449451158L;
@Override
public String getMessage() {
return getCause().getMessage();
}
}

View File

@@ -0,0 +1,76 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.live.xml;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
/**
* Class used to deserialize XML from Telldus Live.
*
* @author Jarle Hjortland - Initial contribution
*/
@XmlRootElement(name = "data")
public class DataTypeValue {
@XmlAttribute(name = "name")
@XmlJavaTypeAdapter(value = NameToDataType.class)
private LiveDataType dataType;
@XmlAttribute(name = "value")
private String data;
private String unit;
private Integer scale;
public LiveDataType getName() {
return dataType;
}
public void setName(LiveDataType dataType) {
this.dataType = dataType;
}
public String getValue() {
return data;
}
public void setValue(String data) {
this.data = data;
}
@XmlAttribute(name = "unit")
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
@XmlAttribute(name = "scale")
public Integer getScale() {
return scale;
}
public void setScale(Integer scale) {
this.scale = scale;
}
@Override
public String toString() {
return "DataTypeValue [dataType=" + dataType + ", data=" + data + ", unit=" + unit + "]";
}
}

View File

@@ -0,0 +1,53 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.live.xml;
/**
* This enum is used to describe the value types in the Live API from telldus.
*
* @author Jarle Hjortland - Initial contribution
*/
public enum LiveDataType {
HUMIDITY("humidity"),
TEMPERATURE("temp"),
WINDAVERAGE("windaverage"),
WINDDIRECTION("winddirection"),
WINDGUST("windgust"),
RAINRATE("rainrate"),
RAINTOTAL("rainttotal"),
WATT("watt"),
LUMINATION("lum"),
UNKOWN("unkown");
private String name;
LiveDataType(String name) {
this.name = name;
}
public static LiveDataType fromName(String name) {
LiveDataType result = LiveDataType.UNKOWN;
for (LiveDataType m : LiveDataType.values()) {
if (m.name.equals(name)) {
result = m;
break;
}
}
return result;
}
@Override
public String toString() {
return name;
}
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.live.xml;
import javax.xml.bind.annotation.adapters.XmlAdapter;
/**
* Class used to deserialize XML from Telldus Live.
*
* @author Jarle Hjortland - Initial contribution
*/
public class NameToDataType extends XmlAdapter<String, LiveDataType> {
@Override
public LiveDataType unmarshal(String v) throws Exception {
return LiveDataType.fromName(v);
}
@Override
public String marshal(LiveDataType v) throws Exception {
return v.toString();
}
}

View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.live.xml;
import javax.xml.bind.annotation.adapters.XmlAdapter;
/**
* Class used to deserialize XML from Telldus Live.
*
* @author Jarle Hjortland - Initial contribution
*/
public class NumberToBooleanMapper extends XmlAdapter<Integer, Boolean> {
@Override
public Boolean unmarshal(Integer v) throws Exception {
return v == 1 ? true : false;
}
@Override
public Integer marshal(Boolean v) throws Exception {
return v ? 1 : 0;
}
}

View File

@@ -0,0 +1,34 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.live.xml;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Class used to deserialize XML from Telldus Live.
*
* @author Jarle Hjortland - Initial contribution
*/
@XmlRootElement(name = "device")
public class TelldusLiveResponse {
@XmlElement
public String status;
@XmlElement
public String error;
@Override
public String toString() {
return "TelldusLiveResponse [status=" + status + ", error=" + error + "]";
}
}

View File

@@ -0,0 +1,173 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.live.xml;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.tellstick.device.iface.Device;
import org.tellstick.enums.DeviceType;
/**
* Class used to deserialize XML from Telldus Live.
*
* @author Jarle Hjortland - Initial contribution
*/
@XmlAccessorType(XmlAccessType.FIELD)
public class TellstickNetDevice implements Device {
@XmlAttribute(name = "id")
int deviceId;
private String protocol;
private String model;
@XmlAttribute()
private String name;
@XmlAttribute()
@XmlJavaTypeAdapter(value = NumberToBooleanMapper.class)
private Boolean online;
@XmlAttribute
private int state;
@XmlAttribute
private String statevalue;
@XmlAttribute
private int methods;
private boolean updated;
public TellstickNetDevice() {
}
public TellstickNetDevice(int id) {
this.deviceId = id;
}
@Override
public int getId() {
return deviceId;
}
@Override
public String getUUId() {
return Integer.toString(deviceId);
}
@Override
public String getProtocol() {
return protocol;
}
@Override
public String getModel() {
return model;
}
@Override
public DeviceType getDeviceType() {
return DeviceType.DEVICE;
}
@Override
public String getName() {
return name;
}
public void setId(int deviceId) {
this.deviceId = deviceId;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public void setModel(String model) {
this.model = model;
}
public void setName(String name) {
this.name = name;
}
public boolean getOnline() {
return online;
}
// @XmlJavaTypeAdapter(value = NumberToBooleanMapper.class)
public void setOnline(boolean online) {
this.online = online;
}
public void setUpdated(boolean b) {
this.updated = b;
}
public boolean isUpdated() {
return updated;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public String getStatevalue() {
return statevalue;
}
public void setStatevalue(String statevalue) {
this.statevalue = statevalue;
}
@Override
public int hashCode() {
int prime = 31;
int result = 1;
result = prime * result + deviceId;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
TellstickNetDevice other = (TellstickNetDevice) obj;
if (deviceId != other.deviceId) {
return false;
}
return true;
}
public int getMethods() {
return methods;
}
public void setMethods(int methods) {
this.methods = methods;
}
@Override
public String toString() {
return "TellstickNetDevice [deviceId=" + deviceId + ", name=" + name + ", online=" + online + ", state=" + state
+ ", statevalue=" + statevalue + ", updated=" + updated + "]";
}
}

View File

@@ -0,0 +1,38 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.live.xml;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Class used to deserialize XML from Telldus Live.
*
* @author Jarle Hjortland - Initial contribution
*/
@XmlRootElement(name = "devices")
public class TellstickNetDevices {
List<TellstickNetDevice> devices;
@XmlElement(name = "device")
public List<TellstickNetDevice> getDevices() {
return devices;
}
public void setDevices(List<TellstickNetDevice> devices) {
this.devices = devices;
}
}

View File

@@ -0,0 +1,189 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.live.xml;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.tellstick.device.iface.Device;
import org.tellstick.enums.DeviceType;
/**
* Class used to deserialize XML from Telldus Live.
*
* @author Jarle Hjortland - Initial contribution
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "sensor")
public class TellstickNetSensor implements Device {
@XmlAttribute(name = "id")
int deviceId;
@XmlAttribute()
private String protocol;
@XmlAttribute()
private String name;
@XmlAttribute()
@XmlJavaTypeAdapter(value = NumberToBooleanMapper.class)
private Boolean online;
@XmlElement(name = "data")
private List<DataTypeValue> data;
@XmlAttribute()
private Long lastUpdated;
private boolean updated;
@XmlAttribute()
private Long battery;
public TellstickNetSensor() {
}
public TellstickNetSensor(int id) {
this.deviceId = id;
}
@Override
public int getId() {
return deviceId;
}
@Override
public String getUUId() {
return Integer.toString(deviceId);
}
@Override
public String getProtocol() {
return protocol;
}
@Override
public DeviceType getDeviceType() {
return DeviceType.SENSOR;
}
@Override
public String getName() {
return name;
}
public void setId(int deviceId) {
this.deviceId = deviceId;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public void setName(String name) {
this.name = name;
}
public boolean getOnline() {
return online;
}
// @XmlJavaTypeAdapter(value = NumberToBooleanMapper.class)
public void setOnline(boolean online) {
this.online = online;
}
public List<DataTypeValue> getData() {
return data;
}
public void setData(List<DataTypeValue> data) {
this.data = data;
}
@Override
public String getModel() {
return null;
}
public Long getLastUpdated() {
return lastUpdated;
}
public void setLastUpdated(Long lastUpdated) {
this.lastUpdated = lastUpdated;
}
@Override
public int hashCode() {
int prime = 31;
int result = 1;
result = prime * result + deviceId;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
TellstickNetSensor other = (TellstickNetSensor) obj;
if (deviceId != other.deviceId) {
return false;
}
return true;
}
public void setUpdated(boolean b) {
this.updated = b;
}
public boolean isUpdated() {
return updated;
}
public boolean isSensorOfType(LiveDataType type) {
boolean res = false;
if (data != null) {
for (DataTypeValue val : data) {
if (val.getName() == type) {
res = true;
break;
}
}
}
return res;
}
public Long getBattery() {
return battery;
}
public void setBattery(Long battery) {
this.battery = battery;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("TellstickNetSensor [deviceId=").append(deviceId).append(", protocol=").append(protocol)
.append(", name=").append(name).append(", online=").append(online).append(", data=").append(data)
.append(", lastUpdated=").append(lastUpdated).append(", updated=").append(updated).append("]");
return builder.toString();
}
}

View File

@@ -0,0 +1,43 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.live.xml;
import org.openhab.binding.tellstick.internal.TellstickRuntimeException;
import org.tellstick.device.TellstickSensorEvent;
import org.tellstick.device.iface.TellstickEvent;
import org.tellstick.enums.DataType;
/**
* This class is used for events for the telldus live sensors.
*
* @author Jarle Hjortland - Initial contribution
*/
public class TellstickNetSensorEvent extends TellstickSensorEvent implements TellstickEvent {
private DataTypeValue dataType;
public TellstickNetSensorEvent(int sensorId, String data, DataTypeValue dataValue, String protocol, String model,
long timeStamp) {
super(sensorId, data, null, protocol, model, timeStamp);
this.dataType = dataValue;
}
public DataTypeValue getDataTypeValue() {
return dataType;
}
@Override
public DataType getDataType() {
throw new TellstickRuntimeException("Should not call this method");
}
}

View File

@@ -0,0 +1,38 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.tellstick.internal.live.xml;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Class used to deserialize XML from Telldus Live.
*
* @author Jarle Hjortland - Initial contribution
*/
@XmlRootElement(name = "sensors")
public class TellstickNetSensors {
List<TellstickNetSensor> sensors;
@XmlElement(name = "sensor")
public List<TellstickNetSensor> getSensors() {
return sensors;
}
public void setSensors(List<TellstickNetSensor> devices) {
this.sensors = devices;
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="tellstick" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>Tellstick Binding</name>
<description>This is the binding for Telldus Tellstick Basic, Duo, .Net and Z-Net Lite.</description>
<author>Jarle Hjortland</author>
</binding:binding>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<config-description:config-descriptions
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0
https://openhab.org/schemas/config-description-1.0.0.xsd">
<config-description uri="thing-type:tellstick:sensor-config">
<parameter name="protocol" type="text">
<label>Protocol</label>
<description>The protocol used by a specific device.</description>
<required>false</required>
</parameter>
<parameter name="model" type="text">
<label>Model</label>
<description>The model used by a specific device.</description>
<required>false</required>
</parameter>
<parameter name="name" type="text">
<label>Name</label>
<description>The name of the device (manually entered)</description>
<required>false</required>
</parameter>
<parameter name="deviceId" type="text">
<label>DeviceID</label>
<description>This function returns the unique id of a device with a specific index.</description>
<required>true</required>
</parameter>
</config-description>
</config-description:config-descriptions>

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="tellstick"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<bridge-type id="telldus-core">
<label>Telldus Core Gateway</label>
<description>This bridge represents the telldus center on a local computer.</description>
<config-description>
<parameter name="libraryPath" type="text" required="false">
<label>The Location of Telldus Core DLL/SO</label>
<description>The location of Telldus Core DLL/SO
</description>
<default>C:/Program Files/Telldus/;C:/Program Files (x86)/Telldus/</default>
</parameter>
<parameter name="resendInterval" type="integer" required="false">
<label>ResendInterval</label>
<description>The interval between resend.</description>
<default>100</default>
</parameter>
</config-description>
</bridge-type>
<bridge-type id="telldus-live">
<label>Telldus Live Gateway</label>
<description>This bridge represents the telldus live cloud service.</description>
<config-description>
<parameter name="privateKey" type="text" required="true">
<context>password</context>
<label>Private Key</label>
<description>The private key from telldus</description>
</parameter>
<parameter name="publicKey" type="text" required="true">
<context>credentials</context>
<label>Public Key</label>
<description>The public key from telldus</description>
</parameter>
<parameter name="token" type="text" required="true">
<context>credentials</context>
<label>Access Token</label>
<description>The openauth token.</description>
</parameter>
<parameter name="tokenSecret" type="text" required="true">
<context>password</context>
<label>Token Secret</label>
<description>The openauth token secret.</description>
</parameter>
<parameter name="refreshInterval" type="integer" required="false">
<label>Refresh Interval</label>
<description>The refresh interval in ms which is used to poll Telldus Live.
</description>
<default>60000</default>
</parameter>
</config-description>
</bridge-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="tellstick"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- Tellstick Dimmer -->
<thing-type id="dimmer">
<supported-bridge-type-refs>
<bridge-type-ref id="telldus-core"/>
<bridge-type-ref id="telldus-live"/>
</supported-bridge-type-refs>
<label>Dimmable Device</label>
<description>This is a Dimmable device</description>
<channels>
<channel id="dimmer" typeId="dimmer"/>
<channel id="state" typeId="state"/>
<channel id="timestamp" typeId="timestamp"/>
</channels>
<config-description>
<parameter name="protocol" type="text" required="false">
<label>Protocol</label>
<description>The protocol used by a specific device.</description>
<required>false</required>
</parameter>
<parameter name="name" type="text">
<label>Name</label>
<description>The name of the device</description>
<required>false</required>
</parameter>
<parameter name="deviceId" type="text">
<label>DeviceID</label>
<description>This is the unique id of a device.</description>
<required>true</required>
</parameter>
<parameter name="model" type="text">
<label>Model</label>
<description>The model used by a specific device.</description>
<required>false</required>
</parameter>
<parameter name="repeat" type="integer">
<label>Repeat</label>
<description>The number of times to resend.</description>
<required>false</required>
<default>2</default>
</parameter>
</config-description>
</thing-type>
<thing-type id="switch">
<supported-bridge-type-refs>
<bridge-type-ref id="telldus-core"/>
</supported-bridge-type-refs>
<label>On/Off Device</label>
<description>This Thing defines a Switch Device</description>
<channels>
<channel id="state" typeId="state"/>
<channel id="timestamp" typeId="timestamp"/>
</channels>
<config-description>
<parameter name="protocol" type="text">
<label>Protocol</label>
<description>The protocol used by a specific device.</description>
<required>false</required>
</parameter>
<parameter name="name" type="text">
<label>Name</label>
<description>The name of the device</description>
<required>false</required>
</parameter>
<parameter name="deviceId" type="text">
<label>DeviceID</label>
<description>This is the unique id of a device.</description>
<required>true</required>
</parameter>
<parameter name="repeat" type="integer">
<label>Repeat</label>
<description>The number of times to resend.</description>
<required>false</required>
<default>2</default>
</parameter>
<parameter name="dimmer" type="boolean">
<label>Dimmer</label>
<description>Is this a dimmer without absolute setting (e.g. you press on to start dim and then on again to stop
it).</description>
<required>false</required>
<default>false</default>
</parameter>
</config-description>
</thing-type>
<channel-type id="dimmer">
<item-type>Dimmer</item-type>
<label>Dimmer Value</label>
<description>The channel to control the dimmer</description>
</channel-type>
<channel-type id="state">
<item-type>Switch</item-type>
<label>Switch</label>
<description>Turns the power on or off</description>
<category>Switch</category>
</channel-type>
<channel-type id="timestamp">
<item-type>DateTime</item-type>
<label>Last Device Update</label>
<description>Last device update</description>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,156 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="tellstick"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="sensor">
<supported-bridge-type-refs>
<bridge-type-ref id="telldus-core"/>
<bridge-type-ref id="telldus-live"/>
</supported-bridge-type-refs>
<label>Sensor</label>
<description>This Thing defines a Sensor</description>
<channels>
<channel id="humidity" typeId="humidity"/>
<channel id="timestamp" typeId="timestamp"/>
<channel id="temperature" typeId="temperature"/>
<channel id="lux" typeId="lux"/>
</channels>
<config-description-ref uri="thing-type:tellstick:sensor-config"/>
</thing-type>
<thing-type id="rainsensor">
<supported-bridge-type-refs>
<bridge-type-ref id="telldus-core"/>
<bridge-type-ref id="telldus-live"/>
</supported-bridge-type-refs>
<label>RainSensor</label>
<description>This Thing defines a Rain Sensor</description>
<channels>
<channel id="timestamp" typeId="timestamp"/>
<channel id="rainrate" typeId="rainrate"/>
<channel id="raintotal" typeId="raintotal"/>
</channels>
<config-description-ref uri="thing-type:tellstick:sensor-config"/>
</thing-type>
<thing-type id="powersensor">
<supported-bridge-type-refs>
<bridge-type-ref id="telldus-live"/>
</supported-bridge-type-refs>
<label>PowerSensor</label>
<description>This Thing defines a Power Sensor</description>
<channels>
<channel id="timestamp" typeId="timestamp"/>
<channel id="watt" typeId="watt"/>
<channel id="ampere" typeId="ampere"/>
</channels>
<config-description-ref uri="thing-type:tellstick:sensor-config"/>
</thing-type>
<thing-type id="windsensor">
<supported-bridge-type-refs>
<bridge-type-ref id="telldus-core"/>
<bridge-type-ref id="telldus-live"/>
</supported-bridge-type-refs>
<label>WindSensor</label>
<description>This Thing defines a Wind Sensor</description>
<channels>
<channel id="timestamp" typeId="timestamp"/>
<channel id="windgust" typeId="windgust"/>
<channel id="winddirection" typeId="winddirection"/>
<channel id="windaverage" typeId="windaverage"/>
</channels>
<config-description-ref uri="thing-type:tellstick:sensor-config"/>
</thing-type>
<channel-type id="temperature">
<item-type>Number:Temperature</item-type>
<label>Temperature</label>
<description>Actual measured room temperature</description>
<category>Temperature</category>
<state pattern="%.1f %unit%" readOnly="true">
</state>
</channel-type>
<channel-type id="humidity">
<item-type>Number:Dimensionless</item-type>
<label>Humidity</label>
<description>Actual measured room Humidity</description>
<category>Humidity</category>
<state pattern="%d %unit%" readOnly="true">
</state>
</channel-type>
<channel-type id="rainrate">
<item-type>Number:Length</item-type>
<label>Rainrate</label>
<description>The current rain rate</description>
<state pattern="%d %unit%" readOnly="true"/>
</channel-type>
<channel-type id="raintotal">
<item-type>Number:Length</item-type>
<label>Total Rain</label>
<description>Total rain</description>
<state pattern="%d %unit%" readOnly="true">
</state>
</channel-type>
<channel-type id="windgust">
<item-type>Number:Speed</item-type>
<label>Wind Gust</label>
<description>Current wind gust</description>
<state pattern="%.1f %unit%" readOnly="true"></state>
</channel-type>
<channel-type id="windaverage">
<item-type>Number:Speed</item-type>
<label>Wind Average</label>
<description>Current average wind</description>
<state pattern="%.1f %unit%" readOnly="true"></state>
</channel-type>
<channel-type id="winddirection">
<item-type>Number:Angle</item-type>
<label>Wind Direction</label>
<description>Current wind direction</description>
<category>Wind</category>
<state min="0" max="360" step="1" readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="watt">
<item-type>Number:Power</item-type>
<label>Watt</label>
<description>Current kWatt</description>
<state readOnly="true" pattern="%f %unit%">
</state>
</channel-type>
<channel-type id="lux">
<item-type>Number:Illuminance</item-type>
<label>Lux</label>
<description>Current lumination</description>
<state readOnly="true" pattern="%f %unit%"/>
</channel-type>
<channel-type id="ampere">
<item-type>Number:ElectricCurrent</item-type>
<label>Ampere</label>
<description>Current ampere</description>
<state pattern="%.1f %unit%" readOnly="true"></state>
</channel-type>
<channel-type id="timestamp">
<item-type>DateTime</item-type>
<label>Last Device Update</label>
<description>Last device update</description>
<state readOnly="true">
</state>
</channel-type>
</thing:thing-descriptions>