Skip to content
This repository has been archived by the owner on May 7, 2020. It is now read-only.

Add LIFX Thing properties #3324

Merged
merged 1 commit into from May 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -59,13 +59,24 @@ public class LifxBindingConstants {
public static final ChannelTypeUID CHANNEL_TYPE_TEMPERATURE_ZONE = new ChannelTypeUID(BINDING_ID,
CHANNEL_TEMPERATURE_ZONE);

// config property for the LIFX device id
// Config property for the LIFX device id
public static final String CONFIG_PROPERTY_DEVICE_ID = "deviceId";
public static final String CONFIG_PROPERTY_FADETIME = "fadetime";

// config property for channel configuration
// Config property for channel configuration
public static final String CONFIG_PROPERTY_POWER_ON_BRIGHTNESS = "powerOnBrightness";

// Property keys
public static final String PROPERTY_HOST_VERSION = "hostVersion";
public static final String PROPERTY_MAC_ADDRESS = "macAddress";
public static final String PROPERTY_PRODUCT_ID = "productId";
public static final String PROPERTY_PRODUCT_NAME = "productName";
public static final String PROPERTY_PRODUCT_VERSION = "productVersion";
public static final String PROPERTY_VENDOR_ID = "vendorId";
public static final String PROPERTY_VENDOR_NAME = "vendorName";
public static final String PROPERTY_WIFI_VERSION = "wifiVersion";
public static final String PROPERTY_ZONES = "zones";

// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_COLORLIGHT = new ThingTypeUID(BINDING_ID, "colorlight");
public static final ThingTypeUID THING_TYPE_COLORIRLIGHT = new ThingTypeUID(BINDING_ID, "colorirlight");
Expand Down
Expand Up @@ -191,7 +191,7 @@ public void initialize() {
try {
lock.lock();

product = Products.getLikelyProduct(getThing().getThingTypeUID());
product = getProduct();
macAddress = new MACAddress((String) getConfig().get(LifxBindingConstants.CONFIG_PROPERTY_DEVICE_ID), true);
macAsHex = this.macAddress.getHex();

Expand Down Expand Up @@ -289,6 +289,16 @@ private PercentType getPowerOnBrightness() {
return powerOnBrightness == null ? null : new PercentType(powerOnBrightness.toString());
}

private Products getProduct() {
String propertyValue = getThing().getProperties().get(LifxBindingConstants.PROPERTY_PRODUCT_ID);
try {
long productID = Long.parseLong(propertyValue);
return Products.getProductFromProductID(productID);
} catch (IllegalArgumentException e) {
return Products.getLikelyProduct(getThing().getThingTypeUID());
}
}

private void addRemoveZoneChannels(int zones) {
List<Channel> newChannels = new ArrayList<Channel>();

Expand All @@ -307,6 +317,10 @@ private void addRemoveZoneChannels(int zones) {
}

updateThing(editThing().withChannels(newChannels).build());

Map<String, String> properties = editProperties();
properties.put(LifxBindingConstants.PROPERTY_ZONES, Integer.toString(zones));
updateProperties(properties);
}

private void sendPacket(Packet packet) {
Expand Down
Expand Up @@ -37,16 +37,21 @@
import org.apache.commons.lang.StringUtils;
import org.eclipse.smarthome.binding.lifx.LifxBindingConstants;
import org.eclipse.smarthome.binding.lifx.internal.fields.MACAddress;
import org.eclipse.smarthome.binding.lifx.internal.fields.Version;
import org.eclipse.smarthome.binding.lifx.internal.protocol.GetHostFirmwareRequest;
import org.eclipse.smarthome.binding.lifx.internal.protocol.GetLabelRequest;
import org.eclipse.smarthome.binding.lifx.internal.protocol.GetServiceRequest;
import org.eclipse.smarthome.binding.lifx.internal.protocol.GetVersionRequest;
import org.eclipse.smarthome.binding.lifx.internal.protocol.GetWifiFirmwareRequest;
import org.eclipse.smarthome.binding.lifx.internal.protocol.Packet;
import org.eclipse.smarthome.binding.lifx.internal.protocol.PacketFactory;
import org.eclipse.smarthome.binding.lifx.internal.protocol.PacketHandler;
import org.eclipse.smarthome.binding.lifx.internal.protocol.Products;
import org.eclipse.smarthome.binding.lifx.internal.protocol.StateHostFirmwareResponse;
import org.eclipse.smarthome.binding.lifx.internal.protocol.StateLabelResponse;
import org.eclipse.smarthome.binding.lifx.internal.protocol.StateServiceResponse;
import org.eclipse.smarthome.binding.lifx.internal.protocol.StateVersionResponse;
import org.eclipse.smarthome.binding.lifx.internal.protocol.StateWifiFirmwareResponse;
import org.eclipse.smarthome.config.discovery.AbstractDiscoveryService;
import org.eclipse.smarthome.config.discovery.DiscoveryResult;
import org.eclipse.smarthome.config.discovery.DiscoveryResultBuilder;
Expand All @@ -69,6 +74,8 @@ public class LifxLightDiscovery extends AbstractDiscoveryService {
private static final int SERVICE_REQUEST_SEQ_NO = 0;
private static final int VERSION_REQUEST_SEQ_NO = 1;
private static final int LABEL_REQUEST_SEQ_NO = 2;
private static final int HOST_VERSION_REQUEST_SEQ_NO = 3;
private static final int WIFI_VERSION_REQUEST_SEQ_NO = 4;

private List<InetSocketAddress> broadcastAddresses;
private List<InetAddress> interfaceAddresses;
Expand All @@ -93,7 +100,11 @@ private class DiscoveredLight {
private MACAddress macAddress;
private InetSocketAddress socketAddress;
private String label;
private Version hostVersion;
private Products products;
private long productVersion;
private boolean supportedProduct = true;
private Version wifiVersion;

private long lastRequestTimeMillis;

Expand All @@ -103,7 +114,7 @@ public DiscoveredLight(MACAddress macAddress, InetSocketAddress socketAddress) {
}

public boolean isDataComplete() {
return label != null && products != null;
return hostVersion != null && label != null && products != null && wifiVersion != null;
}

}
Expand Down Expand Up @@ -256,6 +267,17 @@ private void broadcastPacket(Packet packet, SelectionKey broadcastKey) {
}
}

private void sendLightDataRequestPacket(DiscoveredLight light, Packet packet, int sequenceNumber,
SelectionKey unicastKey) {
packet.setTarget(light.macAddress);
packet.setSequence(sequenceNumber);
packet.setSource(source);

LifxNetworkThrottler.lock(light.macAddress);
sendPacket(packet, light.socketAddress, unicastKey);
LifxNetworkThrottler.unlock(light.macAddress);
}

private boolean sendPacket(Packet packet, InetSocketAddress address, SelectionKey selectedKey) {

boolean result = false;
Expand Down Expand Up @@ -421,7 +443,7 @@ private void requestAdditionalLightData() throws IOException, ClosedChannelExcep

boolean waitingForLightResponse = System.currentTimeMillis() - light.lastRequestTimeMillis < 200;

if (!light.isDataComplete() && !waitingForLightResponse) {
if (light.supportedProduct && !light.isDataComplete() && !waitingForLightResponse) {
DatagramChannel unicastChannel = DatagramChannel.open(StandardProtocolFamily.INET)
.setOption(StandardSocketOptions.SO_REUSEADDR, true);
unicastChannel.configureBlocking(false);
Expand All @@ -431,25 +453,21 @@ private void requestAdditionalLightData() throws IOException, ClosedChannelExcep
logger.trace("Connected to a light via {}", unicastChannel.getLocalAddress().toString());

if (light.products == null) {
GetVersionRequest versionPacket = new GetVersionRequest();
versionPacket.setTarget(light.macAddress);
versionPacket.setSequence(VERSION_REQUEST_SEQ_NO);
versionPacket.setSource(source);

LifxNetworkThrottler.lock(light.macAddress);
sendPacket(versionPacket, light.socketAddress, unicastKey);
LifxNetworkThrottler.unlock(light.macAddress);
sendLightDataRequestPacket(light, new GetVersionRequest(), VERSION_REQUEST_SEQ_NO, unicastKey);
}

if (light.label == null) {
GetLabelRequest labelPacket = new GetLabelRequest();
labelPacket.setTarget(light.macAddress);
labelPacket.setSequence(LABEL_REQUEST_SEQ_NO);
labelPacket.setSource(source);

LifxNetworkThrottler.lock(light.macAddress);
sendPacket(labelPacket, light.socketAddress, unicastKey);
LifxNetworkThrottler.unlock(light.macAddress);
sendLightDataRequestPacket(light, new GetLabelRequest(), LABEL_REQUEST_SEQ_NO, unicastKey);
}

if (light.hostVersion == null) {
sendLightDataRequestPacket(light, new GetHostFirmwareRequest(), HOST_VERSION_REQUEST_SEQ_NO,
unicastKey);
}

if (light.wifiVersion == null) {
sendLightDataRequestPacket(light, new GetWifiFirmwareRequest(), WIFI_VERSION_REQUEST_SEQ_NO,
unicastKey);
}

light.lastRequestTimeMillis = System.currentTimeMillis();
Expand Down Expand Up @@ -484,7 +502,18 @@ private void handlePacket(Packet packet, InetSocketAddress address) {
} else if (packet instanceof StateLabelResponse) {
light.label = ((StateLabelResponse) packet).getLabel().trim();
} else if (packet instanceof StateVersionResponse) {
light.products = Products.getProductFromProductID(((StateVersionResponse) packet).getProduct());
try {
light.products = Products.getProductFromProductID(((StateVersionResponse) packet).getProduct());
light.productVersion = ((StateVersionResponse) packet).getVersion();
} catch (IllegalArgumentException e) {
logger.debug("Discovered an unsupported light ({}): {}", light.macAddress.getAsLabel(),
e.getMessage());
light.supportedProduct = false;
}
} else if (packet instanceof StateHostFirmwareResponse) {
light.hostVersion = ((StateHostFirmwareResponse) packet).getVersion();
} else if (packet instanceof StateWifiFirmwareResponse) {
light.wifiVersion = ((StateWifiFirmwareResponse) packet).getVersion();
}

if (light != null && light.isDataComplete()) {
Expand All @@ -509,9 +538,21 @@ private DiscoveryResult createDiscoveryResult(DiscoveredLight light) {

logger.trace("Discovered a LIFX light : {}", label);

return DiscoveryResultBuilder.create(thingUID).withLabel(label)
.withProperty(LifxBindingConstants.CONFIG_PROPERTY_DEVICE_ID, macAsLabel)
.withRepresentationProperty(macAsLabel).build();
DiscoveryResultBuilder builder = DiscoveryResultBuilder.create(thingUID);
builder.withRepresentationProperty(macAsLabel);
builder.withLabel(label);

builder.withProperty(LifxBindingConstants.CONFIG_PROPERTY_DEVICE_ID, macAsLabel);
builder.withProperty(LifxBindingConstants.PROPERTY_HOST_VERSION, light.hostVersion.toString());
builder.withProperty(LifxBindingConstants.PROPERTY_MAC_ADDRESS, macAsLabel);
builder.withProperty(LifxBindingConstants.PROPERTY_PRODUCT_ID, light.products.getProduct());
builder.withProperty(LifxBindingConstants.PROPERTY_PRODUCT_NAME, light.products.getName());
builder.withProperty(LifxBindingConstants.PROPERTY_PRODUCT_VERSION, light.productVersion);
builder.withProperty(LifxBindingConstants.PROPERTY_VENDOR_ID, light.products.getVendor());
builder.withProperty(LifxBindingConstants.PROPERTY_VENDOR_NAME, light.products.getVendorName());
builder.withProperty(LifxBindingConstants.PROPERTY_WIFI_VERSION, light.wifiVersion.toString());

return builder.build();
} catch (IllegalArgumentException e) {
logger.trace("Ignoring packet: {}", e);
return null;
Expand Down
@@ -0,0 +1,36 @@
/**
* 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.lifx.internal.fields;

/**
* @author Wouter Born - Add Thing properties
*/
public class Version {

private long major;
private long minor;

public Version(long major, long minor) {
this.major = major;
this.minor = minor;
}

public long getMajor() {
return major;
}

public long getMinor() {
return minor;
}

@Override
public String toString() {
return major + "." + minor;
}

}
@@ -0,0 +1,35 @@
/**
* 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.lifx.internal.fields;

import java.nio.ByteBuffer;

/**
* @author Wouter Born - Add Thing properties
*/
public class VersionField extends Field<Version> {

@Override
public int defaultLength() {
return 4;
}

@Override
public Version value(ByteBuffer bytes) {
long value = bytes.getInt() & 0xFFFFFFFFL;
long major = (value >> 16) & 0xFFL;
long minor = value & 0xFFL;
return new Version(major, minor);
}

@Override
public ByteBuffer bytesInternal(Version value) {
return ByteBuffer.allocate(4).putInt((int) (((value.getMajor() << 16) | value.getMinor()) & 0xFFFFFFFFL));
}

}

This file was deleted.

Expand Up @@ -49,13 +49,11 @@ private PacketFactory() {
register(GetLightInfraredRequest.class);
register(GetLightPowerRequest.class);
register(GetLocationRequest.class);
register(GetMeshFirmwareRequest.class);
register(GetPowerRequest.class);
register(GetRequest.class);
register(GetServiceRequest.class);
register(GetTagLabelsRequest.class);
register(GetTagsRequest.class);
register(GetTagsRequest.class);
register(GetVersionRequest.class);
register(GetWifiFirmwareRequest.class);
register(GetWifiInfoRequest.class);
Expand All @@ -75,7 +73,6 @@ private PacketFactory() {
register(StateLightInfraredResponse.class);
register(StateLightPowerResponse.class);
register(StateLocationResponse.class);
register(StateMeshFirmwareResponse.class);
register(StateMultiZoneResponse.class);
register(StatePowerResponse.class);
register(StateResponse.class);
Expand Down
Expand Up @@ -57,6 +57,10 @@ public long getVendor() {
return vendorID;
}

public String getVendorName() {
return vendorID == 1 ? "LIFX" : "Unknown";
}

public long getProduct() {
return productID;
}
Expand Down