HTTP Post doesn't have BODY pin? (help with Philips Hue)

hi -

I’m trying to control some Philips Hue lights with vvvv, they communicative via JSON and it all seems very simple…but I can’t send the correct messages!

To initiate the lights, they say in the API (http://developers.meethue.com/gettingstarted.html) to sent an HTTP POST with the BODY containing a certain bit of JSON…

…problem is, the HTTP POST node in VVV only wants to send NAME and VALUE but no plain BODY!

What am I doing wrong here?

Thanks!

u should post a patch
but i guess u need to send some xml somehow… dunno
sure some one can figure it out

yeah, i don’t know if a patch would actually help…but I’ll cook one up anyway

basically the problem is, the Hue server wants me to send

::{“devicetype”:“test user”,“username”:“newdeveloper”}::

as the BODY of an http POST request, but the http-(network-post) node only has inputs for NAME and VALUE…neither of which work in this situation…

(i’ve tried to just reverse-engineer the formatting of a POST request and send it as a URL but I’ve failed every time)

well the node was designed to transmit web forms easily. see https://en.wikipedia.org/wiki/POST_%28HTTP%29#Use_for_submitting_web_forms.
my guess is no one thought about REST APIs when writing it. so yes, you’re out of luck with that node. but i think it shouldn’t be too hard to patch your http request with the exisiting tcp nodes?

awww, crud…I gotta figure it out from scratch, huh?

anybody have any prior experience wit this kind of thing?

I’m literally starting from nothing, here…

Okay, I was able to sniff out the plaintext of the POST request sent by the built-in debugger (as seen here http://developers.meethue.com/gettingstarted.html)

POST http://10.0.0.7/api HTTP/1.1
Host: 10.0.0.7
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:20.0) Gecko/20100101 Firefox/20.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://10.0.0.7/debug/clip.html
Content-Length: 52
Content-Type: text/plain; charset=UTF-8
DNT: 1
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

{"devicetype":"test user","username":"newdeveloper"}

So now my plan is justy to send exactly that using the tcp-(network-client) node…

…which I’ve tried with no luck :(

Now, I need to send it to 10.0.0.7/api and I have a terrible feeling the remote host pin doesn’t support directories?

yeah, i need help on this…I have no idea how to send an http POST through the TCP node :(

while i’m here

this might do, untested tough.

HttpPostRaw.zip (2.9 kB)

woah, thanks woei!

it kinda works!

I loaded it up, like so:

{img src = “http://i.imgur.com/8Nbp7MI.png”}

The left pin is labelled header but the right pin has no label…is this supposed to be for the response?

As you can see I get a valid header from the Hue API but I don’t seem to be getting anything more…is this the node’s fault? Have I set it up wrong? Maybe it’s the API? (I’m using 45beta29.2 btw)

(I’ll attach the patch even though it won’t make much sense to anybody who doesn’t have the Hue setup)

thanks again, I’ll get this workin’ sooner or later!

HttpPostRaw-Test-01.v4p (4.9 kB)

ah yes, stream pins still new and a little tricky sometimes. take this code, should output something now. i’ve added comments to the code parts where i changed something.

- region usings
using System;
using System.ComponentModel.Composition;

using VVVV.PluginInterfaces.V1;
using VVVV.PluginInterfaces.V2;

using System.IO;
using System.Net;

using VVVV.Core.Logging;
- endregion usings

namespace VVVV.Nodes
{
	#region PluginInfo
	[PluginInfo(Name = "HTTP", Category = "Network", Version = "Post Raw",
	Help = "posts raw data to given urls on the web", Author = "woei")]
	#endregion PluginInfo
	public class HttpPostRawNode : IPluginEvaluate, IPartImportsSatisfiedNotification
	{
		#region fields & pins
		[Input("URL", StringType = StringType.URL, DefaultString = "http://localhost")](Input("URL", StringType = StringType.URL, DefaultString = "http://localhost"))
		ISpread<string> FURL;
		
		[Input("Content")](Input("Content"))
		ISpread<System.IO.Stream> FContent;
		
		[Input("MimeType", EnumName = "MimeTypeMode")](Input("MimeType", EnumName = "MimeTypeMode"))
		ISpread<EnumEntry> FMimeType;
		
		[Input("Refresh", IsBang = true)](Input("Refresh", IsBang = true))
		ISpread<bool> FRefresh;
		
		[Output("Header")](Output("Header"))
		ISpread<string> FHeader;
		
		[Output("Response")](Output("Response"))
		ISpread<System.IO.Stream> FResponse;

		[Import()](Import())
		ILogger FLogger;
		#endregion fields & pins
		
		public void OnImportsSatisfied()
		{
			// This ensures that we start in a clean state -> no null in FResponse,
			// which we'd need to take care of in each evaluate call.
			FHeader.SliceCount = 0;
			FResponse.SliceCount = 0;
		}

		//called when data for any output pin is requested
		public void Evaluate(int spreadMax)
		{
			FHeader.SliceCount = spreadMax;
			// We need to manage the lifetime of our streams
			FResponse.ResizeAndDispose(spreadMax, () => new MemoryStream());
			
			for (int i=0; i<spreadMax; i++)
			{
				if (FRefresh[i](i))
				{
					try
					{
						Uri url = new Uri(FURL[i](i));
						HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
						request.ContentType = FMimeType[i](i).Name;
						request.Method = "POST";
	        			request.KeepAlive = true;
						request.Credentials = System.Net.CredentialCache.DefaultCredentials;
						
						byte[]() buffer = new byte[1024](1024);
						int bytesRead = 0;
						using (Stream reqstr = request.GetRequestStream())
						{
							while [bytesRead = FContent[i](i).Read(buffer, 0, buffer.Length](https://vvvv.org/documentation/bytesRead-=-FContent[i](i).Read(buffer,-0,-buffer.Length) != 0) 
		            				reqstr.Write(buffer, 0, bytesRead);
	        			}
						
						WebResponse response = request.GetResponse();
						FHeader[i](i) = response.Headers.ToString();
						// Response stream doesn't support seeking -> getting Length not allowed
						FResponse[i](i).SetLength(response.ContentLength);
						using (Stream respstr = response.GetResponseStream())
						{
							while [bytesRead = respstr.Read(buffer, 0, buffer.Length](https://vvvv.org/documentation/bytesRead-=-respstr.Read(buffer,-0,-buffer.Length) != 0) 
		            				FResponse[i](i).Write(buffer, 0, bytesRead);
						}
						// Marks the pin as changed (as the pin doesn't know about write operation above)
						FResponse.Flush(true);
					}
					catch (Exception e)
					{
						FLogger.Log(e);
					}
				}
			}
		}
	}
}

EDIT: did a clean install of vvvv on a separate computer and the right pin is labelled “Response:” but I’m not getting any output

hmm…I pasted that code in place of the existing HttpPostRawNode.cs and the right output pin still isn’t labelled and doesn’t output anything :(

I just renamed woei’s code as old-HttpPostRawNode.cs and saved that code as HttpPostRawNode.cs, did I miss a step? I kept the same .csproj and didn’t touch anything in the bin and properties folders…

create new template (ctrl-click on template (value), put any name) and paste whole code in there

@zz it’s okey how you did it.
with the code elias posted you should see the response pin, which you do.

the issue with no data on the pin is actually something else. there’s really no response coming back. but i couldn’t figure out why exactly.

maybe some web wizzard knows what exactly you have to post to a server to get a response. just sending some string i get nothing back…

yeah it’s weird how the HEADER comes back but not the CONTENT/BODY/RESPONSE/WhateverIt’sCalled…aren’t they sent simultaneously?

I know that in my specific case (which may not be helpful), the header information coming out of the node is:

Pragma: no-cache
Connection: close
Access-Control-Max-Age: 0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE
Access-Control-Allow-Headers: Content-Type
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Content-Type: application/json
Expires: Mon, 1 Aug 2011 09:00:00 GMT

but the full plaintext response I see in a sniffer is:

HTTP/1.1 200 OK
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Expires: Mon, 1 Aug 2011 09:00:00 GMT
Connection: close
Access-Control-Max-Age: 0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE
Access-Control-Allow-Headers: Content-Type
Content-type: application/json

[{"error":{"type":101,"address":"","description":"link button not pressed"}}]({"error":{"type":101,"address":"","description":"link button not pressed"}})

note: the ‘[{“error”:{“type”:101,“address”:"",“description”:“link button not pressed”}}]({“error”:{“type”:101,“address”:"",“description”:“link button not pressed”}})’ json is a good sign, and exactly what I’m looking to receive, so no problem there

don’t know if that helps at all, but there you go

request.KeepAlive = true;

was causing troubles

here we go

HttpPostRaw.zip (88.4 kB)

no luck, still getting all the header information but no output on the body

{img src = “http://i.imgur.com/Ieuy01B.png”}

Would this have anything to do with the header info(s) being outputted as a string but the body coming out as RAW?

Also, oddly, despite the header coming through it marks it as failed…

ok next attempt :)

seems as if the content-length property doesn’t need to be set - so modified that part that it can deal with both cases. oh and open up a tty node if your requests fail. should give you a little more info what’s going on. i’ve also added a new enum to the node “Method”, where you can select whether it’s a GET/POST/etc. request method. so be careful to set that one to POST in your case.

HttpPostRaw_1.zip (3.4 kB)

it…

it…

it…

{img src = “http://i.imgur.com/tAJAfq9.gif”}

IT WORKS!!!

{img src = “http://i.imgur.com/WJhbYoa.png”}

thanks so much antokhio & Elias & woei !!

next up I have to send some PUT commands but I have a good feeling those will work out fine!

Good to read it works :)

Would be nice if you can this a contribution, so we can add the Philips Hue to our “up and running” hardware collection, or at least post a patch. :)