/**
* 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.onewire.internal;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Map;
import java.util.Objects;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.onewire.OneWireBindingProvider;
import org.openhab.binding.onewire.internal.connection.OneWireConnection;
import org.openhab.binding.onewire.internal.control.AbstractOneWireControlBindingConfig;
import org.openhab.binding.onewire.internal.deviceproperties.AbstractOneWireDevicePropertyBindingConfig;
import org.openhab.binding.onewire.internal.deviceproperties.AbstractOneWireDevicePropertyWritableBindingConfig;
import org.openhab.binding.onewire.internal.deviceproperties.OneWireDevicePropertyExecutableBindingConfig;
import org.openhab.binding.onewire.internal.listener.OneWireDevicePropertyWantsUpdateListener;
import org.openhab.binding.onewire.internal.listener.OneWireDevicePropertyWantsUpdateEvent;
import org.openhab.binding.onewire.internal.scheduler.OneWireUpdateScheduler;
import org.openhab.core.binding.AbstractBinding;
import org.openhab.core.binding.BindingConfig;
import org.openhab.core.binding.BindingProvider;
import org.openhab.core.items.Item;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.Type;
import org.openhab.core.types.UnDefType;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The 1-wire items / device properties are scheduled and refreshed via
* OneWireUpdateScheduler for this binding
*
* @author Thomas.Eichstaedt-Engelen, Dennis Riegelbauer
* @since 0.6.0
*/
public class OneWireBinding extends AbstractBinding<OneWireBindingProvider>
implements ManagedService, OneWireDevicePropertyWantsUpdateListener {
private static final Logger logger = LoggerFactory.getLogger(OneWireBinding.class);
/**
* Scheduler for items
*/
private OneWireUpdateScheduler ivOneWireReaderScheduler;
/**
* Use the Cache to post only changed values for items to the eventPublisher
*/
private boolean ivPostOnlyChangedValues = true;
/**
* Cache of item values
*/
private Hashtable<String, State> ivCacheItemStates = new Hashtable<String, State>();
public OneWireBinding() {
super();
ivOneWireReaderScheduler = new OneWireUpdateScheduler(this);
}
@Override
public void activate() {
super.activate();
ivOneWireReaderScheduler.start();
}
@Override
public void deactivate() {
super.deactivate();
ivOneWireReaderScheduler.stop();
}
protected void addBindingProvider(OneWireBindingProvider bindingProvider) {
super.addBindingProvider(bindingProvider);
}
protected void removeBindingProvider(OneWireBindingProvider bindingProvider) {
super.removeBindingProvider(bindingProvider);
}
/*
* (non-Javadoc)
*
* @see org.osgi.service.cm.ManagedService#updated(java.util.Dictionary)
*/
@Override
public void updated(Dictionary<String, ?> pvConfig) throws ConfigurationException {
if (pvConfig != null) {
// Basic config
String lvPostOnlyChangedValues = Objects.toString(pvConfig.get("post_only_changed_values"), null);
if (StringUtils.isNotBlank(lvPostOnlyChangedValues)) {
ivPostOnlyChangedValues = Boolean.getBoolean(lvPostOnlyChangedValues);
}
// Connection config
OneWireConnection.updated(pvConfig);
}
for (OneWireBindingProvider lvProvider : providers) {
scheduleAllBindings(lvProvider);
}
}
@Override
protected void internalReceiveCommand(String pvItemName, Command pvCommand) {
logger.debug("received command {} for item {}", pvCommand, pvItemName);
OneWireBindingConfig lvBindigConfig = getBindingConfig(pvItemName);
if (lvBindigConfig instanceof OneWireDevicePropertyExecutableBindingConfig) {
// This Binding implements a special behavior
logger.debug("call execute for item " + pvItemName);
((OneWireDevicePropertyExecutableBindingConfig) lvBindigConfig).execute(pvCommand);
} else if (lvBindigConfig instanceof AbstractOneWireDevicePropertyWritableBindingConfig) {
logger.debug("write to item " + pvItemName);
AbstractOneWireDevicePropertyWritableBindingConfig lvWritableBindingConfig = (AbstractOneWireDevicePropertyWritableBindingConfig) lvBindigConfig;
// Standard Write Operation
String lvStringValue = lvWritableBindingConfig.convertTypeToString(pvCommand);
OneWireConnection.writeToOneWire(lvWritableBindingConfig.getDevicePropertyPath(), lvStringValue);
} else if (lvBindigConfig instanceof AbstractOneWireControlBindingConfig) {
logger.debug("call executeControl for item " + pvItemName);
AbstractOneWireControlBindingConfig lvControlBindingConfig = (AbstractOneWireControlBindingConfig) lvBindigConfig;
lvControlBindingConfig.executeControl(this, pvCommand);
} else {
logger.debug("received command {} for item {} which is not writable or executable", pvCommand, pvItemName);
}
}
/*
* (non-Javadoc)
*
* @see
* org.openhab.core.binding.AbstractBinding#allBindingsChanged(org.openhab
* .core.binding.BindingProvider)
*/
@Override
public void allBindingsChanged(BindingProvider pvProvider) {
scheduleAllBindings(pvProvider);
}
/**
* schedule All Bindings to get updated
*
* @param pvProvider
*/
private void scheduleAllBindings(BindingProvider pvProvider) {
if (OneWireConnection.isConnectionEstablished()) {
logger.debug("scheduleAllBindings");
if (pvProvider instanceof OneWireBindingProvider) {
OneWireBindingProvider lvBindingProvider = (OneWireBindingProvider) pvProvider;
ivOneWireReaderScheduler.clear();
ivCacheItemStates.clear();
Map<String, BindingConfig> lvBindigConfigs = lvBindingProvider.getBindingConfigs();
for (String lvItemName : lvBindigConfigs.keySet()) {
logger.debug("scheduleAllBindings, now item {}.", lvItemName);
OneWireBindingConfig lvOneWireBindingConfig = (OneWireBindingConfig) lvBindigConfigs
.get(lvItemName);
if (lvOneWireBindingConfig instanceof AbstractOneWireDevicePropertyBindingConfig) {
logger.debug("Initializing read of item {}.", lvItemName);
AbstractOneWireDevicePropertyBindingConfig lvDevicePropertyBindingConfig = (AbstractOneWireDevicePropertyBindingConfig) lvOneWireBindingConfig;
if (lvDevicePropertyBindingConfig != null) {
int lvAutoRefreshTimeInSecs = lvDevicePropertyBindingConfig.getAutoRefreshInSecs();
if (lvAutoRefreshTimeInSecs > -1) {
ivOneWireReaderScheduler.updateOnce(lvItemName);
}
if (lvAutoRefreshTimeInSecs > 0) {
if (!ivOneWireReaderScheduler.scheduleUpdate(lvItemName, lvAutoRefreshTimeInSecs)) {
logger.warn("Couldn't add to OneWireUpdate scheduler",
lvDevicePropertyBindingConfig);
}
}
}
} else {
logger.debug("Didn't schedule item {} because it is not a DevicePropertyBinding.", lvItemName);
}
}
}
}
}
/*
* (non-Javadoc)
*
* @see
* org.openhab.core.binding.AbstractBinding#bindingChanged(org.openhab.core
* .binding.BindingProvider, java.lang.String)
*/
@Override
public void bindingChanged(BindingProvider pvProvider, String pvItemName) {
logger.debug("bindingChanged() for item {} msg received.", pvItemName);
if (pvProvider instanceof OneWireBindingProvider) {
ivCacheItemStates.remove(pvItemName);
OneWireBindingProvider lvBindingProvider = (OneWireBindingProvider) pvProvider;
OneWireBindingConfig lvBindingConfig = lvBindingProvider.getBindingConfig(pvItemName);
// Only for AbstractOneWireDevicePropertyBindingConfig, not for
// AbstractOneWireControlBindingConfigs
if (lvBindingConfig != null && lvBindingConfig instanceof AbstractOneWireDevicePropertyBindingConfig) {
AbstractOneWireDevicePropertyBindingConfig lvDeviceBindingConfig = (AbstractOneWireDevicePropertyBindingConfig) lvBindingConfig;
logger.debug("Initializing read of item {}.", pvItemName);
int lvAutoRefreshTimeInSecs = lvDeviceBindingConfig.getAutoRefreshInSecs();
if (lvAutoRefreshTimeInSecs > -1) {
ivOneWireReaderScheduler.updateOnce(pvItemName);
}
if (lvAutoRefreshTimeInSecs > 0) {
if (!ivOneWireReaderScheduler.scheduleUpdate(pvItemName, lvAutoRefreshTimeInSecs)) {
logger.warn("Couldn't add to OneWireUpdate scheduler", lvDeviceBindingConfig);
}
} else {
logger.debug("Didn't add to OneWireUpdate scheduler, because refresh is <= 0: {}",
lvDeviceBindingConfig);
}
}
}
}
/*
* (non-Javadoc)
*
* @see org.openhab.binding.onewire.internal.listener.
* InterfaceOneWireDevicePropertyWantsUpdateListener#
* devicePropertyWantsUpdate(org.openhab.binding.onewire.internal.listener.
* OneWireDevicePropertyWantsUpdateEvent)
*/
@Override
public void devicePropertyWantsUpdate(OneWireDevicePropertyWantsUpdateEvent pvWantsUpdateEvent) {
String lvItemName = pvWantsUpdateEvent.getItemName();
logger.debug("Item {} wants update!", lvItemName);
updateItemFromOneWire(lvItemName);
}
/**
*
* @param pvItemName
* @return the corresponding AbstractOneWireDevicePropertyBindingConfig to
* the given <code>pvItemName</code>
*/
private OneWireBindingConfig getBindingConfig(String pvItemName) {
for (OneWireBindingProvider lvProvider : providers) {
return lvProvider.getBindingConfig(pvItemName);
}
return null;
}
/**
*
* @param pvItemName
* @return the corresponding Item to the given <code>pvItemName</code>
*/
private Item getItem(String pvItemName) {
for (OneWireBindingProvider lvProvider : providers) {
return lvProvider.getItem(pvItemName);
}
return null;
}
/**
* Update an item with value from 1-wire device property
*
* @param pvItemName
*/
public void updateItemFromOneWire(String pvItemName) {
if (OneWireConnection.getConnection() != null) {
AbstractOneWireDevicePropertyBindingConfig pvBindingConfig = (AbstractOneWireDevicePropertyBindingConfig) getBindingConfig(
pvItemName);
if (pvBindingConfig == null) {
logger.error("no bindingConfig found for itemName={} cannot update! It will be removed from scheduler",
pvItemName);
ivOneWireReaderScheduler.removeItem(pvItemName);
return;
}
String lvReadValue = OneWireConnection.readFromOneWire(pvBindingConfig);
Item lvItem = getItem(pvItemName);
if (lvReadValue != null) {
Type lvNewType = pvBindingConfig.convertReadValueToType(lvReadValue);
if (lvItem != null) {
postUpdate(lvItem, lvNewType);
} else {
logger.error("There is no Item for ItemName={}", pvItemName);
}
} else {
String lvLogText = "Set Item for itemName=" + pvItemName
+ " to Undefined, because the readvalue is null";
if (pvBindingConfig.isIgnoreReadErrors()) {
logger.debug(lvLogText);
} else {
logger.error(lvLogText);
}
postUpdate(lvItem, UnDefType.UNDEF);
}
}
}
private void postUpdate(Item pvItem, Type pvNewType) {
synchronized (pvItem) {
State lvNewState = (State) pvNewType;
State lvCachedState = ivCacheItemStates.get(pvItem.getName());
if (!ivPostOnlyChangedValues || !lvNewState.equals(lvCachedState)) {
ivCacheItemStates.remove(pvItem.getName());
ivCacheItemStates.put(pvItem.getName(), lvNewState);
eventPublisher.postUpdate(pvItem.getName(), lvNewState);
} else {
logger.debug("didn't post update to eventPublisher, because state did not change for item {}",
pvItem.getName());
}
}
}
/**
* Clears the Cache for ItemStates
*/
public void clearCacheItemState() {
this.ivCacheItemStates.clear();
}
/**
* Clears the Cache for given Item
*/
public void clearCacheItemState(String pvItenName) {
this.ivCacheItemStates.remove(pvItenName);
}
}