Skip to content

Instantly share code, notes, and snippets.

@erijpkema
Last active September 13, 2021 14:36
Show Gist options
  • Save erijpkema/17f2b970ca79fb7b8049e5d14bc541b2 to your computer and use it in GitHub Desktop.
Save erijpkema/17f2b970ca79fb7b8049e5d14bc541b2 to your computer and use it in GitHub Desktop.
ESP8266 flash lifx lights
/* This is made for a ESP8266 (i use a wemos d1). It uses the udp lan protocol to flash the lights.
* This program will let your lifx lamps flash purple seven times when a switch is pressed.
* When it has a wifi connection, a led will go on.
* I started from code by daniel_hall at https://community.lifx.com/t/sending-lan-packet-using-arduino/1460/3
*/
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <ESP8266WiFiMulti.h>
#include <SPI.h>
#define pushButton 14
#define readyLed 15
// Remote IP (In this case we broadcast to the entire subnet)
IPAddress broadcast_ip(192, 168, 178, 255);
unsigned int localPort = 8888; // Port to listen for responses on
unsigned int lifxPort = 56700; // Port used to send to send to LIFX devices
const char* WiFiSSID = "my_ssd";
const char* WiFiPW = "wifi_password";
ESP8266WiFiMulti WiFiMulti;
WiFiUDP Udp;
// The LIFX Header structure
#pragma pack(push, 1)
typedef struct {
/* frame */
uint16_t size;
uint16_t protocol:12;
uint8_t addressable:1;
uint8_t tagged:1;
uint8_t origin:2;
uint32_t source;
/* frame address */
uint8_t target[8];
uint8_t reserved[6];
uint8_t res_required:1;
uint8_t ack_required:1;
uint8_t :6;
uint8_t sequence;
/* protocol header */
uint64_t :64;
uint16_t type;
uint16_t :16;
/* variable length payload follows */
} lifx_header;
#pragma pack(pop)
// Device::SetColor Payload
#pragma pack(push, 1)
typedef struct {
uint16_t level;
} lifx_payload_device_set_power;
#pragma pack(pop)
// see SetColor https://lan.developer.lifx.com/docs/light-messages
#pragma pack(push, 1)
typedef struct {
uint8_t reserved;
//HSBK
uint16_t hue;
uint16_t saturation;
uint16_t brightness;
uint16_t kelvin;
uint32_t duration;
} lifx_payload_light_set_color;
#pragma pack(pop)
// Payload types
#define LIFX_DEVICE_SETPOWER 21
#define LIFX_LIGHT_SETCOLOR 102
// Packet buffer size
#define LIFX_INCOMING_PACKET_BUFFER_LEN 300
// Timing data
unsigned long sendInterval = 5000; // 5 seconds
unsigned long lastSend = 0;
void setup() {
Serial.begin(9600);
// Wait a little...
for(uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
Serial.printf("Adding AP \n");
WiFiMulti.addAP(WiFiSSID, WiFiPW);
Serial.println("DEBUG added ap");
Udp.begin(localPort); // Listen for incoming UDP packets
Serial.println("DEBUG, listening for incoming UDB");
// Setup the Pushbutton
// make the pushbutton's pin an input:
pinMode(pushButton, OUTPUT); // Output first seems to be nessecary on wemos d1.
pinMode(pushButton, INPUT);
pinMode(readyLed, OUTPUT);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println(" connected");
digitalWrite(readyLed, HIGH);
}
void set_power(const unsigned int level) {
lifx_header header;
lifx_payload_device_set_power payload;
// Initialise both structures
memset(&header, 0, sizeof(header));
memset(&payload, 0, sizeof(payload));
// Setup the header
header.size = sizeof(lifx_header) + sizeof(payload); // Size of header + payload
header.tagged = 1;
header.addressable = 1;
header.protocol = 1024;
header.source = 123;
header.ack_required = 1;
header.sequence = 100;
header.type = LIFX_DEVICE_SETPOWER;
// Setup payload
payload.level = level;
Serial.println("writing package");
// Send a packet on startup
Udp.beginPacket(broadcast_ip, 56700);
Udp.write((char *) &header, sizeof(lifx_header)); // Treat the structures like byte arrays
Udp.write((char *) &payload, sizeof(payload)); // Which makes the data on wire correct
Udp.endPacket();
Serial.println("package written");
}
void set_color(const unsigned int hue, const unsigned int saturation, const unsigned int kelvin) {
// Set color to purple
lifx_header header;
lifx_payload_light_set_color payload;
// Initialise both structures
memset(&header, 0, sizeof(header));
memset(&payload, 0, sizeof(payload));
// Setup the header
header.size = sizeof(lifx_header) + sizeof(payload); // Size of header + payload
header.tagged = 1;
header.addressable = 1;
header.protocol = 1024;
header.source = 123;
header.ack_required = 1;
header.sequence = 100;
header.type = LIFX_LIGHT_SETCOLOR;
payload.hue = hue; // 0 - 65535
payload.saturation = saturation;
payload.brightness = 65535;
payload.kelvin = kelvin;
Serial.println("Writing color payload");
// Send a packet on startup
Udp.beginPacket(broadcast_ip, 56700);
Udp.write((char *) &header, sizeof(lifx_header)); // Treat the structures like byte arrays
Udp.write((char *) &payload, sizeof(payload)); // Which makes the data on wire correct
Udp.endPacket();
Serial.println("package written");
}
void flash () {
/*
* Flash purple three times
* set to white repeatedly afterwards,
* just to be sure.
*/
//set purple
set_color(50000, 65535, 32767);
// flash lights 3 times
for(uint8_t t = 3; t > 0; t--) {
set_power(65535);
delay(2000);
set_power(0);
delay(2000);
}
delay(5000);
for(uint8_t t = 6; t > 0; t--) {
set_color(0, 0, 32767); // set white 8996k
set_power(65535);
delay(2000);
}
}
void loop() {
// read the input pin:
int buttonState = digitalRead(pushButton);
// print out the state of the button:
Serial.println(buttonState);
delay(1); // delay in between reads for stability
if(buttonState == 1) {
flash();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment