LIFX Developer Zone

LIFX Discovery Only Works from Some Clients

I am currently writing a C++ program to control some of my LIFX bulbs. I have the program broadcasting the proper UDP packet to the network to discover the bulbs, and when I run this program from my laptop everything works as expected and the bulbs respond. However when I run this program from a Ubuntu machine I have attached to the network I see the packet being sent but none of the lights will respond.

Does anyone have any idea why this might be? The payload for each of the packets is identical. I have attached some screenshots from Wireshark:

No response:

Well that’s bizarre! I assume your ubuntu computer is on the same network.

I know that in photons I need to do this in Windows https://github.com/delfick/photons-core/blob/master/photons_transport/transports/udp.py#L44 but it seems if I have that line on Ubuntu, it still works.

Is your code online somewhere?

The linux machine is on the same network, and if I send a command to turn on/off a light or something like that, then the light will work as expected. However if I request an acknowledgement for the command I will only receive something if it is sent from my laptop.

I don’t have my code hosted online currently, but I posted the relevant bit below. The establishConnection() section is where I am generating the message to discover devices.

Thanks!!

#include "LIFXLight.h"
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <iostream>
#include <cerrno>
#include <stdio.h>

using namespace std;

LIFXLight::LIFXLight() {

}

int LIFXLight::sendUDPMessage(uint8_t* message, size_t length) {
	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

	if (sockfd < 0) {
		return -1; // Failed to create the socket
	}

	int broadcast = 1;
	int operationStatus = 0;

	operationStatus = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast));

	if (operationStatus < 0) {
		//printf("%s\n", sterror(errno));
		close(sockfd);
		return -2; // Failed to set SO_BROADCAST option
	}

	struct sockaddr_in servaddr;
	memset(&servaddr, 0, sizeof(servaddr)); // Zero data structure

	servaddr.sin_family = AF_INET;
	inet_aton("10.0.1.255", &servaddr.sin_addr);
	servaddr.sin_port = htons(56700);

	operationStatus = sendto(sockfd, message, length, 0, (const struct sockaddr *) &servaddr, sizeof(servaddr));

	if (operationStatus < 0) {
		//printf("%s\n", strerror(errno));
		close(sockfd);
		return -3; // Failed to send data
	}

	close(sockfd);
	return 0;
}

uint8_t* LIFXLight::generateMessage(LIFXMessageData data, uint8_t* payload, size_t payloadSize, size_t* bufSize) {
	uint16_t messageSize = 36 + payloadSize;
	uint8_t* buf = (uint8_t*) calloc(messageSize, 1);

	if (buf == NULL) {
		return 0;
	}

	buf[0] = (uint8_t) messageSize;
	buf[1] = (uint8_t) (messageSize >> 8);
	buf[3] = 0b00010100 | (data.tagged << 5);
	buf[4] = (uint8_t) (data.source);
	buf[5] = (uint8_t) (data.source >> 8);
	buf[6] = (uint8_t) (data.source >> 16);
	buf[7] = (uint8_t) (data.source >> 24);

	memcpy(&buf[8], data.target, 6);

	buf[22] = (data.ack_required << 1) | (data.res_required);
	buf[23] = data.sequence;
	buf[32] = (uint8_t) data.type;
	buf[33] = (uint8_t) (data.type >> 8);

	memcpy(&buf[36], payload, payloadSize);

	*bufSize = messageSize;

	return buf;
}

int establishConnection() {
	LIFXMessageData data = {
		.tagged = 1,
		.source = 1,
		.target = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
		.res_required = 0,
		.ack_required = 0,
		.sequence = 0,
		.type = 2
	};

	size_t bufSize;
	uint8_t *buf = generateMessage(data, NULL, 0, &bufSize);

	for (unsigned int i = 0; i < bufSize; i++) {
		printf("%02x ", buf[i]);
	}
	printf("\n");

	int result = sendUDPMessage(buf, bufSize);
	free(buf);
	return result;
}


int LIFXLight::turnOff() {
	LIFXMessageData data = {
		.tagged = 0,
		.source = 4,
		.target = {0xD0, 0x73, 0xD5, 0x31, 0x3C, 0x89},
		.res_required = 0,
		.ack_required = 0,
		.sequence = 0,
		.type = 21
	};

	size_t bufSize;
	uint8_t payload[] = {0x00, 0x00};
	uint8_t *buf = generateMessage(data, payload, sizeof(payload), &bufSize);

	int result =  sendUDPMessage(buf, bufSize);
	free(buf);
	return result;
}

int LIFXLight::turnOn() {
	LIFXMessageData data = {
		.tagged = 0,
		.source = 4,
		.target = {0xD0, 0x73, 0xD5, 0x31, 0x3C, 0x89},
		.res_required = 0,
		.ack_required = 0,
		.sequence = 0,
		.type = 21
	};

	size_t bufSize;
	uint8_t payload[] = {0xFF, 0xFF};
	uint8_t *buf = generateMessage(data, payload, sizeof(payload), &bufSize);

	int result = sendUDPMessage(buf, bufSize);
	free(buf);
	return result;
}

I have a theory, but I’m not sure if it’s what’s happening.

If you use a different source value from the two computers (so from windows, source=1 and from ubuntu source=2), does it work?

I gave it a try and it didn’t seem to fix the problem. I have noticed that when I send the message from the Ubuntu machine the lights are sending out multiple ARP messages that aren’t getting answered:

for a sanity check, can we see if photons works on your ubuntu machine?

# install python3.6 or python3.7
$ pip install lifx-photons-core
$ lifx lan:find_devices

I installed photon and it seems to be able to find all of the lights on my network, however I don’t see responses from the lights in Wireshark. Maybe I have a gap in my understanding of how this is supposed to work?

The only way photons can see the bulbs is if the bulbs respond to the GetService packets. So now we know the responses are working and its just that Wireshark is not seeing them. Are you running photons on the same machine as you are running Wireshark?

Hi Daniel,

Wireshark was not running on the same machine, I didn’t realize it wouldn’t be able to see the packets anyway! I installed tshark on the Ubuntu server and now I can see the packets coming back.

Thank you so much for all of your help @delfick and @daniel_hall!

2 Likes