I am trying to build a one button ESP8266 switch to control one of my Lifx bulbs.
I am not a coder so I’ve searched to find a working code designed by someone but none of the ones I found did work. So would love to hear from this community if one has build one and if possible share the code to tyr.
Yeah, just a sec. This is a cut-down version of my current controller. Should toggle a light on and off on button press. If you want a two-way switch (like a normal light switch) then I can remove all the debounce stuff and check buttonState and set “HIGH” to on, and “LOW” to off.
It’s based on code I originally got off this forum and iterated on. The tricky stuff is setting up the packet structure. Once you’ve done that you can wrap it all up in a function (SetPower) and call it
NB: there’s a bit of code around checking for a “held” button, but you can probably ignore that.
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
// ---- Network Settings ----
//wifi setup
const char* ssid = "your network";
const char* password = "your password";
// Remote IP (In this case we broadcast to the entire subnet - .1 for me, might be different for you)
IPAddress broadcast_ip(192, 168, 1, 255);
//the light's mac address - update
uint8_t dest[] = {0xd0, 0x73, 0xd5, 0xab, 0xcd, 0xef};
// the ESP pin you're using
#define buttonPin 4
// Port we listen to
unsigned int localPort = 8888;
// Port for talking to LIFX devices
unsigned int lifxPort = 56700;
// --- LIFX Protocol ---
// 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)
#pragma pack(push, 1)
typedef struct {
uint16_t color[4];
int16_t reserved;
uint16_t power;
char label[32];
uint64_t reserved2;
} lifx_light_state;
#pragma pack(pop)
// Device::SetPower Payload
#pragma pack(push, 1)
typedef struct {
uint16_t level;
} lifx_payload_device_set_power;
#pragma pack(pop)
// Device::StatePower Payload
#pragma pack(push, 1)
typedef struct {
uint16_t level;
} lifx_payload_device_state_power;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct {
uint8_t reserved;
uint16_t color[4];
uint32_t duration;
} lifx_payload_light_set_color;
#pragma pack(pop)
// Payload types
#define LIFX_DEVICE_GETPOWER 20
#define LIFX_DEVICE_SETPOWER 21
#define LIFX_DEVICE_STATEPOWER 22
#define LIFX_LIGHT_GETSTATE 101
#define LIFX_LIGHT_SETCOLOR 102
#define LIFX_LIGHT_STATE 107
// Packet buffer size
#define LIFX_INCOMING_PACKET_BUFFER_LEN 600
// Length in bytes of serial numbers
#define LIFX_SERIAL_LEN 6
// An EthernetUDP instance to let us send and receive packets over UDP
WiFiUDP Udp;
unsigned long timeoutInterval = 500;
unsigned long lastSend = 0;
unsigned long lastCheck = 0;
boolean buttonState = LOW;
unsigned long onTime;
uint16_t level = 0;
uint16_t brightness = 0;
uint16_t hue = 0;
uint16_t saturation = 0;
uint16_t kelvin = 4000;
#define LEDPIN LED_BUILTIN
int buttonState = HIGH;
long lastDebounceTime = 0;
long debounceDelay = 50;
long holdWindow = 800;
int lastButtonState = HIGH;
long lastHoldTime = -1;
long lastPressTime = -1;
bool initialised = false;
void setup() {
Serial.begin(19200);
Serial.print("\n\n\n\n");
Serial.println("Setting up switches");
pinMode(buttonPin, INPUT_PULLUP);
Serial.println("\n\nSetting up network");
IPAddress deviceIpip(192, 168, 1, 211); //this device IP - update if you like
IPAddress gateway(192, 168, 1, 1); //your router
IPAddress subnet(255, 255, 255, 0);
WiFi.config(ip, gateway, subnet);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Udp.begin(localPort); // Listen for incoming UDP packets
Serial.println("Network is set up");
}
void loop() {
//read the button and check for changes
buttonState = digitalRead(buttonPin);
if ( (millis() - lastDebounceTime) > debounceDelay) {
if (buttonState == LOW && lastButtonState == HIGH) {
//the button has been pressed
lastButtonState = LOW;
lastHoldTime = millis();
}
if (buttonState == HIGH && lastButtonState == LOW && (millis() - lastHoldTime < holdWindow)) {
//the button has been released (quickly)
lastButtonState = HIGH;
lastDebounceTime = millis();
if (level == 0) {
level = 65535;
} else {
level = 0;
}
Serial.println(SetPower(dest, level));
lastPressTime = millis();
} else if (buttonState == HIGH && lastButtonState == LOW) {
//the button has been released after holding for a while
lastButtonState = HIGH;
lastDebounceTime = millis();
}
}
}
uint16_t SetPower(uint8_t *dest, uint16_t power) {
lifx_header header;
lifx_payload_device_set_power payload;
// Initialise both structures
memset(&header, 0, sizeof(header));
memset(&payload, 0, sizeof(payload));
// Set the target the nice way
memcpy(header.target, dest, sizeof(uint8_t) * LIFX_SERIAL_LEN);
// Setup the header
header.size = sizeof(lifx_header) + sizeof(payload); // Size of header + payload
header.tagged = 0;
header.addressable = 1;
header.protocol = 1024;
header.source = 123;
header.ack_required = 1;
//header.res_required = 1;
header.sequence = 100;
header.type = LIFX_DEVICE_SETPOWER;
payload.level = power;
// Send a packet on startup
Udp.beginPacket(broadcast_ip, 56700);
Udp.write((char *) &header, sizeof(lifx_header));
Udp.write((char *) &payload, sizeof(payload)); // Which makes the data on wire correct
Udp.endPacket();
unsigned long started = millis();
while (millis() - started < timeoutInterval) {
int packetLen = Udp.parsePacket();
byte packetBuffer[LIFX_INCOMING_PACKET_BUFFER_LEN];
if (packetLen && packetLen < LIFX_INCOMING_PACKET_BUFFER_LEN) {
Udp.read(packetBuffer, sizeof(packetBuffer));
Serial.print("Received Packet type: ");
Serial.println(((lifx_header *)packetBuffer)->type);
}
}
return power;
}
2 Likes