You should be doing the GET test first with String “/2” and the url not terminated with a backslash.
I have this on the wemos side
BLYNK_WRITE(V0) // Webhook widget
{
String webhookdata = param.asStr();
//Serial.println("hue feedback:");
Serial.println(webhookdata);
}
BLYNK_WRITE(V1) // button
{
//lightBrightness = param.asInt();
//String msgBody = ("{""\"bri\":" + String(lightBrightness) + "}");
String msgBody = "/2";
Serial.println(msgBody);
Blynk.virtualWrite(V0, msgBody); // send to Webhook on V0
}
And the webhook is on V0 with URL http://ip/user/api/lights/pin/ method GET, body empty. When I push the button in the app I indeed see /2, but nothing is returned
You have api and user the wrong way round in this url.
Human error after all…
GET works with http://ip/api/user/lights/pin/ BUT it needs {} in the body, with an empty body it gives an invalid json response.
I also changed V1 back to the slider (with a range of 10-255) and it works!
/*************************************************************
WebhookPUTtest.ino by Costas the code 13/3/18
Control brightness of Philips Hue Light with Blynk Webhook widget on a local server only!
V0 Webhook widget url syntax: http://<bridge ip address>/api/<username>/lights/<id>/state
Method PUT
Body /pin/
V1 Blynk slider with no decimal places set as send on release
range 10 to 255
*************************************************************/
#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#define BLYNK_MAX_READBYTES 4096
char auth[] = "xxxxxxxxxxxxxxxxxxx";
char ssid[] = "xxxxxxxxxxxxxx";
char pass[] = "xxxxxxxxxxxxx";
#define server "192.168.0.201"
unsigned int lightBrightness = 10; // minimum brightness value for a white hue lamp
void setup()
{
Serial.begin(115200);
Blynk.begin(auth, ssid, pass, server, 8080);
pinMode(LED_BUILTIN,OUTPUT);
digitalWrite(LED_BUILTIN,LOW);
Serial.println("Starting program...");
}
BLYNK_WRITE(V0) // Webhook widget
{
String webhookdata = param.asStr();
Serial.println("hue feedback:");
Serial.println(webhookdata);
}
BLYNK_WRITE(V1) // button
{
lightBrightness = param.asInt();
String msgBody = ("{""\"bri\":" + String(lightBrightness) + "}");
Serial.println(msgBody);
Blynk.virtualWrite(V0, msgBody); // send to Webhook on V0
}
void loop()
{
Blynk.run();
}
Thank you very much for helping with this problem!
Knew we would get there in the end. I’ll add Philips Hue light hacker to my CV
I find this very hard to believe as the GET doesn’t require a body as per the Philips API and all other GET methods. Probably just need to set content type as text/plain when using GET rather the json for PUT.
I just tried switching to text/plain and still get this error:
[{“error”:{“type”:2,“address”:“/lights/2”,“description”:“body contains invalid json”}}]
You will notice 2 appears twice in that response.
Something wrong with the formatting somewhere but probably not the body as GET doesn’t use it.
Might be that you ignore the Blynk warning, pretty sure I do, and use the double backslash in the url
as //pin/
and just send 2 to the Webhook rather than “/2”.
The Blynk error message is blatantly wrong as the url DOES start with the required http / https and at best it should say something like “badly formatted url” for double backslash. But I’m pretty sure you can ignore the error message and it’s best to use double backslash.
I believe the first 2 refers to the type of error the Hue Bridge is returning, type 1 is invalid user, type 2 is invalid json and type 3 I forgot…
I wrote an addition which adds an on/off button to the system, just need to figure a way of verifying whether the current slider position corresponds to the brightness of the light (Philips doesn’t allow brightness changes when the light is off).
Could also change the slider range to 0-255 and let everything below 10 send the off command, but then I need a smart way of sending the on command only once (Philips advises to not always send the on command with another command once the light is already on)
BLYNK_WRITE(V2) // on/off button
{
if( param.asInt() == 1){
lightState = "true";
}
else if ( param.asInt() == 0){
lightState = "false";
}
String msgBody = ("{""\"on\":" + lightState + "}");
Serial.println(msgBody);
Blynk.virtualWrite(V0, msgBody); // send to Webhook on V0
}
Slider with off function:
BLYNK_WRITE(V1) // slider with off function
{
lightBrightness = param.asInt();
if (lightBrightness < 10){
lightState = "false, ";
}
else {
lightState = "true, ";
}
String msgBody = ("{""\"on\":" + lightState + "\"bri\":" + String(lightBrightness) + "}");
Serial.println(msgBody);
Blynk.virtualWrite(V0, msgBody); // send to Webhook on V0
}
Comprehensive schedule of error messages at Login - Philips Hue Developer Program
My thoughts on the on / off with hue settings is to send both parts of the json via the slider.
We send 7 or 8 variables in some of our json strings.
I added this implementation to my previous post, works really nice! Now I can start thinking of ways to add multiple lights/scenes easily. This is where the hue app has an advantage I guess.
@jbowser and @Costas: if I understand correctly, @jbowser wants to figure out how to control Hue lights using the Blynk app, via a suitable microcontroller. To be honest, I am too lazy to read through all of the message you exchanged. When I started to work with the Hues, it took me some time to find some good examples and to get it to work and maybe @jbowser is at the same stage. So what I can offer here is to paste some code that I am using and which works fine.
I have a number of Particle Photons and the user interface is either the Blynk app or hardware buttons/rotary encoders and the code on the microcontroller translates this into HTTP GET or PUT requests to read out or set the state (on or off, brightness level), respectively. I would like to point out that I don’t want to entirely take the credit for this code because it is adapted from different website that I found (e.g. by googling “particle photon philips hue PUT GET” or something like that).
A code example to read the state of a HUE group:
TCPClient HueHub;
byte HueHubIP[] = { 192, 168, x, xx };
const char HueUsername[] = "2eoVQxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // Hue username
const int HueHubPort = 80;
boolean GetHue(int lightNum) {
String jsonExtract;
if (HueHub.connect(HueHubIP, HueHubPort))
{
HueHub.print("GET /api/");
HueHub.print(HueUsername);
HueHub.print("/lights/");
HueHub.print(lightNum);
HueHub.println(" HTTP/1.1");
HueHub.print("Host: ");
HueHub.println(HueHubIP);
HueHub.println("Content-type: application/json");
HueHub.println("keep-alive");
HueHub.println();
while (HueHub.connected())
{
if (HueHub.available())
{
HueHub.findUntil("\"on\":", "\0");
String jsonExtract = HueHub.readStringUntil(',');
Serial.print("Reading Hue state feedback:...");
Serial.println(jsonExtract);
if (jsonExtract == "true") LightstripOn = true;
if (jsonExtract == "false") LightstripOn = false;
HueHub.findUntil("\"bri\":", "\0");
Serial.print("Reading Hue brightness feedback:...");
jsonExtract = HueHub.readStringUntil(',');
Serial.println(jsonExtract);
if (!LightstripOn) LightstripOn = 0; else LightStripHueBrightness = jsonExtract.toInt(); // set variable to brightness value
BrightnessUpdated = true;
break; // not capturing other light attributes yet
}
}
HueHub.stop();
return true; // captured on,bri,hue
}
else
return false; // error reading on,bri,hue
}
The following code block can be used to set the state of a Hue, e.g. switch it on or off, set a brightness value.
boolean setHue(int lightNum,String command) {
if (HueHub.connect(HueHubIP, HueHubPort)) {
HueHub.print("PUT /api/");
HueHub.print(HueUsername);
HueHub.print("/groups/");
HueHub.print(lightNum); // hueLight zero based, add 1
HueHub.println("/action HTTP/1.1");
HueHub.println("keep-alive");
HueHub.print("Host: ");
HueHub.println(HueHubIP);
HueHub.print("Content-Length: ");
HueHub.println(command.length());
HueHub.println("Content-Type: text/plain;charset=UTF-8");
HueHub.println(); // blank line before body
HueHub.println(command); // Hue command
delay(30);
HueHub.stop();
return true; // command executed
}
else {
Serial.println(".. error: no connection to Hue bridge");
return false; // command failed
}
}
The above routines can be simply called like in this example:
#define BathLightStripHue 14
String HueOFF = "{\"on\": false}";
String Hue_SetBrightness = "{\"on\": true,\"bri\":";
String BathLightStripHueON = "{\"on\": true}";
To switch a light on and/or to set a certain brightness level:
int LightStripHueBrightness = 254;
setHue(BathLightStripHue,(Hue_SetBrightness+String(LightStripHueBrightness)+"}"));
Or to switch off:
setHue(BathLightStripHue, HueOFF);
Or to read the current state and brightness (this saves the brightness value and a boolean which holds state, i.e. on or off in two global variables):
GetHue(BathLightStripHue);
To implement a slider in the Blynk app, I did the following: (this simply reads the slide value and passes it on to the SetHue routine, in this case for the Hue group with nr 3)
String Hue_SetBrightness = "{\"on\": true,\"bri\":";
BLYNK_WRITE(HueVPin) { // gets called from the slider widget on virtual pin "HueVPin"
int HueBrightness = param[0].asInt();
setHue(3, Hue_SetBrightness + String(HueBrightness)+"}"));
}
Hope this helps.
Should be easy with Node-RED + node-red-contrib-blynk-ws + node-red-contrib-node-hue ?