
How to connect your ESP or Arduino with Philips Hue bridge using RESTfull API and HTTP requests.
Hardware | |||
---|---|---|---|
1 | Wemos D1 mini (ESP8266) | $ 3.5 | |
1 | Lolin D32 Pro (ESP32) | $ 8.8 | |
1 | TFT 2.4 Touch Shield V1.0.0 for LOLIN | $ 5.9 | |
1 | IR Controller Shield V1.0.0 for LOLIN | $ 1.4 |
Software | |||
---|---|---|---|
1 | Arduino IDE |
In this tutorial, I'm going to show you how to connect your ESP or Arduino with Philips Hue bridge using RESTfull API and HTTP requests.
I would like to continue with the idea of using a microcontroller with the Philips Hue system. I will do this by extending the light control capabilities with IR remote control (e.g., a simple remote control from a television) or make an interactive switch with TFT shield for ESP32 Lolin D32 with simple power consumption monitoring.
The ideas above are a few basic concepts and several other details need to be solved for real use (location of IR sensor, detection of the current state of the bulb by API getter, etc.)
Required Hardware
Required Libraries
- https://github.com/markszabo/IRremoteESP8266
- https://github.com/adafruit/Adafruit-GFX-Library
- https://github.com/adafruit/Adafruit_ILI9341
- https://github.com/PaulStoffregen/XPT2046_Touchscreen
Project Code
/************************************************************* | |
Hue @ D1 mini Pro (ESP8266) | |
Basic demo of switch based on IR sensor to demonstrate | |
communication between ESP and Hue gateway | |
Version: 1.00 | |
by Petr Lukas | |
Functionality: | |
Identify IR signal and switch light on and off using IR remote control. | |
*************************************************************/ | |
#include <IRremoteESP8266.h> | |
#include <IRrecv.h> | |
#include <IRutils.h> | |
#include <ESP8266HTTPClient.h> | |
#include <ESP8266WiFi.h> | |
// Wifi network SSID | |
const char* ssid = "YOUR_SSID"; | |
// Wifi network password | |
const char* password = "YOUR_PASSWORD"; | |
// IP of Hue gateway | |
String ip = "YOUR_HUE_BRIDGE_IP"; | |
// Set IR signal number (copy it from serial output) to switch light on and off | |
int switch_on = 0xE0E048B7; | |
int switch_off = 0xE0E008F7; | |
// Hue gateway user name | |
String user_name = "YOUR_HUE_AUTHORIZED_USER"; | |
#define RECV_PIN D4 | |
#define MIN_UNKNOWN_SIZE 20 | |
IRrecv irrecv(RECV_PIN); | |
decode_results results; | |
bool state = false; | |
void setup() { | |
Serial.begin(115200); | |
WiFi.begin(ssid, password); | |
Serial.print("Connecting to WiFi"); | |
while (WiFi.status() != WL_CONNECTED) { | |
delay(1000); | |
Serial.print("."); | |
} | |
Serial.println("Connected to the WiFi network"); | |
irrecv.enableIRIn(); // Start the receiver | |
while (!Serial) // Wait for the serial connection to be establised. | |
delay(50); | |
Serial.println(); | |
Serial.print("IR receiver is now running and waiting for IR message on Pin "); | |
Serial.println(RECV_PIN); | |
irrecv.setUnknownThreshold(MIN_UNKNOWN_SIZE); | |
} | |
void loop() { | |
if (irrecv.decode(&results)) { | |
// print() & println() can't handle printing long longs. (uint64_t) | |
serialPrintUint64(results.value, HEX); | |
Serial.println(""); | |
if(results.value == switch_on){ | |
switchLight(1,true); | |
delay(500); | |
} | |
if(results.value == switch_off){ | |
switchLight(1,false); | |
delay(500); | |
} | |
irrecv.resume(); // Receive the next value | |
} | |
delay(100); | |
} | |
void switchLight(byte room, bool current_state){ | |
state = current_state; | |
HTTPClient http; | |
String req_string; | |
req_string = "http://"; | |
req_string += ip; | |
req_string += "/api/"; | |
req_string += user_name; | |
req_string += "/lights/"; | |
req_string += room; | |
req_string += "/state"; | |
Serial.println(req_string); | |
http.begin(req_string); | |
http.addHeader("Content-Type", "text/plain"); | |
String put_string; | |
put_string = "{\"on\":"; | |
put_string += (current_state)? "true" : "false"; | |
put_string += "}"; | |
int httpResponseCode = http.PUT(put_string); | |
if(httpResponseCode > 0){ | |
String response = http.getString(); | |
Serial.println(httpResponseCode); | |
Serial.println(response); | |
} else { | |
Serial.print("Error on sending PUT Request: "); | |
Serial.println(httpResponseCode); | |
} | |
http.end(); | |
} |
/************************************************************* | |
Hue @ Lolin D32 Pro (ESP32) | |
Basic demo of switch based on touch TFT display to demonstrate | |
communication between ESP and Hue gateway | |
Version: 1.00 | |
by Petr Lukas | |
Functionality: | |
Touch a button on TFT to switch on and off the lights. | |
*************************************************************/ | |
#include <WiFi.h> | |
#include <HTTPClient.h> | |
#include <Adafruit_GFX.h> | |
#include <Adafruit_ImageReader.h> | |
#include <Adafruit_ILI9341.h> | |
#include <SPI.h> | |
#include <SD.h> | |
// Touchscreen library | |
#include <XPT2046_Touchscreen.h> | |
// Fonts | |
#include <Fonts/FreeMono9pt7b.h> | |
#include <Fonts/FreeSansBold9pt7b.h> | |
#include <Fonts/FreeSansBold12pt7b.h> | |
// Default pin numbers for D32 Pro | |
#define TFT_CS 14 | |
#define TFT_DC 27 | |
#define TFT_RST 33 | |
#define TS_CS 12 | |
// SD card pin | |
#define SD_CS 4 | |
// IP of Hue gateway | |
String ip = "YOUR_HUE_BRIDGE_IP"; | |
// Hue gateway user name | |
String user_name = "YOUR_HUE_AUTHORIZED_USER"; | |
// Wifi network SSID | |
const char* ssid = "YOUR_SSID"; | |
// Wifi network password | |
const char* password = "YOUR_PASSWORD"; | |
// Power consumtion per bulb | |
float consumption = 8.5; // Let's assume consumption of bulb in full light is 8.5 W | |
unsigned long previousMillis = 0; | |
bool state1 = false; | |
bool state2 = false; | |
bool state3 = false; | |
float total_consumption = 0; | |
int runtime = 0; | |
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST); | |
Adafruit_ImageReader reader; | |
XPT2046_Touchscreen ts(TS_CS); | |
void setup() { | |
// put your setup code here, to run once: | |
Serial.begin(115200); | |
tft.begin(); | |
tft.setFont(&FreeMono9pt7b); | |
tft.fillScreen(ILI9341_BLACK); | |
tft.setCursor(0, 15); | |
tft.println("Init SD card..."); | |
if (!SD.begin(SD_CS)) { | |
tft.setTextColor(ILI9341_RED); | |
Serial.println("SD card failed"); | |
tft.println("Failed!"); | |
delay(999999); | |
return; | |
} | |
WiFi.begin(ssid, password); | |
tft.println("Connecting to WiFi"); | |
Serial.print("Connecting to WiFi"); | |
while (WiFi.status() != WL_CONNECTED) { | |
delay(1000); | |
Serial.print("."); | |
} | |
Serial.println("Connected to the WiFi network"); | |
tft.println("Success"); | |
delay(500); | |
tft.println("Init touchscreen..."); | |
ts.begin(); | |
tft.println("Setup complete"); | |
tft.println("Starting loop..."); | |
delay(500); | |
tft.fillScreen(ILI9341_BLACK); | |
drawButtons(); | |
} | |
void switchLight(byte light_id, bool current_state, int x, int y){ | |
HTTPClient http; | |
String req_string; | |
req_string = "http://"; | |
req_string += ip; | |
req_string += "/api/"; | |
req_string += user_name; | |
req_string += "/lights/"; | |
req_string += light_id; | |
req_string += "/state"; | |
Serial.println(req_string); | |
http.begin(req_string); | |
http.addHeader("Content-Type", "text/plain"); | |
String put_string; | |
put_string = "{\"on\":"; | |
put_string += (current_state)? "true" : "false"; | |
put_string += "}"; | |
int httpResponseCode = http.PUT(put_string); | |
// Change button only in case the operation is successfull | |
if(httpResponseCode == 200){ | |
toggleButton(x,y,current_state); | |
} | |
if(httpResponseCode > 0){ | |
String response = http.getString(); | |
Serial.println(httpResponseCode); | |
Serial.println(response); | |
} else { | |
Serial.print("Error on sending PUT Request: "); | |
Serial.println(httpResponseCode); | |
} | |
http.end(); | |
} | |
void drawButtons(){ | |
int y = 115; | |
int y_space = 60; | |
reader.drawBMP("/wemos.bmp", tft, 10, 20); | |
reader.drawBMP("/hue.bmp", tft, 180, 20); | |
reader.drawBMP("/off.bmp", tft, 130, y); | |
reader.drawBMP("/off.bmp", tft, 130, y + y_space); | |
reader.drawBMP("/off.bmp", tft, 130, y + y_space*2); | |
tft.setFont(&FreeSansBold12pt7b); | |
y = y + 22; | |
tft.setCursor(3, y); | |
tft.println("Hall:"); | |
tft.setCursor(3, y + y_space); | |
tft.println("Bedroom:"); | |
tft.setCursor(3, y + y_space*2); | |
tft.println("Bathroom:"); | |
tft.setFont(&FreeSansBold9pt7b); | |
tft.setCursor(50, 310); | |
tft.println("0.00 Wh | 0 min"); | |
} | |
void toggleButton(int x, int y, bool state){ | |
if(state){ | |
reader.drawBMP("/on.bmp", tft, x, y); | |
} else { | |
reader.drawBMP("/off.bmp", tft, x, y); | |
} | |
} | |
void loop() { | |
unsigned long currentMillis = millis(); | |
if (currentMillis - previousMillis >= 1000){ | |
if(state1)total_consumption += consumption/3600; | |
if(state2)total_consumption += consumption/3600; | |
if(state3)total_consumption += consumption/3600; | |
runtime++; | |
tft.setFont(&FreeSansBold9pt7b); | |
tft.setCursor(50, 310); | |
tft.fillRect(0,285,240,320,ILI9341_BLACK); | |
tft.print(total_consumption,2); | |
tft.print(" Wh | "); | |
tft.print(runtime/60); | |
tft.print(" min"); | |
previousMillis = currentMillis; | |
} | |
if (ts.touched()) { | |
TS_Point p = ts.getPoint(); | |
// You need to test coordinates (in this case landscape oriented) | |
/* | |
tft.setCursor(0,50); | |
tft.fillRect(0,30,100,50,ILI9341_BLACK); | |
tft.println(p.x); | |
tft.println(p.y); | |
*/ | |
if((p.x < 2500 && p.x > 2000) && (p.y < 1800 && p.y > 300)){ | |
state1 = !state1; | |
switchLight(1, state1, 130, 115); | |
} | |
if((p.x < 2000 && p.x > 1500) && (p.y < 1800 && p.y > 300)){ | |
state2 = !state2; | |
switchLight(2, state2, 130, 175); | |
} | |
if((p.x < 1500 && p.x > 1000) && (p.y < 1800 && p.y > 300)){ | |
state3 = !state3; | |
switchLight(3, state3, 130, 235); | |
} | |
delay(500); | |
} | |
} |
Watch the video below to see how I do!