/**
* 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.dmx.internal;
import org.openhab.binding.dmx.DmxBindingProvider;
import org.openhab.binding.dmx.DmxService;
import org.openhab.binding.dmx.DmxStatusUpdateListener;
import org.openhab.binding.dmx.internal.config.DmxColorItem;
import org.openhab.binding.dmx.internal.config.DmxDimmerItem;
import org.openhab.binding.dmx.internal.config.DmxItem;
import org.openhab.binding.dmx.internal.config.DmxSwitchItem;
import org.openhab.core.binding.BindingChangeListener;
import org.openhab.core.binding.BindingProvider;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.items.Item;
import org.openhab.core.library.items.ColorItem;
import org.openhab.core.library.items.DimmerItem;
import org.openhab.core.library.items.SwitchItem;
import org.openhab.core.types.State;
import org.openhab.model.item.binding.AbstractGenericBindingProvider;
import org.openhab.model.item.binding.BindingConfigParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* {@literal
*
* DMX Binding provider. The DMX binding currently supports the following item
* types: Switch, Dimmer and Color.
*
* The DMX binding configuration contains a channel configuration and 0 or more
* command configurations. It has the following structure:
*
* dmx="CHANNEL[<channel-config>], <OPENHAB-COMMAND>[<dmx-command>], <OPENHAB-COMMAND>[<dmx-command>], ..."
*
* Channel Configuration:
*
* There can be only one channel configuration structure per item and
* it contains the following structure:
*
* CHANNEL[<universe>:<channels>/<footprint>:<status-update-frequency>]
*
* <universe>: DMX universe id, should be 0 in most cases
* <channels>: csv list of DMX channel numbers. DMX commands are multiplied on the available channels.
* <channel-width>: optional width of the DMX channels on device (e.g 1 for switch, 3 for rgb, 4 for rgbw).
* When used, only a single channel may be specified in <channels>.
* <status-update-frequency> : optional delay in ms between status updates for continuously changing values.
* If omitted or a value < 100 is used, no status updates are sent.
*
*
* Command Configuration:
*
* The command configuration has the following structure:
*
* <OPENHAB-COMMAND>[<dmx-command>|<command-variables>|<command-variables|..]
*
* <OPENHAB-COMMAND> : openhab command to override, e.g. ON, OFF, INCREASE, DECREASE, ...
* <dmx-command> : dmx-command name, e.g. FADE
* <command-variables : repeatable command variable sections for use with the DMX command
*
* For the details on the different command structures, consult the corresponding classes like DmxFadeCommand.
*
* }
*
* @author Davy Vanherbergen
* @since 1.2.0
*/
public class DmxGenericBindingProvider extends AbstractGenericBindingProvider implements DmxBindingProvider {
private static final Logger logger = LoggerFactory.getLogger(DmxGenericBindingProvider.class);
private DmxService dmxService;
private EventPublisher eventPublisher;
/**
* {@inheritDoc}
*/
@Override
public String getBindingType() {
return "dmx";
}
/**
* {@inheritDoc}
*/
@Override
public void validateItemType(Item item, String bindingConfig) throws BindingConfigParseException {
if (!(item instanceof SwitchItem || item instanceof DimmerItem || item instanceof ColorItem)) {
throw new BindingConfigParseException("Item '" + item.getName() + "' is of type '"
+ item.getClass().getSimpleName() + "', which is not supported by the DMX Binding.");
}
}
/**
* {@inheritDoc}
*/
@Override
public void processBindingConfiguration(String context, Item item, String bindingConfig)
throws BindingConfigParseException {
if (dmxService == null) {
logger.error("DMX Service unavailable. Cannot process item configuration for {}", item.getName());
return;
}
super.processBindingConfiguration(context, item, bindingConfig);
String config = (bindingConfig == null) ? "" : bindingConfig.replaceAll(" ", "").toUpperCase();
logger.trace("Binding item: {} with configuration {}", item.getName(), config);
DmxItem itemBinding = null;
if (item instanceof ColorItem) {
itemBinding = new DmxColorItem(item.getName(), config, this);
} else if (item instanceof DimmerItem) {
itemBinding = new DmxDimmerItem(item.getName(), config, this);
} else if (item instanceof SwitchItem) {
itemBinding = new DmxSwitchItem(item.getName(), config, this);
} else {
throw new BindingConfigParseException("Unsupported item type " + item.getClass().getSimpleName());
}
if (itemBinding.isStatusListener()) {
final DmxStatusUpdateListener dmxStatusListener = itemBinding;
final String itemName = item.getName();
logger.trace("Registering status listener for item {} ", item.getName());
dmxService.registerStatusListener(dmxStatusListener);
// add binding change listener to clean up status listeners on item
// removal
addBindingChangeListener(new BindingChangeListener() {
@Override
public void bindingChanged(BindingProvider provider, String changedItemName) {
if (itemName.equals(changedItemName) && !provider.providesBindingFor(itemName)) {
logger.trace("Removing status listener for item {}", itemName);
dmxService.unregisterStatusListener(dmxStatusListener);
}
}
@Override
public void allBindingsChanged(BindingProvider provider) {
if (!provider.providesBindingFor(itemName)) {
logger.trace("Removing status listener for item {}", itemName);
dmxService.unregisterStatusListener(dmxStatusListener);
}
}
});
}
addBindingConfig(item, itemBinding);
}
/**
* {@inheritDoc}
*/
@Override
public DmxItem getBindingConfig(String itemName) {
return (DmxItem) bindingConfigs.get(itemName);
}
/**
* DmxService loaded via DS.
*/
public void setDmxService(DmxService dmxService) {
this.dmxService = dmxService;
}
/**
* DmxService unloaded via DS.
*/
public void unsetDmxService(DmxService dmxService) {
this.dmxService = null;
}
/**
* Event publisher loaded via DS.
*/
public void setEventPublisher(EventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
/**
* Event publisher unloaded via DS.
*/
public void unsetEventPublisher(EventPublisher eventPublisher) {
this.eventPublisher = null;
}
/**
* {@inheritDoc}
*/
@Override
public void postUpdate(String itemName, State state) {
if (eventPublisher != null) {
logger.trace("Sending status update to {} : {}", itemName, state);
eventPublisher.postUpdate(itemName, state);
} else {
logger.error("Could not send status update. Event Publisher is missing");
}
}
}