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

Commit

Permalink
Add LIFX Thing properties (#3324)
Browse files Browse the repository at this point in the history
Signed-off-by: Wouter Born <eclipse@maindrain.net>
  • Loading branch information
wborn authored and kaikreuzer committed May 5, 2017
1 parent be30103 commit f7155c4
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 231 deletions.
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

0 comments on commit f7155c4

Please sign in to comment.