/** * 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.sapp.internal; import java.math.MathContext; import java.math.RoundingMode; import java.util.Collection; import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.openhab.binding.sapp.SappBindingProvider; import org.openhab.binding.sapp.internal.configs.SappBindingConfigContactItem; import org.openhab.binding.sapp.internal.configs.SappBindingConfigDimmerItem; import org.openhab.binding.sapp.internal.configs.SappBindingConfigNumberItem; import org.openhab.binding.sapp.internal.configs.SappBindingConfigRollershutterItem; import org.openhab.binding.sapp.internal.configs.SappBindingConfigSwitchItem; import org.openhab.binding.sapp.internal.configs.SappBindingConfigUtils; import org.openhab.binding.sapp.internal.executer.SappCentralExecuter; import org.openhab.binding.sapp.internal.executer.SappCentralExecuter.PollingResult; import org.openhab.binding.sapp.internal.model.SappAddressDecimal; import org.openhab.binding.sapp.internal.model.SappAddressDimmer; import org.openhab.binding.sapp.internal.model.SappAddressOnOffControl; import org.openhab.binding.sapp.internal.model.SappAddressOnOffStatus; import org.openhab.binding.sapp.internal.model.SappAddressOpenClosedStatus; import org.openhab.binding.sapp.internal.model.SappAddressRollershutterControl; import org.openhab.binding.sapp.internal.model.SappAddressRollershutterStatus; import org.openhab.binding.sapp.internal.model.SappAddressType; import org.openhab.binding.sapp.internal.model.SappPnmas; import org.openhab.core.binding.AbstractActiveBinding; import org.openhab.core.binding.BindingProvider; import org.openhab.core.items.Item; import org.openhab.core.items.ItemNotFoundException; import org.openhab.core.items.ItemRegistry; import org.openhab.core.items.ItemRegistryChangeListener; import org.openhab.core.library.items.ContactItem; import org.openhab.core.library.items.DimmerItem; import org.openhab.core.library.items.NumberItem; import org.openhab.core.library.items.RollershutterItem; import org.openhab.core.library.items.SwitchItem; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.IncreaseDecreaseType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.OpenClosedType; import org.openhab.core.library.types.PercentType; import org.openhab.core.library.types.StopMoveType; import org.openhab.core.library.types.UpDownType; import org.openhab.core.types.Command; import org.openhab.core.types.State; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.github.paolodenti.jsapp.core.command.base.SappException; import com.github.paolodenti.jsapp.core.util.SappUtils; /** * Implement this class if you are going create an actively polling service like querying a Website/Device. * * @author Paolo Denti * @since 1.8.0 */ public class SappBinding extends AbstractActiveBinding<SappBindingProvider>implements ItemRegistryChangeListener { private static final Logger logger = LoggerFactory.getLogger(SappBinding.class); private static final String CONFIG_KEY_REFRESH = "refresh"; private static final String CONFIG_KEY_PNMAS_ENABLED = "pnmas.ids"; private static final String CONFIG_KEY_PNMAS_ID = "pnmas.%s.ip"; private static final String CONFIG_KEY_PNMAS_PORT = "pnmas.%s.port"; private static final String ALL_UPDATE_REQUEST_KEY = "*"; /** * the refresh interval which is used to poll values from the Sapp server (optional, defaults to 100ms) */ private long refreshInterval = 100; /** * the item registry */ protected ItemRegistry itemRegistry; /** * polling enabler; toggled by switch P type */ private boolean pollingEnabled = true; /** * Called by the SCR to activate the component with its configuration read from CAS * * @param bundleContext * BundleContext of the Bundle that defines this component * @param configuration * Configuration properties for this component obtained from the ConfigAdmin service */ public void activate(final BundleContext bundleContext, final Map<String, Object> configuration) { logger.debug("sapp activate called"); String refreshIntervalString = (String) configuration.get(CONFIG_KEY_REFRESH); if (StringUtils.isNotBlank(refreshIntervalString)) { refreshInterval = Long.parseLong(refreshIntervalString); logger.debug("set refresh interval: {}", refreshInterval); } SappBindingProvider provider = getFirstSappBindingProvider(); if (provider != null) { String pnmasEnabled = (String) configuration.get(CONFIG_KEY_PNMAS_ENABLED); if (pnmasEnabled != null) { String[] pnmasIds = pnmasEnabled.split(","); for (String pnmasId : pnmasIds) { logger.debug("loading info for pnmas {}", pnmasId); String ip = (String) configuration.get(String.format(CONFIG_KEY_PNMAS_ID, pnmasId)); if (ip == null) { logger.warn("ip not found for pnmas {}", pnmasId); continue; } int port; String portString = (String) configuration.get(String.format(CONFIG_KEY_PNMAS_PORT, pnmasId)); if (portString == null) { logger.warn("port not found for pnmas {}", pnmasId); continue; } else { try { port = Integer.parseInt(portString); } catch (NumberFormatException e) { logger.warn("bad port number for pnmas {}", pnmasId); continue; } } if (provider.getPnmasMap().containsKey(pnmasId)) { logger.warn("pnmas {} duplicated, skipping", pnmasId); continue; } provider.getPnmasMap().put(pnmasId, new SappPnmas(ip, port)); } for (String pnmasKey : provider.getPnmasMap().keySet()) { logger.debug("pnmas {} : {}:", pnmasKey, provider.getPnmasMap().get(pnmasKey)); } } } provider.getSappUpdatePendingRequests().replaceAllPendingUpdateRequests(ALL_UPDATE_REQUEST_KEY); setProperlyConfigured(true); } /** * Called by the SCR to deactivate the component when either the configuration is removed or mandatory references * are no longer satisfied or the component has simply been stopped. * * @param reason * Reason code for the deactivation:<br> * <ul> * <li>0 – Unspecified * <li>1 – The component was disabled * <li>2 – A reference became unsatisfied * <li>3 – A configuration was changed * <li>4 – A configuration was deleted * <li>5 – The component was disposed * <li>6 – The bundle was stopped * </ul> */ public void deactivate(final int reason) { logger.debug("sapp deactivate called"); } /** * @{inheritDoc */ @Override protected long getRefreshInterval() { return refreshInterval; } /** * @{inheritDoc */ @Override protected String getName() { return "Sapp Refresh Service"; } protected void addBindingProvider(SappBindingProvider bindingProvider) { super.addBindingProvider(bindingProvider); } protected void removeBindingProvider(SappBindingProvider bindingProvider) { super.removeBindingProvider(bindingProvider); } @Override public void allBindingsChanged(BindingProvider provider) { ((SappBindingProvider) provider).getSappUpdatePendingRequests() .replaceAllPendingUpdateRequests(ALL_UPDATE_REQUEST_KEY); } @Override public void bindingChanged(BindingProvider provider, String itemName) { ((SappBindingProvider) provider).getSappUpdatePendingRequests().addPendingUpdateRequest(itemName); } /** * Sets locally the item registry * * @param itemRegistry * the item registry */ public void setItemRegistry(ItemRegistry itemRegistry) { logger.debug("setting item registry"); this.itemRegistry = itemRegistry; this.itemRegistry.addItemRegistryChangeListener(this); } /** * Unsets locally the item registry * * @param itemRegistry * the item registry */ public void unsetItemRegistry(ItemRegistry itemRegistry) { logger.debug("unsetting item registry"); this.itemRegistry.removeItemRegistryChangeListener(this); this.itemRegistry = null; } /** * @{inheritDoc */ @Override protected void execute() { if (isProperlyConfigured()) { // wait until provider is properly configured and all items are loaded SappBindingProvider provider = getFirstSappBindingProvider(); if (provider != null) { if (provider.getSappUpdatePendingRequests().areUpdatePendingRequestsPresent()) { // reinit // items Set<String> toBeProcessed = provider.getSappUpdatePendingRequests() .getAndClearPendingUpdateRequests(); initializeAllItemsInProvider(provider, toBeProcessed); } else { if (!pollingEnabled) { return; } SappCentralExecuter sappCentralExecuter = SappCentralExecuter.getInstance(); for (String pnmasId : provider.getPnmasMap().keySet()) { // each pnmas SappPnmas pnmas = provider.getPnmasMap().get(pnmasId); try { PollingResult pollingResult = sappCentralExecuter.executePollingSappCommands(pnmas.getIp(), pnmas.getPort()); if (pollingResult.changedOutputs.size() != 0) { for (Byte outputAddress : pollingResult.changedOutputs.keySet()) { logger.debug("Output variation {} received, new value is {}", SappUtils.byteToUnsigned(outputAddress), pollingResult.changedOutputs.get(outputAddress)); provider.setOutputCachedValue(SappUtils.byteToUnsigned(outputAddress), pollingResult.changedOutputs.get(outputAddress).intValue()); updateState(pnmasId, SappAddressType.OUTPUT, SappUtils.byteToUnsigned(outputAddress), pollingResult.changedOutputs.get(outputAddress).intValue(), provider); } } if (pollingResult.changedInputs.size() != 0) { for (Byte inputAddress : pollingResult.changedInputs.keySet()) { logger.debug("Input variation {} received, new value is {}", SappUtils.byteToUnsigned(inputAddress), pollingResult.changedInputs.get(inputAddress)); provider.setInputCachedValue(SappUtils.byteToUnsigned(inputAddress), pollingResult.changedInputs.get(inputAddress).intValue()); updateState(pnmasId, SappAddressType.INPUT, SappUtils.byteToUnsigned(inputAddress), pollingResult.changedInputs.get(inputAddress).intValue(), provider); } } if (pollingResult.changedVirtuals.size() != 0) { for (Integer virtualAddress : pollingResult.changedVirtuals.keySet()) { logger.debug("Virtual variation {} received, new value is {}", virtualAddress, pollingResult.changedVirtuals.get(virtualAddress)); provider.setVirtualCachedValue(virtualAddress, pollingResult.changedVirtuals.get(virtualAddress).intValue()); updateState(pnmasId, SappAddressType.VIRTUAL, virtualAddress, pollingResult.changedVirtuals.get(virtualAddress).intValue(), provider); } } } catch (SappException e) { logger.error("polling failed on pnmas {}", pnmas); } } } } } } /** * @{inheritDoc */ @Override protected void internalReceiveCommand(String itemName, Command command) { // the code being executed when a command was sent on the openHAB // event bus goes here. This method is only called if one of the // BindingProviders provide a binding for the given 'itemName'. logger.debug("internalReceiveCommand({},{}) is called!", itemName, command); executeSappCommand(itemName, command); } /** * @{inheritDoc */ @Override protected void internalReceiveUpdate(String itemName, State newState) { // the code being executed when a state was sent on the openHAB // event bus goes here. This method is only called if one of the // BindingProviders provide a binding for the given 'itemName'. logger.debug("internalReceiveUpdate({},{}) is called!", itemName, newState); } /** * executes the real command on pnmas device */ private void executeSappCommand(String itemName, Command command) { SappBindingProvider provider = findFirstMatchingBindingProvider(itemName); if (provider == null) { logger.error("cannot find a provider, skipping command"); } try { Item item = itemRegistry.getItem(itemName); logger.debug("found item {}", item); if (item instanceof SwitchItem && !(item instanceof DimmerItem)) { SappBindingConfigSwitchItem sappBindingConfigSwitchItem = (SappBindingConfigSwitchItem) provider .getBindingConfig(itemName); logger.debug("found binding {}", sappBindingConfigSwitchItem); if (sappBindingConfigSwitchItem.isPollerSuspender()) { if (pollingEnabled) { // turning off polling pollingEnabled = false; updatePollingSwitchesState(provider); // force updates of polling switches because polling is // off } else { // turning on polling provider.getSappUpdatePendingRequests().replaceAllPendingUpdateRequests(ALL_UPDATE_REQUEST_KEY); pollingEnabled = true; } } else { SappAddressOnOffControl controlAddress = sappBindingConfigSwitchItem.getControl(); if (!provider.getPnmasMap().containsKey(controlAddress.getPnmasId())) { logger.error("bad pnmas id ({}) in binding ({}) ... skipping", controlAddress.getPnmasId(), sappBindingConfigSwitchItem); return; } try { if (command instanceof OnOffType) { switch (controlAddress.getAddressType()) { case VIRTUAL: { // mask bits on previous value int previousValue = getVirtualValue(provider, controlAddress.getPnmasId(), controlAddress.getAddress(), controlAddress.getSubAddress(), false); int newValue = SappBindingConfigUtils.maskWithSubAddressAndSet( controlAddress.getSubAddress(), command.equals(OnOffType.ON) ? controlAddress.getOnValue() : controlAddress.getOffValue(), previousValue); // update pnmas SappPnmas pnmas = provider.getPnmasMap().get(controlAddress.getPnmasId()); SappCentralExecuter sappCentralExecuter = SappCentralExecuter.getInstance(); sappCentralExecuter.executeSapp7DCommand(pnmas.getIp(), pnmas.getPort(), controlAddress.getAddress(), newValue); break; } default: logger.error("cannot run {} on type {}", command.getClass().getSimpleName(), controlAddress.getAddressType()); break; } } else { logger.error("command {} not applicable", command.getClass().getSimpleName()); } } catch (SappException e) { logger.error("could not run sappcommand", e); } } } else if (item instanceof NumberItem) { SappBindingConfigNumberItem sappBindingConfigNumberItem = (SappBindingConfigNumberItem) provider .getBindingConfig(itemName); logger.debug("found binding {}", sappBindingConfigNumberItem); SappAddressDecimal address = sappBindingConfigNumberItem.getStatus(); if (!provider.getPnmasMap().containsKey(address.getPnmasId())) { logger.error("bad pnmas id ({}) in binding ({}) ... skipping", address.getPnmasId(), sappBindingConfigNumberItem); return; } try { if (command instanceof DecimalType) { switch (address.getAddressType()) { case VIRTUAL: { // mask bits on previous value int previousValue = getVirtualValue(provider, address.getPnmasId(), address.getAddress(), address.getSubAddress(), false); int newValue = SappBindingConfigUtils.maskWithSubAddressAndSet(address.getSubAddress(), address.backScaledValue(((DecimalType) command).toBigDecimal()), previousValue); // update pnmas SappPnmas pnmas = provider.getPnmasMap().get(address.getPnmasId()); SappCentralExecuter sappCentralExecuter = SappCentralExecuter.getInstance(); sappCentralExecuter.executeSapp7DCommand(pnmas.getIp(), pnmas.getPort(), address.getAddress(), newValue); break; } default: logger.error("cannot run {} on type {}", command.getClass().getSimpleName(), address.getAddressType()); break; } } else { logger.error("command {} not applicable", command.getClass().getSimpleName()); } } catch (SappException e) { logger.error("could not run sappcommand", e); } } else if (item instanceof RollershutterItem) { SappBindingConfigRollershutterItem sappBindingConfigRollershutterItem = (SappBindingConfigRollershutterItem) provider .getBindingConfig(itemName); logger.debug("found binding {}", sappBindingConfigRollershutterItem); SappAddressRollershutterControl controlAddress = null; if (command instanceof UpDownType && ((UpDownType) command) == UpDownType.UP) { controlAddress = sappBindingConfigRollershutterItem.getUpControl(); } else if (command instanceof UpDownType && ((UpDownType) command) == UpDownType.DOWN) { controlAddress = sappBindingConfigRollershutterItem.getDownControl(); } else if (command instanceof StopMoveType && ((StopMoveType) command) == StopMoveType.STOP) { controlAddress = sappBindingConfigRollershutterItem.getStopControl(); } if (controlAddress != null) { if (!provider.getPnmasMap().containsKey(controlAddress.getPnmasId())) { logger.error("bad pnmas id ({}) in binding ({}) ... skipping", controlAddress.getPnmasId(), sappBindingConfigRollershutterItem); return; } try { switch (controlAddress.getAddressType()) { case VIRTUAL: { // mask bits on previous value int previousValue = getVirtualValue(provider, controlAddress.getPnmasId(), controlAddress.getAddress(), controlAddress.getSubAddress(), false); int newValue = SappBindingConfigUtils.maskWithSubAddressAndSet( controlAddress.getSubAddress(), controlAddress.getActivateValue(), previousValue); // update pnmas SappPnmas pnmas = provider.getPnmasMap().get(controlAddress.getPnmasId()); SappCentralExecuter sappCentralExecuter = SappCentralExecuter.getInstance(); sappCentralExecuter.executeSapp7DCommand(pnmas.getIp(), pnmas.getPort(), controlAddress.getAddress(), newValue); break; } default: logger.error("cannot run {} on type {}", command.getClass().getSimpleName(), controlAddress.getAddressType()); break; } } catch (SappException e) { logger.error("could not run sappcommand", e); } } else { logger.error("command {} not applicable", command.getClass().getSimpleName()); } } else if (item instanceof DimmerItem) { SappBindingConfigDimmerItem sappBindingConfigDimmerItem = (SappBindingConfigDimmerItem) provider .getBindingConfig(itemName); logger.debug("found binding {}", sappBindingConfigDimmerItem); SappAddressDimmer address = sappBindingConfigDimmerItem.getStatus(); if (!provider.getPnmasMap().containsKey(address.getPnmasId())) { logger.error("bad pnmas id ({}) in binding ({}) ... skipping", address.getPnmasId(), sappBindingConfigDimmerItem); return; } try { if (command instanceof OnOffType) { switch (address.getAddressType()) { case VIRTUAL: { // mask bits on previous value int previousValue = getVirtualValue(provider, address.getPnmasId(), address.getAddress(), address.getSubAddress(), false); int newValue = SappBindingConfigUtils.maskWithSubAddressAndSet( address.getSubAddress(), ((OnOffType) command) == OnOffType.ON ? address.getOriginalMaxScale() : address.getOriginalMinScale(), previousValue); // update pnmas SappPnmas pnmas = provider.getPnmasMap().get(address.getPnmasId()); SappCentralExecuter sappCentralExecuter = SappCentralExecuter.getInstance(); sappCentralExecuter.executeSapp7DCommand(pnmas.getIp(), pnmas.getPort(), address.getAddress(), newValue); break; } default: logger.error("cannot run {} on type {}", command.getClass().getSimpleName(), address.getAddressType()); break; } } else if (command instanceof IncreaseDecreaseType) { switch (address.getAddressType()) { case VIRTUAL: { // mask bits on previous value int previousValue = getVirtualValue(provider, address.getPnmasId(), address.getAddress(), address.getSubAddress(), false); int newValue = SappBindingConfigUtils.maskWithSubAddressAndSet(address.getSubAddress(), ((IncreaseDecreaseType) command) == IncreaseDecreaseType.INCREASE ? Math.min(previousValue + address.getIncrement(), address.getOriginalMaxScale()) : Math.max(previousValue - address.getIncrement(), address.getOriginalMinScale()), previousValue); // update pnmas SappPnmas pnmas = provider.getPnmasMap().get(address.getPnmasId()); SappCentralExecuter sappCentralExecuter = SappCentralExecuter.getInstance(); sappCentralExecuter.executeSapp7DCommand(pnmas.getIp(), pnmas.getPort(), address.getAddress(), newValue); break; } default: logger.error("cannot run {} on type {}", command.getClass().getSimpleName(), address.getAddressType()); break; } } else if (command instanceof PercentType) { switch (address.getAddressType()) { case VIRTUAL: { // mask bits on previous value int previousValue = getVirtualValue(provider, address.getPnmasId(), address.getAddress(), address.getSubAddress(), false); int newValue = SappBindingConfigUtils.maskWithSubAddressAndSet(address.getSubAddress(), address.backScaledValue(((PercentType) command).toBigDecimal()), previousValue); // update pnmas SappPnmas pnmas = provider.getPnmasMap().get(address.getPnmasId()); SappCentralExecuter sappCentralExecuter = SappCentralExecuter.getInstance(); sappCentralExecuter.executeSapp7DCommand(pnmas.getIp(), pnmas.getPort(), address.getAddress(), newValue); break; } default: logger.error("cannot run {} on type {}", command.getClass().getSimpleName(), address.getAddressType()); break; } } else { logger.error("command {} not applicable", command.getClass().getSimpleName()); } } catch (SappException e) { logger.error("could not run sappcommand", e); } } else { logger.error("unimplemented item type: {}", item.getClass().getSimpleName()); } } catch (ItemNotFoundException e) { logger.error("Item {} not found", itemName); } } /** * Find the first matching {@link ChannelBindingProvider} according to <code>itemName</code> * * @param itemName * * @return the matching binding provider or <code>null</code> if no binding provider could be found */ protected SappBindingProvider findFirstMatchingBindingProvider(String itemName) { for (SappBindingProvider provider : providers) { logger.debug("found provider: {}", provider.getClass()); if (!provider.providesBindingFor(itemName)) { continue; } return provider; } return null; } /** * initializes all items */ private void initializeAllItemsInProvider(SappBindingProvider provider, Set<String> toBeProcessed) { logger.debug("Updating item state for items {}", provider.getItemNames()); for (String itemName : provider.getItemNames()) { if (toBeProcessed.contains(ALL_UPDATE_REQUEST_KEY) || toBeProcessed.contains(itemName)) { queryAndSendActualState(provider, itemName); } } updatePollingSwitchesState(provider); } /** * reads state from device and updates item repository */ private void queryAndSendActualState(SappBindingProvider provider, String itemName) { logger.debug("querying and sending item {}", itemName); try { Item item = itemRegistry.getItem(itemName); if (item instanceof SwitchItem && !(item instanceof DimmerItem)) { SappBindingConfigSwitchItem sappBindingConfigSwitchItem = (SappBindingConfigSwitchItem) provider .getBindingConfig(itemName); SappAddressOnOffStatus statusAddress = sappBindingConfigSwitchItem.getStatus(); if (!sappBindingConfigSwitchItem.isPollerSuspender()) { updateOnOffItem(provider, statusAddress, itemName, item); } } else if (item instanceof ContactItem) { SappBindingConfigContactItem sappBindingConfigContactItem = (SappBindingConfigContactItem) provider .getBindingConfig(itemName); SappAddressOpenClosedStatus statusAddress = sappBindingConfigContactItem.getStatus(); updateOpenClosedItem(provider, statusAddress, itemName, item); } else if (item instanceof NumberItem) { SappBindingConfigNumberItem sappBindingConfigNumberItem = (SappBindingConfigNumberItem) provider .getBindingConfig(itemName); SappAddressDecimal statusAddress = sappBindingConfigNumberItem.getStatus(); updateDecimalItem(provider, statusAddress, itemName, item); } else if (item instanceof RollershutterItem) { SappBindingConfigRollershutterItem sappBindingConfigRollershutterItem = (SappBindingConfigRollershutterItem) provider .getBindingConfig(itemName); SappAddressRollershutterStatus statusAddress = sappBindingConfigRollershutterItem.getStatus(); updateRollershutterItem(provider, statusAddress, itemName, item); } else if (item instanceof DimmerItem) { SappBindingConfigDimmerItem sappBindingConfigDimmerItem = (SappBindingConfigDimmerItem) provider .getBindingConfig(itemName); SappAddressDimmer statusAddress = sappBindingConfigDimmerItem.getStatus(); updateDimmerItem(provider, statusAddress, itemName, item); } else { logger.error("unimplemented item type: {}", item.getClass().getSimpleName()); } } catch (ItemNotFoundException e) { logger.error("Item {} not found", itemName); } } /** * loads Sapp provider */ private SappBindingProvider getFirstSappBindingProvider() { for (SappBindingProvider provider : providers) { return provider; } return null; } /** * updates item repository for a single item */ private void updateState(String pnmasId, SappAddressType sappAddressType, int addressToUpdate, int newState, SappBindingProvider provider) { logger.debug("Updating {} {} with new value {}", sappAddressType, addressToUpdate, newState); for (String itemName : provider.getItemNames()) { try { Item item = itemRegistry.getItem(itemName); if (item instanceof SwitchItem && !(item instanceof DimmerItem)) { SappBindingConfigSwitchItem sappBindingConfigSwitchItem = (SappBindingConfigSwitchItem) provider .getBindingConfig(itemName); if (!sappBindingConfigSwitchItem.isPollerSuspender()) { SappAddressOnOffStatus statusAddress = sappBindingConfigSwitchItem.getStatus(); if (statusAddress.getAddressType() == sappAddressType && statusAddress.getPnmasId().equals(pnmasId) && addressToUpdate == statusAddress.getAddress()) { logger.debug("found binding to update {}", sappBindingConfigSwitchItem); int result = SappBindingConfigUtils.maskWithSubAddress(statusAddress.getSubAddress(), newState); State stateToSet = result == statusAddress.getOnValue() ? OnOffType.ON : OnOffType.OFF; if (!stateToSet.equals(item.getState())) { eventPublisher.postUpdate(itemName, stateToSet); } } } } else if (item instanceof ContactItem) { SappBindingConfigContactItem sappBindingConfigContactItem = (SappBindingConfigContactItem) provider .getBindingConfig(itemName); SappAddressOpenClosedStatus statusAddress = sappBindingConfigContactItem.getStatus(); if (statusAddress.getAddressType() == sappAddressType && statusAddress.getPnmasId().equals(pnmasId) && addressToUpdate == statusAddress.getAddress()) { logger.debug("found binding to update {}", sappBindingConfigContactItem); int result = SappBindingConfigUtils.maskWithSubAddress(statusAddress.getSubAddress(), newState); State stateToSet = result == statusAddress.getOpenValue() ? OpenClosedType.OPEN : OpenClosedType.CLOSED; if (!stateToSet.equals(item.getState())) { eventPublisher.postUpdate(itemName, stateToSet); } } } else if (item instanceof NumberItem) { SappBindingConfigNumberItem sappBindingConfigNumberItem = (SappBindingConfigNumberItem) provider .getBindingConfig(itemName); SappAddressDecimal address = sappBindingConfigNumberItem.getStatus(); if (address.getAddressType() == sappAddressType && address.getPnmasId().equals(pnmasId) && addressToUpdate == address.getAddress()) { logger.debug("found binding to update {}", sappBindingConfigNumberItem); int result = SappBindingConfigUtils.maskWithSubAddress(address.getSubAddress(), newState); State stateToSet = new DecimalType(address.scaledValue(result, address.getSubAddress())); if (!stateToSet.equals(item.getState())) { eventPublisher.postUpdate(itemName, stateToSet); } } } else if (item instanceof RollershutterItem) { SappBindingConfigRollershutterItem sappBindingConfigRollershutterItem = (SappBindingConfigRollershutterItem) provider .getBindingConfig(itemName); SappAddressRollershutterStatus statusAddress = sappBindingConfigRollershutterItem.getStatus(); if (statusAddress.getAddressType() == sappAddressType && statusAddress.getPnmasId().equals(pnmasId) && addressToUpdate == statusAddress.getAddress()) { logger.debug("found binding to update {}", sappBindingConfigRollershutterItem); int result = SappBindingConfigUtils.maskWithSubAddress(statusAddress.getSubAddress(), newState); State stateToSet = result == statusAddress.getOpenValue() ? PercentType.HUNDRED : (result == statusAddress.getClosedValue() ? PercentType.ZERO : PercentType.valueOf("50")); if (!stateToSet.equals(item.getState())) { eventPublisher.postUpdate(itemName, stateToSet); } } } else if (item instanceof DimmerItem) { SappBindingConfigDimmerItem sappBindingConfigDimmerItem = (SappBindingConfigDimmerItem) provider .getBindingConfig(itemName); SappAddressDimmer statusAddress = sappBindingConfigDimmerItem.getStatus(); if (statusAddress.getAddressType() == sappAddressType && statusAddress.getPnmasId().equals(pnmasId) && addressToUpdate == statusAddress.getAddress()) { logger.debug("found binding to update {}", sappBindingConfigDimmerItem); int result = statusAddress .scaledValue(SappBindingConfigUtils.maskWithSubAddress(statusAddress.getSubAddress(), newState), statusAddress.getSubAddress()) .round(new MathContext(0, RoundingMode.HALF_EVEN)).intValue(); State stateToSet; if (result <= PercentType.ZERO.intValue()) { stateToSet = PercentType.ZERO; } else if (result >= PercentType.HUNDRED.intValue()) { stateToSet = PercentType.HUNDRED; } else { stateToSet = PercentType.valueOf(String.valueOf(result)); } if (!stateToSet.equals(item.getState())) { eventPublisher.postUpdate(itemName, stateToSet); } } } else { logger.error("unimplemented item type: {}", item.getClass().getSimpleName()); } } catch (ItemNotFoundException e) { logger.error("Item {} not found", itemName); } } } /** * updates item repository for special polling switches */ private void updatePollingSwitchesState(SappBindingProvider provider) { logger.debug("Updating poller switch states"); for (String itemName : provider.getItemNames()) { try { Item item = itemRegistry.getItem(itemName); if (item instanceof SwitchItem && !(item instanceof DimmerItem)) { SappBindingConfigSwitchItem sappBindingConfigSwitchItem = (SappBindingConfigSwitchItem) provider .getBindingConfig(itemName); if (sappBindingConfigSwitchItem.isPollerSuspender()) { eventPublisher.postUpdate(itemName, pollingEnabled ? OnOffType.ON : OnOffType.OFF); } } } catch (ItemNotFoundException e) { logger.error("Item {} not found", itemName); } } } /** * updates item repository for OnOff items */ private void updateOnOffItem(SappBindingProvider provider, SappAddressOnOffStatus statusAddress, String itemName, Item item) { switch (statusAddress.getAddressType()) { case VIRTUAL: try { int result = SappBindingConfigUtils.maskWithSubAddress(statusAddress.getSubAddress(), getVirtualValue(provider, statusAddress.getPnmasId(), statusAddress.getAddress(), statusAddress.getSubAddress(), true)); eventPublisher.postUpdate(itemName, result == statusAddress.getOnValue() ? OnOffType.ON : OnOffType.OFF); } catch (SappException e) { logger.error("could not run sappcommand", e); } break; case INPUT: try { int result = SappBindingConfigUtils.maskWithSubAddress(statusAddress.getSubAddress(), getInputValue(provider, statusAddress.getPnmasId(), statusAddress.getAddress(), statusAddress.getSubAddress(), true)); eventPublisher.postUpdate(itemName, result == statusAddress.getOnValue() ? OnOffType.ON : OnOffType.OFF); } catch (SappException e) { logger.error("could not run sappcommand", e); } break; case OUTPUT: try { int result = SappBindingConfigUtils.maskWithSubAddress(statusAddress.getSubAddress(), getOutputValue(provider, statusAddress.getPnmasId(), statusAddress.getAddress(), statusAddress.getSubAddress(), true)); eventPublisher.postUpdate(itemName, result == statusAddress.getOnValue() ? OnOffType.ON : OnOffType.OFF); } catch (SappException e) { logger.error("could not run sappcommand", e); } break; default: logger.error("item type not yet implemented {} for address type {}", item.getClass().getSimpleName(), statusAddress.getAddressType()); break; } } /** * updates item repository for OpenClosed items */ private void updateOpenClosedItem(SappBindingProvider provider, SappAddressOpenClosedStatus statusAddress, String itemName, Item item) { switch (statusAddress.getAddressType()) { case VIRTUAL: try { int result = SappBindingConfigUtils.maskWithSubAddress(statusAddress.getSubAddress(), getVirtualValue(provider, statusAddress.getPnmasId(), statusAddress.getAddress(), statusAddress.getSubAddress(), true)); eventPublisher.postUpdate(itemName, result == statusAddress.getOpenValue() ? OpenClosedType.OPEN : OpenClosedType.CLOSED); } catch (SappException e) { logger.error("could not run sappcommand", e); } break; case INPUT: try { int result = SappBindingConfigUtils.maskWithSubAddress(statusAddress.getSubAddress(), getInputValue(provider, statusAddress.getPnmasId(), statusAddress.getAddress(), statusAddress.getSubAddress(), true)); eventPublisher.postUpdate(itemName, result == statusAddress.getOpenValue() ? OpenClosedType.OPEN : OpenClosedType.CLOSED); } catch (SappException e) { logger.error("could not run sappcommand", e); } break; case OUTPUT: try { int result = SappBindingConfigUtils.maskWithSubAddress(statusAddress.getSubAddress(), getOutputValue(provider, statusAddress.getPnmasId(), statusAddress.getAddress(), statusAddress.getSubAddress(), true)); eventPublisher.postUpdate(itemName, result == statusAddress.getOpenValue() ? OpenClosedType.OPEN : OpenClosedType.CLOSED); } catch (SappException e) { logger.error("could not run sappcommand", e); } break; default: logger.error("item type not yet implemented {} for address type {}", item.getClass().getSimpleName(), statusAddress.getAddressType()); break; } } /** * updates item repository for Decimal items */ private void updateDecimalItem(SappBindingProvider provider, SappAddressDecimal address, String itemName, Item item) { switch (address.getAddressType()) { case VIRTUAL: try { int result = SappBindingConfigUtils.maskWithSubAddress(address.getSubAddress(), getVirtualValue( provider, address.getPnmasId(), address.getAddress(), address.getSubAddress(), true)); eventPublisher.postUpdate(itemName, new DecimalType(address.scaledValue(result, address.getSubAddress()))); } catch (SappException e) { logger.error("could not run sappcommand", e); } break; case INPUT: try { int result = SappBindingConfigUtils.maskWithSubAddress(address.getSubAddress(), getInputValue( provider, address.getPnmasId(), address.getAddress(), address.getSubAddress(), true)); eventPublisher.postUpdate(itemName, new DecimalType(address.scaledValue(result, address.getSubAddress()))); } catch (SappException e) { logger.error("could not run sappcommand", e); } break; case OUTPUT: try { int result = SappBindingConfigUtils.maskWithSubAddress(address.getSubAddress(), getOutputValue( provider, address.getPnmasId(), address.getAddress(), address.getSubAddress(), true)); eventPublisher.postUpdate(itemName, new DecimalType(address.scaledValue(result, address.getSubAddress()))); } catch (SappException e) { logger.error("could not run sappcommand: " + e.getMessage()); } break; default: logger.error("item type not yet implemented {} for address type {}", item.getClass().getSimpleName(), address.getAddressType()); break; } } /** * updates item repository for Rollershutter items */ private void updateRollershutterItem(SappBindingProvider provider, SappAddressRollershutterStatus statusAddress, String itemName, Item item) { switch (statusAddress.getAddressType()) { case VIRTUAL: try { int result = SappBindingConfigUtils.maskWithSubAddress(statusAddress.getSubAddress(), getVirtualValue(provider, statusAddress.getPnmasId(), statusAddress.getAddress(), statusAddress.getSubAddress(), true)); eventPublisher.postUpdate(itemName, result == statusAddress.getOpenValue() ? PercentType.HUNDRED : (result == statusAddress.getClosedValue() ? PercentType.ZERO : PercentType.valueOf("50"))); } catch (SappException e) { logger.error("could not run sappcommand", e); } break; case INPUT: logger.error("item type not yet implemented {} for address type {}", item.getClass().getSimpleName(), statusAddress.getAddressType()); break; case OUTPUT: logger.error("item type not yet implemented {} for address type {}", item.getClass().getSimpleName(), statusAddress.getAddressType()); break; default: logger.error("item type not yet implemented {} for address type {}", item.getClass().getSimpleName(), statusAddress.getAddressType()); break; } } /** * updates item repository for Dimmer items */ private void updateDimmerItem(SappBindingProvider provider, SappAddressDimmer statusAddress, String itemName, Item item) { switch (statusAddress.getAddressType()) { case VIRTUAL: try { int result = statusAddress .scaledValue( SappBindingConfigUtils.maskWithSubAddress(statusAddress.getSubAddress(), getVirtualValue(provider, statusAddress.getPnmasId(), statusAddress.getAddress(), statusAddress.getSubAddress(), true)), statusAddress.getSubAddress()).round(new MathContext(0, RoundingMode.HALF_EVEN)).intValue(); if (result <= PercentType.ZERO.intValue()) { eventPublisher.postUpdate(itemName, PercentType.ZERO); } else if (result >= PercentType.HUNDRED.intValue()) { eventPublisher.postUpdate(itemName, PercentType.HUNDRED); } else { eventPublisher.postUpdate(itemName, PercentType.valueOf(String.valueOf(result))); } } catch (SappException e) { logger.error("could not run sappcommand", e); } break; case INPUT: logger.error("item type not yet implemented {} for address type {}", item.getClass().getSimpleName(), statusAddress.getAddressType()); break; case OUTPUT: logger.error("item type not yet implemented {} for address type {}", item.getClass().getSimpleName(), statusAddress.getAddressType()); break; default: logger.error("item type not yet implemented {} for address type {}", item.getClass().getSimpleName(), statusAddress.getAddressType()); break; } } /** * load virtual value from pnmas, if not cached, and caches it */ private int getVirtualValue(SappBindingProvider provider, String pnmasId, int address, String subAddress, boolean forceReload) throws SappException { Integer value = provider.getVirtualCachedValue(address); if (forceReload || value == null) { logger.debug("cached value missing, reloading for [{} {} {}]", pnmasId, address, subAddress); SappPnmas pnmas = provider.getPnmasMap().get(pnmasId); SappCentralExecuter sappCentralExecuter = SappCentralExecuter.getInstance(); value = sappCentralExecuter.executeSapp7CCommand(pnmas.getIp(), pnmas.getPort(), address); provider.setVirtualCachedValue(address, value); } return value.intValue(); } /** * load input value from pnmas, if not cached, and caches it */ private int getInputValue(SappBindingProvider provider, String pnmasId, int address, String subAddress, boolean forceReload) throws SappException { Integer value = provider.getInputCachedValue(address); if (forceReload || value == null) { logger.debug("cached value missing, reloading for [{} {} {}]", pnmasId, address, subAddress); SappPnmas pnmas = provider.getPnmasMap().get(pnmasId); SappCentralExecuter sappCentralExecuter = SappCentralExecuter.getInstance(); value = sappCentralExecuter.executeSapp74Command(pnmas.getIp(), pnmas.getPort(), (byte) address); provider.setInputCachedValue(address, value); } return value.intValue(); } /** * load output value from pnmas, if not cached, and caches it */ private int getOutputValue(SappBindingProvider provider, String pnmasId, int address, String subAddress, boolean forceReload) throws SappException { Integer value = provider.getOutputCachedValue(address); if (forceReload || value == null) { logger.debug("cached value missing, reloading for [{} {} {}]", pnmasId, address, subAddress); SappPnmas pnmas = provider.getPnmasMap().get(pnmasId); SappCentralExecuter sappCentralExecuter = SappCentralExecuter.getInstance(); value = sappCentralExecuter.executeSapp75Command(pnmas.getIp(), pnmas.getPort(), (byte) address); provider.setOutputCachedValue(address, value); } return value.intValue(); } @Override public void allItemsChanged(Collection<String> oldItemNames) { SappBindingProvider provider = getFirstSappBindingProvider(); provider.getSappUpdatePendingRequests().replaceAllPendingUpdateRequests(ALL_UPDATE_REQUEST_KEY); } @Override public void itemAdded(Item item) { } @Override public void itemRemoved(Item item) { } }