/** * 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.sagercaster.internal; import static org.apache.commons.lang.StringUtils.isBlank; import java.util.Dictionary; import org.joda.time.DateTime; import org.joda.time.base.AbstractInstant; import org.openhab.binding.sagercaster.SagerCasterBindingConfig; import org.openhab.binding.sagercaster.SagerCasterBindingProvider; import org.openhab.core.binding.AbstractBinding; import org.openhab.core.items.Item; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.StringType; import org.openhab.core.persistence.HistoricItem; 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; /** * Sager Weather Caster Binding implementation * This binding monitor some input items evolutions and changes (sea level pressure, * wind bearing, cloud level, raining status, wind speed) in order to trigger * calculation of the Sager Caster Algorithm to generate weather forecasts. * * @author Gaël L'hopital * @since 1.7.0 */ public class SagerCasterBinding extends AbstractBinding<SagerCasterBindingProvider>implements ManagedService { private static final Logger logger = LoggerFactory.getLogger(SagerCasterBinding.class); private static SagerWeatherCaster sagerWeatherCaster = new SagerWeatherCaster(); static final String LATITUDE = "latitude"; static final String PERSISTENCE = "persistence"; private static String persistenceService = null; /** * 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) { sagerWeatherCaster = null; } private void postNewForecast(SagerCasterBindingProvider provider) { for (final String itemName : provider.getItemNamesBy(CommandType.FORECAST)) { eventPublisher.postUpdate(itemName, new StringType(sagerWeatherCaster.getForecast())); } for (final String itemName : provider.getItemNamesBy(CommandType.VELOCITY)) { eventPublisher.postUpdate(itemName, new StringType(sagerWeatherCaster.getWindVelocity())); } for (final String itemName : provider.getItemNamesBy(CommandType.WINDFROM)) { eventPublisher.postUpdate(itemName, new DecimalType(sagerWeatherCaster.getWindDirection())); } for (final String itemName : provider.getItemNamesBy(CommandType.WINDTO)) { eventPublisher.postUpdate(itemName, new DecimalType(sagerWeatherCaster.getWindDirection2())); } } protected HistoricItem getPreviousValue(Item theItem) { DateTime now = new DateTime(); AbstractInstant earlier = now.minusHours(6); if (persistenceService == null) { return PersistenceExtensions.historicState(theItem, earlier); } else { return PersistenceExtensions.historicState(theItem, earlier, persistenceService); } } @SuppressWarnings("incomplete-switch") @Override protected void internalReceiveCommand(String itemName, Command command) { logger.debug("internalReceiveCommand({},{}) is called!", itemName, command); for (SagerCasterBindingProvider provider : providers) { SagerCasterBindingConfig config = provider.getConfig(itemName); switch (config.commandType) { case CLOUDLEVEL: { logger.debug("Updated cloudlevel, updating forecast"); DecimalType newValue = (DecimalType) command; sagerWeatherCaster.setCloudLevel(newValue.doubleValue()); postNewForecast(provider); break; } case RAINING: { logger.debug("Updated rain status, updating forecast"); OnOffType newOnOffValue = (OnOffType) command; sagerWeatherCaster.setRaining(newOnOffValue.equals(OnOffType.ON)); postNewForecast(provider); break; } case SEALEVELPRESSURE: { logger.debug("Updated sea-level pressure, updating forecast"); DecimalType newValue = (DecimalType) command; HistoricItem historicItem = getPreviousValue(config.item); if (historicItem != null) { DecimalType previousValue = (DecimalType) historicItem.getState(); sagerWeatherCaster.setPressure(newValue.doubleValue(), previousValue.doubleValue()); State pressTrend = new DecimalType(sagerWeatherCaster.getPressureTrend()); for (final String pressureItems : provider.getItemNamesBy(CommandType.PRESSURETREND)) { eventPublisher.postUpdate(pressureItems, pressTrend); } postNewForecast(provider); } else { logger.warn("Not enough historic data to study pressure evolution, wait a bit ..."); } break; } case WINDBEARING: { // Bearing have changed, we can compute a // compass orientation logger.debug("Updated wind direction, updating forecast"); DecimalType newValue = (DecimalType) command; HistoricItem historicItem = getPreviousValue(config.item); if (historicItem != null) { DecimalType previousValue = (DecimalType) historicItem.getState(); sagerWeatherCaster.setBearing(newValue.intValue(), previousValue.intValue()); State compassState = new StringType(sagerWeatherCaster.getCompass()); for (final String compassItems : provider.getItemNamesBy(CommandType.COMPASS)) { eventPublisher.postUpdate(compassItems, compassState); } State windTrend = new DecimalType(sagerWeatherCaster.getWindEvolution()); for (final String windTrendItems : provider.getItemNamesBy(CommandType.WINDTREND)) { eventPublisher.postUpdate(windTrendItems, windTrend); } postNewForecast(provider); } else { logger.warn("Not enough historic data to study wind bearing evolution, wait a bit ..."); } break; } case WINDSPEED: { logger.debug("Updated wind speed, updating forecast"); DecimalType newValue = (DecimalType) command; sagerWeatherCaster.setBeaufort(newValue.intValue()); postNewForecast(provider); break; } } } } @Override public void updated(Dictionary<String, ?> properties) throws ConfigurationException { String latitude = (String) properties.get(LATITUDE); sagerWeatherCaster.setLatitude(Double.parseDouble(latitude)); String persistence = (String) properties.get(PERSISTENCE); if (!isBlank(persistence)) { persistenceService = persistence; } ; } }