/** * Copyright (c) 2014-2017 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.eclipse.smarthome.binding.hue.internal.discovery; import static org.eclipse.smarthome.binding.hue.HueBindingConstants.*; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.smarthome.binding.hue.handler.HueBridgeHandler; import org.eclipse.smarthome.binding.hue.handler.HueLightHandler; import org.eclipse.smarthome.binding.hue.handler.LightStatusListener; import org.eclipse.smarthome.binding.hue.internal.FullLight; import org.eclipse.smarthome.binding.hue.internal.HueBridge; import org.eclipse.smarthome.config.discovery.AbstractDiscoveryService; import org.eclipse.smarthome.config.discovery.DiscoveryResult; import org.eclipse.smarthome.config.discovery.DiscoveryResultBuilder; import org.eclipse.smarthome.core.thing.ThingTypeUID; import org.eclipse.smarthome.core.thing.ThingUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.ImmutableMap; /** * The {@link HueBridgeServiceTracker} tracks for hue lights which are connected * to a paired hue bridge. The default search time for hue is 60 seconds. * * @author Kai Kreuzer - Initial contribution * @author Andre Fuechsel - changed search timeout, changed discovery result creation to support generic thing types * @author Thomas Höfer - Added representation * @author Denis Dudnik - switched to internally integrated source of Jue library */ public class HueLightDiscoveryService extends AbstractDiscoveryService implements LightStatusListener { private final Logger logger = LoggerFactory.getLogger(HueLightDiscoveryService.class); private final static int SEARCH_TIME = 60; private final static String MODEL_ID = "modelId"; // @formatter:off private final static Map<String, String> TYPE_TO_ZIGBEE_ID_MAP = new ImmutableMap.Builder<String, String>() .put("on_off_light", "0000") .put("on_off_plug_in_unit", "0010") .put("dimmable_light", "0100") .put("dimmable_plug_in_unit", "0110") .put("color_light", "0200") .put("extended_color_light", "0210") .put("color_temperature_light", "0220") .build(); // @formatter:on private HueBridgeHandler hueBridgeHandler; public HueLightDiscoveryService(HueBridgeHandler hueBridgeHandler) { super(SEARCH_TIME); this.hueBridgeHandler = hueBridgeHandler; } public void activate() { hueBridgeHandler.registerLightStatusListener(this); } @Override public void deactivate() { removeOlderResults(new Date().getTime()); hueBridgeHandler.unregisterLightStatusListener(this); } @Override public Set<ThingTypeUID> getSupportedThingTypes() { return HueLightHandler.SUPPORTED_THING_TYPES; } @Override public void startScan() { List<FullLight> lights = hueBridgeHandler.getFullLights(); if (lights != null) { for (FullLight l : lights) { onLightAddedInternal(l); } } // search for unpaired lights hueBridgeHandler.startSearch(); } @Override protected synchronized void stopScan() { super.stopScan(); removeOlderResults(getTimestampOfLastScan()); } @Override public void onLightAdded(HueBridge bridge, FullLight light) { onLightAddedInternal(light); } private void onLightAddedInternal(FullLight light) { ThingUID thingUID = getThingUID(light); ThingTypeUID thingTypeUID = getThingTypeUID(light); String modelId = light.getModelID().replaceAll(HueLightHandler.NORMALIZE_ID_REGEX, "_"); if (thingUID != null && thingTypeUID != null) { ThingUID bridgeUID = hueBridgeHandler.getThing().getUID(); Map<String, Object> properties = new HashMap<>(1); properties.put(LIGHT_ID, light.getId()); properties.put(MODEL_ID, modelId); /* * TODO retrieve the light´s unique id (available since Hue bridge versions > 1.3) and set the mac address * as discovery result representation. For this purpose the jue library has to be modified. */ DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withThingType(thingTypeUID) .withProperties(properties).withBridge(bridgeUID).withLabel(light.getName()).build(); thingDiscovered(discoveryResult); } else { logger.debug("discovered unsupported light of type '{}' and model '{}' with id {}", light.getType(), modelId, light.getId()); } } @Override public void onLightRemoved(HueBridge bridge, FullLight light) { ThingUID thingUID = getThingUID(light); if (thingUID != null) { thingRemoved(thingUID); } } @Override public void onLightStateChanged(HueBridge bridge, FullLight light) { // nothing to do } private ThingUID getThingUID(FullLight light) { ThingUID bridgeUID = hueBridgeHandler.getThing().getUID(); ThingTypeUID thingTypeUID = getThingTypeUID(light); if (thingTypeUID != null && getSupportedThingTypes().contains(thingTypeUID)) { return new ThingUID(thingTypeUID, bridgeUID, light.getId()); } else { return null; } } private ThingTypeUID getThingTypeUID(FullLight light) { String thingTypeId = TYPE_TO_ZIGBEE_ID_MAP .get(light.getType().replaceAll(HueLightHandler.NORMALIZE_ID_REGEX, "_").toLowerCase()); return thingTypeId != null ? new ThingTypeUID(BINDING_ID, thingTypeId) : null; } }