/** * Copyright (c) 2017 by Kai Kreuzer and others. * 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.eclipse.smarthome.automation.module.core.handler; import java.util.Collections; import java.util.Dictionary; import java.util.HashSet; import java.util.Hashtable; import java.util.Map; import java.util.Set; import org.eclipse.smarthome.automation.Trigger; import org.eclipse.smarthome.automation.handler.BaseTriggerModuleHandler; import org.eclipse.smarthome.core.events.Event; import org.eclipse.smarthome.core.events.EventFilter; import org.eclipse.smarthome.core.events.EventSubscriber; import org.eclipse.smarthome.core.items.events.GroupItemStateChangedEvent; import org.eclipse.smarthome.core.items.events.ItemStateChangedEvent; import org.eclipse.smarthome.core.items.events.ItemStateEvent; import org.eclipse.smarthome.core.types.State; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Maps; /** * This is an ModuleHandler implementation for Triggers which trigger the rule * if an item state event occurs. The eventType and state value can be set with the * configuration. * * @author Kai Kreuzer - Initial contribution and API * @author Simon Merschjohann * */ public class ItemStateTriggerHandler extends BaseTriggerModuleHandler implements EventSubscriber, EventFilter { private final Logger logger = LoggerFactory.getLogger(ItemStateTriggerHandler.class); private String itemName; private String state; private String previousState; private Set<String> types; private BundleContext bundleContext; public static final String UPDATE_MODULE_TYPE_ID = "core.ItemStateUpdateTrigger"; public static final String CHANGE_MODULE_TYPE_ID = "core.ItemStateChangeTrigger"; private static final String CFG_ITEMNAME = "itemName"; private static final String CFG_STATE = "state"; private static final String CFG_PREVIOUS_STATE = "previousState"; @SuppressWarnings("rawtypes") private ServiceRegistration eventSubscriberRegistration; public ItemStateTriggerHandler(Trigger module, BundleContext bundleContext) { super(module); this.itemName = (String) module.getConfiguration().get(CFG_ITEMNAME); this.state = (String) module.getConfiguration().get(CFG_STATE); this.previousState = (String) module.getConfiguration().get(CFG_PREVIOUS_STATE); if (UPDATE_MODULE_TYPE_ID.equals(module.getTypeUID())) { this.types = Collections.singleton(ItemStateEvent.TYPE); } else { HashSet<String> set = new HashSet<>(); set.add(ItemStateChangedEvent.TYPE); set.add(GroupItemStateChangedEvent.TYPE); this.types = Collections.unmodifiableSet(set); } this.bundleContext = bundleContext; Dictionary<String, Object> properties = new Hashtable<String, Object>(); properties.put("event.topics", "smarthome/items/" + itemName + "/*"); eventSubscriberRegistration = this.bundleContext.registerService(EventSubscriber.class.getName(), this, properties); } @Override public Set<String> getSubscribedEventTypes() { return types; } @Override public EventFilter getEventFilter() { return this; } @Override public void receive(Event event) { if (ruleEngineCallback != null) { logger.trace("Received Event: Source: {} Topic: {} Type: {} Payload: {}", event.getSource(), event.getTopic(), event.getType(), event.getPayload()); Map<String, Object> values = Maps.newHashMap(); if (event instanceof ItemStateEvent && UPDATE_MODULE_TYPE_ID.equals(module.getTypeUID())) { State state = ((ItemStateEvent) event).getItemState(); if ((this.state == null || this.state.equals(state.toFullString()))) { values.put("state", state); } } else if (event instanceof ItemStateChangedEvent && CHANGE_MODULE_TYPE_ID.equals(module.getTypeUID())) { State state = ((ItemStateChangedEvent) event).getItemState(); State oldState = ((ItemStateChangedEvent) event).getOldItemState(); if (stateMatches(this.state, state) && stateMatches(this.previousState, oldState)) { values.put("oldState", oldState); values.put("newState", state); } } if (!values.isEmpty()) { values.put("event", event); ruleEngineCallback.triggered(this.module, values); } } } private boolean stateMatches(String requiredState, State state) { if (requiredState == null) { return true; } String reqState = requiredState.trim(); return reqState.isEmpty() || reqState.equals(state.toFullString()); } /** * do the cleanup: unregistering eventSubscriber... */ @Override public void dispose() { super.dispose(); if (eventSubscriberRegistration != null) { eventSubscriberRegistration.unregister(); eventSubscriberRegistration = null; } } @Override public boolean apply(Event event) { logger.trace("->FILTER: {}:{}", event.getTopic(), itemName); return event.getTopic().contains("/" + itemName + "/"); } }