/**
* Copyright (c) 2010-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.binding.ipx800.internal;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Map;
import org.openhab.binding.ipx800.Ipx800BindingProvider;
import org.openhab.binding.ipx800.internal.Ipx800Config.Ipx800DeviceConfig;
import org.openhab.binding.ipx800.internal.Ipx800GenericBindingProvider.Ipx800BindingConfig;
import org.openhab.binding.ipx800.internal.command.Ipx800Port;
import org.openhab.binding.ipx800.internal.command.Ipx800PortType;
import org.openhab.binding.ipx800.internal.exception.Ipx800UnknownDeviceException;
import org.openhab.binding.ipx800.internal.itemslot.Ipx800AstableSwitch;
import org.openhab.binding.ipx800.internal.itemslot.Ipx800Consumption;
import org.openhab.binding.ipx800.internal.itemslot.Ipx800ConsumptionPeriod;
import org.openhab.binding.ipx800.internal.itemslot.Ipx800Counter;
import org.openhab.binding.ipx800.internal.itemslot.Ipx800Dimmer;
import org.openhab.binding.ipx800.internal.itemslot.Ipx800DoubleClic;
import org.openhab.binding.ipx800.internal.itemslot.Ipx800Item;
import org.openhab.binding.ipx800.internal.itemslot.Ipx800Mirror;
import org.openhab.binding.ipx800.internal.itemslot.Ipx800OutputItem;
import org.openhab.binding.ipx800.internal.itemslot.Ipx800SimpleClic;
import org.openhab.core.binding.AbstractBinding;
import org.openhab.core.binding.BindingProvider;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The ipx800 binding. Handle the creation of items object linked to the devices.
*
* @author Seebag
* @since 1.8.0
*/
public class Ipx800Binding extends AbstractBinding<Ipx800BindingProvider>implements ManagedService {
private static final Logger logger = LoggerFactory.getLogger(Ipx800Binding.class);
/**
* Store the all ipx800 devices DeviceName, Ipx800DeviceConnector
*/
private Map<String, Ipx800DeviceConnector> devices = new HashMap<String, Ipx800DeviceConnector>();
public Ipx800Binding() {
}
@Override
public void bindingChanged(BindingProvider prov, String itemName) {
if (prov.getItemNames().contains(itemName)) {
try {
createInternalItem(itemName, prov);
} catch (Ipx800UnknownDeviceException e) {
logger.error("Item {} will be ignored", itemName);
}
} else {
logger.debug("Removing item {}", itemName);
for (String deviceName : devices.keySet()) {
for (Ipx800Port slot : devices.get(deviceName).getAllPorts()) {
slot.destroyItem(itemName);
}
}
}
}
/**
* Reload and reattach all items to all devices
*/
public void reloadItems() {
logger.trace("Size of providers : {}", providers.size());
for (Ipx800BindingProvider provider : providers) {
for (String itemName : provider.getItemNames()) {
try {
createInternalItem(itemName, provider);
} catch (Ipx800UnknownDeviceException e) {
logger.error("Item {} will be ignored", itemName);
}
}
}
}
private Ipx800DeviceAndPort getDeviceAndPort(String name, String portString) throws Ipx800UnknownDeviceException {
if (name.isEmpty() || portString.isEmpty()) {
return new Ipx800DeviceAndPort(null, null);
}
int extDelta = 0;
Ipx800DeviceConnector device = devices.get(name);
if (device == null) {
// Try to find extensions
for (Ipx800DeviceConnector dev : devices.values()) {
extDelta = dev.getExtensionDelta(name);
if (extDelta != 0) {
device = dev;
break;
}
}
if (extDelta == 0) {
throw new Ipx800UnknownDeviceException(
"Device '" + name + "' doesn't exist, please check your config/items");
}
}
return new Ipx800DeviceAndPort(device, device.getPort(portString, extDelta));
}
/**
* Create and attach new item to device
*
* @param itemName
* @param provider
* @throws Ipx800UnknownDeviceException
*/
private void createInternalItem(String itemName, BindingProvider prov) throws Ipx800UnknownDeviceException {
if (prov instanceof Ipx800GenericBindingProvider) {
Ipx800GenericBindingProvider provider = (Ipx800GenericBindingProvider) prov;
Ipx800BindingConfig config = provider.getBindingConfig(itemName);
if (config != null) {
Ipx800DeviceAndPort devPort = getDeviceAndPort(config.getDeviceName(), config.getPortField());
Ipx800DeviceConnector device = devPort.getDevice();
Ipx800Port port = devPort.getPort();
Ipx800Item item;
if (port.getCommandType() == Ipx800PortType.OUPUT) {
boolean pulse = false;
if (config.getExtra(0).equals("p")) {
pulse = true;
}
item = new Ipx800OutputItem(pulse);
} else if (port.getCommandType() == Ipx800PortType.COUNTER) {
if (config.getExtra(0).equals("a")) {
float unit = 1;
if (!config.getExtra(1).equals("")) {
unit = Float.parseFloat(config.getExtra(1));
}
Ipx800ConsumptionPeriod period = Ipx800ConsumptionPeriod.getPeriod(config.getExtra(2));
item = new Ipx800Consumption(unit, period);
} else {
item = new Ipx800Counter();
}
} else {
if (config.getExtra(0).equals("D")) {
item = new Ipx800DoubleClic();
port.switchToMultiHandler();
} else if (config.getExtra(0).equals("d")) {
item = new Ipx800SimpleClic();
port.switchToMultiHandler();
} else if (config.getExtra(0).equals("v")) {
if (config.getExtra(1).equals("")) {
item = new Ipx800Dimmer();
} else {
item = new Ipx800Dimmer(new Integer(config.getExtra(1)));
}
port.switchToMultiHandler();
} else if (config.getExtra(0).equals("m")) {
item = new Ipx800Mirror();
} else {
item = new Ipx800AstableSwitch();
}
}
item.setBinding(this);
item.setItemName(itemName);
// If no to action set : null is returned
String toDeviceName = config.getToDeviceName();
if (toDeviceName.isEmpty()) {
toDeviceName = config.getDeviceName();
}
Ipx800DeviceAndPort devToPort = getDeviceAndPort(toDeviceName, config.getToPortField());
Ipx800DeviceConnector toDevice = devToPort.getDevice();
Ipx800Port toPort = devToPort.getPort();
Ipx800OutputItem toItem = null;
if (toDevice != null && toPort != null) {
toItem = new Ipx800OutputItem(config.isToPulse());
toItem.setItemName(itemName + "-out");
toItem.setBinding(this);
toItem.setFromItem(item);
item.setToItem(toItem);
toPort.attachItem(itemName + "-out", toItem);
}
port.attachItem(itemName, item);
if (toItem != null) {
logger.info("Item {} created using {}, attached to {} on port {} to item {}", itemName, item,
device, port, toItem);
} else {
logger.info("Item {} created using {}, attached to {} on port {}", itemName, item, device, port);
}
}
}
}
@Override
public void activate() {
logger.debug("Activate called");
}
@Override
public void deactivate() {
for (Ipx800DeviceConnector device : devices.values()) {
device.destroyAndExit();
}
logger.debug("DeActivate called");
}
/**
* @{inheritDoc
*/
@Override
protected void internalReceiveCommand(String itemName, Command command) {
logger.debug("Received command item='{}', command='{}'", itemName, command.toString());
for (Ipx800DeviceConnector device : devices.values()) {
for (Ipx800Port slot : device.getAllPorts()) {
Ipx800Item itemSlot = slot.getItemSlot(itemName);
if (itemSlot != null) {
itemSlot.setState((State) command);
if (itemSlot instanceof Ipx800OutputItem) {
device.setOutput((Ipx800OutputItem) itemSlot);
}
}
}
}
}
protected void addBindingProvider(Ipx800BindingProvider bindingProvider) {
super.addBindingProvider(bindingProvider);
}
protected void removeBindingProvider(Ipx800BindingProvider bindingProvider) {
super.removeBindingProvider(bindingProvider);
}
/**
* {@inheritDoc}
*/
@Override
public void updated(Dictionary<String, ?> config) throws ConfigurationException {
if (config != null) {
// Unload items is not necessary as devices list is erased
quitThreads();
// read new config
Ipx800Config ipx800Config = Ipx800Config.readConfig(config);
logger.info("Ipx800 configuration read with " + ipx800Config.getDevices().size() + " device(s) : ");
// Start thread
startThreads();
// Reload items configuration
reloadItems();
}
}
/**
* Exit all the device threads
*/
private void quitThreads() {
logger.info("Exiting IPX800 threads");
for (Ipx800DeviceConnector device : devices.values()) {
device.interrupt();
}
devices.clear();
}
/**
* Start devices threads
*/
private void startThreads() {
for (Ipx800DeviceConfig config : Ipx800Config.INSTANCE.getDevices().values()) {
Ipx800DeviceConnector thread = new Ipx800DeviceConnector(config);
thread.start();
devices.put(config.name, thread);
}
}
/**
* Post the state of an item to the event bus
*
* @param item
*/
public void postUpdate(Ipx800Item item) {
if (item.getPort().getCommandType() == Ipx800PortType.OUPUT) {
eventPublisher.postUpdate(item.getItemName(), item.getState());
} else {
eventPublisher.postCommand(item.getItemName(), (Command) item.getState());
}
}
}