Home AMX User Forum AMX General Discussion

Clearly I need a REST

As an Accidental Programmer I sometimes run across a problem that requires knowledge, rather than brute force, and I think this is one of those times.

I have one of the little Roku media streamers, which has external control support (found here):

http://sdkdocs.roku.com/display/sdkdoc/External+Control+Guide

I can establish a connection with my master on the correct port, but I just can't get my commands acted upon. I've tried various iterations of what's in the examples, but it seems (for example) a Home button emulation should be sent as (after a successful connection) POST /keypress/Home

At least I think so. If anyone can offer an educated opinion as to how the string needs to actually be formatted I'd appreciate it. All the online help examples involve various.cryptic.libraries that I don't have the depth to understand.

Comments

  • ericmedleyericmedley Posts: 4,177
    Jeff,
    Can you post the code with your string build too? Might help.
    E
  • Sure! Through the course of testing and head beating I've ended up reducing it to the super simple:
    DEFINE_DEVICE 
    
        dvRoku	= 0:3:0
        vdvRoku = 33001:1:0
    
    DEFINE_EVENT
    
    DATA_EVENT [dvRoku]
    {
        ONLINE: SEND_STRING dvRoku, 'POST /keypress/Home'  // 'POST /keypress/Home HTTP/1.1' 
    }
    
    CHANNEL_EVENT [vdvRoku,1]
    {
        ON: IP_CLIENT_OPEN (dvRoku.Port,'192.168.1.20',8060,1)
    }	
    
    

    Thanks! I have the Roku up on the TV and I'm not on the Home screen, so I would know if this command worked.
  • nickmnickm Posts: 152
    Here's a snippet of how an HTTP header should be formed. This particular example is from my BoxeeBox control module which uses the same RESTful scheme (though different commands)
    DEFINE_FUNCTION AddHTTPGet(CHAR cShortURI[]) {
    	//---Add an HTTP GET request to BBox.Comm.cQue
    	//---To be instantiated by SendQue above
    	
    	STACK_VAR CHAR cURLString[512]
    	STACK_VAR CHAR cHeader[512]
    	
    	cURLString = "'/',cShortURI"
    	DebugString(4,"'Add to Que: HTTP://',BBox.Comm.cIPAddress,cURLString")
    	
    	cHeader = "'GET ',cURLString,' HTTP/1.1',$0D,$0A"
    	cHeader = "cHeader,'Host: ',BBox.Comm.cIPAddress,$0D,$0A"
    	cHeader = "cHeader,'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64,rv:13.0) Gecko/20100101 Firefox/13.0.1',$0D,$0A"
    	cHeader = "cHeader,'Accept: text/html,application/xhtml+xml,application/xml;q=0.9*/*;q=0.8',$0D,$0A"
    	cHeader = "cHeader,'Accept-Language: en-us;q=0.5',$0D,$0A"
    	cHeader = "cHeader,'Accept-Encoding: gzip,deflate',$0D,$0A"
    	cHeader = "cHeader,'Connection: keep-alive',$0D,$0A,$0D,$0A"
    	
    	BBox.Comm.cQue = "BBox.Comm.cQue,cHeader,$0B,$0B"
    	DebugString(3,"'AddHTTPGet : ',cShortURI")
    }
    

    You can find the entire module here: https://github.com/nickmil/BoxeeBox

    As you can see, there is a lot of information required of an HTTP header. A tool that will come in quite handy as you play more with RESTful APIs is the POSTman REST client. It's a Chrome app that breaks down everything that happens in a REST request and response.
  • Yup, that looks quite different to what I have.
  • nickmnickm Posts: 152
    The equivalent here would be your '/keypress/home' string.
  • nickm,

    I replaced your GET with POST in the function and gave it a try with my Home command and it worked, thanks. I guess the Roku document assumes a level of http/REST knowledge that I don't have.

    Cheers!
  • PhreaKPhreaK Posts: 966
    If you want a quick and painless intro to REST there's a great 15 minute talk on the Google Developers channel.
  • Ah, cool, I'll check that out. Thanks!
  • DHawthorneDHawthorne Posts: 4,584
    You don't necessarily need all that header information ... especially the "CONNECTION: keep_alive field." In fact, that one might even be hurting you by forcing the connection to stay open after it's finished. I was stunned how much more responsive a weather module worked when I replaced that with "CONNECTION: close." What I do on all my HTTP mods is to start with a full-blown header, then take stuff out one at a time until it breaks. Then I know I have it reduced to what is really needed to make it work.
  • nickmnickm Posts: 152
    DHawthorne wrote: »
    You don't necessarily need all that header information ...

    Agreed. There is a lot of header information that typically isn't needed in the scope of devices/services we are communicating with.
  • viningvining Posts: 4,368
    Here's an example of what I would observe in WireShark between my PC and a particular device:
    SEND_STRING dvJSON,"'POST /jsonrpc.js HTTP/1.1',STR_CRLF"; 
    		    SEND_STRING dvJSON,"'Host: ',sJSON.sPlayer.cIP,':',itoa(sJSON.sPlayer.nPort),STR_CRLF";
    		    SEND_STRING dvJSON,"'User-Agent: Netlinx',STR_CRLF";
    		    //SEND_STRING dvJSON,"'User-Agent: User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:27.0) Gecko/20100101 Firefox/27.0',STR_CRLF";
    		    SEND_STRING dvJSON,"'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',STR_CRLF"; 
    		    SEND_STRING dvJSON,"'Accept-Language: en-us',STR_CRLF";
    		    SEND_STRING dvJSON,"'Accept-Encoding: gzip, deflate',STR_CRLF";
    		    SEND_STRING dvJSON,"'X-Requested-With: XMLHttpRequest',STR_CRLF";
    		    SEND_STRING dvJSON,"'Content-Type: application/x-www-form-urlencoded; charset=UTF-8',STR_CRLF";
    		    SEND_STRING dvJSON,"'Referer: http://',sJSON.sPlayer.cIP,':',itoa(sJSON.sPlayer.nPort),'/',STR_CRLF";
    		    SEND_STRING dvJSON,"'Content-Length: ',itoa(length_string(sJSON.sPlayer.cFullCmd)),STR_CRLF";
    		    SEND_STRING dvJSON,"'Cookie: Squeezebox-player=',fnEncodeURL(sJSON.sPlayer.cStrMAC),'; Squeezebox-expandPlayerControl=false; ',
    		    'Squeezebox-expanded-MY_MUSIC=1; Squeezebox-expanded-RADIO=0; Squeezebox-expanded-PLUGIN_MY_APPS_MODULE_NAME=1; ',
    		    'Squeezebox-expanded-FAVORITES=0; Squeezebox-expanded-PLUGINS=0; Squeezebox-playersettings=null; ',
    		    'Squeezebox-advancedsettings=settings/server/debugging.html%3F; Squeezebox-expanded-updatePlugins=1; ',
    		    'Squeezebox-expanded-activePlugins=1; Squeezebox-expanded-inactivePlugins=1; Squeezebox-expanded-otherPlugins0=1; ',
    		    'Squeezebox-expanded-otherPlugins1=1; __utma=124789194.27251913.1391382619.1391382619.1391382619.1; ',
    		    '__utmz=124789194.1391382619.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)',STR_CRLF";
    		    SEND_STRING dvJSON,"'Connection: keep-alive',STR_CRLF";
    		    SEND_STRING dvJSON,"'Pragma: no-cache',STR_CRLF";
    		    SEND_STRING dvJSON,"'Cache-Control: no-cache',STR_CRLF";
    		    SEND_STRING dvJSON,"STR_CRLF";
    		    SEND_STRING dvJSON,"sJSON.sPlayer.cFullCmd,STR_CRLF";
    
    and then as Dave mentioned I would get it working using everything that I observed being used and then comment out a line or more at a time and test. In the end all I ended up needing was:
    SEND_STRING dvJSON,"'POST /jsonrpc.js HTTP/1.1',STR_CRLF"; 
    		    SEND_STRING dvJSON,"'Host: ',sJSON.sPlayer.cIP,':',itoa(sJSON.sPlayer.nPort),STR_CRLF";
    		    SEND_STRING dvJSON,"'Referer: http://',sJSON.sPlayer.cIP,':',itoa(sJSON.sPlayer.nPort),'/',STR_CRLF";
    		    SEND_STRING dvJSON,"'Content-Length: ',itoa(length_string(sJSON.sPlayer.cFullCmd)),STR_CRLF";
    		    SEND_STRING dvJSON,"STR_CRLF";
    		    SEND_STRING dvJSON,"sJSON.sPlayer.cFullCmd,STR_CRLF";
    
Sign In or Register to comment.