/** * 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.rwesmarthome.internal; import java.util.HashMap; import java.util.Map; import java.util.regex.Pattern; import org.apache.commons.collections.map.MultiKeyMap; import org.apache.commons.lang.StringUtils; import org.openhab.binding.rwesmarthome.RWESmarthomeBindingProvider; import org.openhab.core.binding.BindingChangeListener; import org.openhab.core.binding.BindingConfig; import org.openhab.core.binding.BindingProvider; import org.openhab.core.items.Item; 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.StringItem; import org.openhab.core.library.items.SwitchItem; import org.openhab.model.item.binding.AbstractGenericBindingProvider; import org.openhab.model.item.binding.BindingConfigParseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class is responsible for parsing the binding configuration. * * Examples of valid item configurations (replace '2951a048-1d21-5caf-d866-b63bc00280f4' to your specific device id): * * Contact rweContact "Window livingroom [MAP(de.map):%s]" * <contact> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=contact"} * Number rweHumidity "Humidity livingroom [%.1f %%]" * <temperature> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=humidity"} * Number rweLuminance "Luminance corridor [%d %%]" * <slider> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=luminance"} * Number rweSettemp "Settemp living [%.1f °C]" * <temperature> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=settemperature"} * Number rweTemp "Temp living [%.1f °C]" * <temperature> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=temperature"} * Switch rweAlarm "Alarm corridor" <siren> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=alarm"} * Switch rweSettempOpMode "Settemp living auto" * <temperature> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=operationmodeauto"} * Switch rweSmokeDetector "Smokedetector corridor" * <fire> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=smokedetector"} * Switch rweSwitch "Light corridor" <switch> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=switch"} * Switch rweVariable "Variable TEST" <switch> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=variable"} * Rollershutter rweRollershutter "Rollershutter living [%d %%]" * <rollershutter> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=rollershutterinverted"} * Dimmer rweDimmer "Light [%d %%]" <slider> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=dimmer"} * Number rweEnergyConsumptionTotal "EnergyConsumption total [%.3f kWh]" * <energy> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=totalenergy"} * Number rweEnergyConsumptionMonthKWh "EnergyConsumption per month [%.3f kWh]" * <energy> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=energypermonthinkwh"} * Number rweEnergyConsumptionMonthEuro "EnergyConsumption per month [%.2f €]" * <energy> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=energypermonthineuro"} * Number rweEnergyConsumptionDayKWh "EnergyConsumption per day [%.3f kWh]" * <energy> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=energyperdayinkwh"} * Number rweEnergyConsumptionDayEuro "EnergyConsumption per day [%.2f €]" * <energy> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=energyperdayineuro"} * Number rwePowerConsumption "PowerConsumption [%.2f W]" * <energy> {rwe="id=2951a048-1d21-5caf-d866-b63bc00280f4,param=powerinwatt"} * * @author ollie-dev * @since 1.8.0 */ public class RWESmarthomeGenericBindingProvider extends AbstractGenericBindingProvider implements RWESmarthomeBindingProvider, BindingChangeListener { private static final Logger logger = LoggerFactory.getLogger(RWESmarthomeGenericBindingProvider.class); private Map<String, Item> items = new HashMap<String, Item>(); private RWESmarthomeContext context = RWESmarthomeContext.getInstance(); private Map<String, Item> itemMapById = new HashMap<String, Item>(); private MultiKeyMap itemMapByIdAndParam = new MultiKeyMap(); /** * {@inheritDoc} */ @Override public String getBindingType() { return context.getBindingType(); } /** * @{inheritDoc} */ @Override public void validateItemType(Item item, String bindingConfig) throws BindingConfigParseException { if (!(item instanceof ContactItem || item instanceof DimmerItem || item instanceof NumberItem || item instanceof RollershutterItem || item instanceof StringItem || item instanceof SwitchItem)) { logger.debug("item '" + item.getName() + "' is of type '" + item.getClass().getSimpleName() + "', only the following item types are allowed: " + "Contact, Dimmer, Number, Rollershutter, String, Switch - please check your *.items configuration"); throw new BindingConfigParseException("item '" + item.getName() + "' is of type '" + item.getClass().getSimpleName() + "', only the following item types are allowed: " + "Contact, Dimmer, Number, Rollershutter, String, Switch - please check your *.items configuration"); } } /** * {@inheritDoc} */ @Override public void processBindingConfiguration(String context, Item item, String bindingConfig) throws BindingConfigParseException { super.processBindingConfiguration(context, item, bindingConfig); RWESmarthomeBindingConfig config = new RWESmarthomeBindingConfig(); // parse config bindingConfig = StringUtils.trimToEmpty(bindingConfig); String[] configstrings = bindingConfig.split("[,]"); Pattern patternForId = Pattern.compile("^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$"); Pattern patternForParam = Pattern.compile( "^(temperature|humidity|settemperature|variable|contact|switch|operationmodeauto|luminance|smokedetector|dimmer|dimmerinverted|rollershutter|rollershutterinverted|alarm|totalenergy|energypermonthinkwh|energypermonthineuro|energyperdayinkwh|energyperdayineuro|powerinwatt)$"); for (String configstring : configstrings) { String[] configParts = StringUtils.trimToEmpty(configstring).split("[=]"); if (configParts.length != 2) { throw new BindingConfigParseException("Each entry must have a key and a value"); } String key = StringUtils.trim(configParts[0]); String value = StringUtils.trim(configParts[1]); // id if ("id".equalsIgnoreCase(key)) { if (!patternForId.matcher(value).matches()) { throw new BindingConfigParseException("id '" + value + "' is not a valid logicalDeviceId. Valid example: 12345a67-890b-1c23-de45-f67890123456"); } config.setDeviceId(value); // param } else if ("param".equalsIgnoreCase(key)) { if (!patternForParam.matcher(value).matches()) { throw new BindingConfigParseException( "Invalid configuration: 'param' must be one of the following: temperature|humidity|settemperature|variable|contact|switch|operationmodeauto|luminance|smokedetector|dimmer|dimmerinverted|rollershutter|rollershutterinverted|alarm|totalenergy|energypermonthinkwh|energypermonthineuro|energyperdayinkwh|energyperdayineuro|powerinwatt"); } config.setDeviceParam(value); // unknown configuration key } else { logger.warn("Invalid configuration key '%s' - only 'id' and 'param' are allowed!", key, value); throw new BindingConfigParseException("Invalid configuration key '" + key + "'"); } } if (config.getDeviceId() == null) { throw new BindingConfigParseException("Invalid configuration: id is missing!"); } if (config.getDeviceParam() == null) { throw new BindingConfigParseException("Invalid configuration: param is missing!"); } logger.info("Adding item {} with {}", item.getName(), config.toString()); items.put(item.getName(), item); itemMapById.put(config.getDeviceId(), item); itemMapByIdAndParam.put(config.getDeviceId(), config.getDeviceParam(), item); addBindingConfig(item, config); this.context.setBindingChanged(true); } /** * This is a helper class holding binding specific configuration details * * @author ollie-dev * @since 1.8.0 */ public class RWESmarthomeBindingConfig implements BindingConfig { private String deviceId = null; private String deviceParam = null; /** * Returns the id of the device. * * @return the device id */ public String getDeviceId() { return deviceId; } /** * Sets the id of the device. * * @param deviceId */ public void setDeviceId(String deviceId) { this.deviceId = deviceId; } /** * Returns the device parameter. * * @return device parameter */ public String getDeviceParam() { return deviceParam; } /** * Sets the device parameter. * * @param deviceParam */ public void setDeviceParam(String deviceParam) { this.deviceParam = deviceParam; } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { String configString = "RWESmarthomeBindingConfig [deviceId=" + deviceId + ", param=" + deviceParam + "]"; return configString; } } /* * (non-Javadoc) * * @see org.openhab.binding.rwesmarthome.RWESmarthomeBindingProvider#getItem(java.lang.String) */ @Override public Item getItem(String itemName) { return items.get(itemName); } /* * (non-Javadoc) * * @see org.openhab.binding.rwesmarthome.RWESmarthomeBindingProvider#getItemById(java.lang.String) */ @Override public String getItemNameById(String id) { Item item = itemMapById.get(id); if (item != null) { return item.getName(); } else { return null; } } /* * (non-Javadoc) * * @see org.openhab.binding.rwesmarthome.RWESmarthomeBindingProvider#getItemByIdAndParam(java.lang.String, * java.lang.String) */ @Override public String getItemNameByIdAndParam(String id, String param) { Item item = (Item) itemMapByIdAndParam.get(id, param); if (item != null) { return item.getName(); } else { return null; } } /* * (non-Javadoc) * * @see org.openhab.core.binding.BindingChangeListener#bindingChanged(org.openhab.core.binding.BindingProvider, * java.lang.String) */ @Override public void bindingChanged(BindingProvider provider, String itemName) { logger.debug("BINDING CHANGED! item='{}', provider='{}'", itemName, provider); context.setBindingChanged(true); } /* * (non-Javadoc) * * @see org.openhab.core.binding.BindingChangeListener#allBindingsChanged(org.openhab.core.binding.BindingProvider) */ @Override public void allBindingsChanged(BindingProvider provider) { logger.debug("ALL BINDINGS CHANGED! provider='{}'", provider); context.setBindingChanged(true); } /* * (non-Javadoc) * * @see org.openhab.binding.rwesmarthome.RWESmarthomeBindingProvider#getBindingFor(java.lang.String) */ @Override public RWESmarthomeBindingConfig getBindingConfigFor(String itemName) { return (RWESmarthomeBindingConfig) bindingConfigs.get(itemName); } }