TriplePlay Server (HTTP/JSON)
I'm hoping I can get some help here, as I am a fairly new AMX programmer.
I have a JSON controlled server, and I am trying to figure out how to use the commands given to me in the API.
All the commands are HTTP (made to be entered into a web browser)
After speaking with Tech Support, I am told to just use an IP_CLIENT_OPEN command and then send the string over port 80.
I am hoping to get some second opinions, and maybe a little help if at all possible!
Here is one of the commands given to me in the API:
http://<serverIP>/triplecare/JsonRpcHandler.php?
call={"jsonrpc":"2.0","method":"Reboot","params":[1]}
Any help at all is greatly appreciated!
Thanks!
I have a JSON controlled server, and I am trying to figure out how to use the commands given to me in the API.
All the commands are HTTP (made to be entered into a web browser)
After speaking with Tech Support, I am told to just use an IP_CLIENT_OPEN command and then send the string over port 80.
I am hoping to get some second opinions, and maybe a little help if at all possible!
Here is one of the commands given to me in the API:
http://<serverIP>/triplecare/JsonRpcHandler.php?
call={"jsonrpc":"2.0","method":"Reboot","params":[1]}
Any help at all is greatly appreciated!
Thanks!
0
Comments
One might surmise that the steps are 1) send the IP_Client_Open() command then immediately send the string I need to send. But this is not the case.
In the real world, It happens this way.
1) Client asks Webserver to open a connection on its port 80.
2) Webserver responds by opening a socket between the Web Server's port 80 and your computer.
3) You are then supposed to know what to send to the webserver to get what you want.
it's step 3 that seems to confuse Netlinx programmers.
Bear in mind, the time from when you issue the ip_client_open() command and when you get the response from the web server that it has opened the port for you to use, is literally thousands of CPU clock ticks. Your entire code could have ran in that span of time.
So, bear in mind that when you issue the ip_client_open command - you are now waiting for a response.
The result of that response comes in the form of a data_event>Online:
Once you've issued the IP_C_O command you now need to watch for a response over in the DATA_EVENT[whatever D:P:S] you opend IP_C_O.
When you see that the port is open, you now send your request to the server.
so here's what that might look like...
[/SIZE][/FONT][/COLOR][COLOR=#111111][FONT=Arial][SIZE=12px]DEFINE_DEVICE[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px]dvMy_IP = 0:3:0[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px]DEFINE_EVENT[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px]button_event[TP,1]{ // do the thing:[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] push:{[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] stack_var sinteger result[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] result=ip_client_open(dvMy_IP.port,'<URL or IP of SERVER>',< IP PORT>,TCP);[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] send_string 0, " 'tried to open web server. result was',itoa(result)";[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] } // push[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] } //b_e[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px]data_event[dvMy_IP]{[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] online:{ // this event fires when the web server opens the port for you[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] send_string dvMy_IP,'whatever string you need to send to the server - usually a "GET" comand'[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] send_string 0, " 'web server port opened' ";[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] }[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] string:{[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] // data.text will be the response from the server.[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] send_string 0, " 'web server said:',data.text ";[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] }[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] offline:{[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] // will let you know when the web server hangs up.[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] send_string 0, " 'web server port closed' ";[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] }[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] onerror:{[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] // reports any errors.[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] }[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] }[/SIZE][/FONT][/COLOR][COLOR=#111111][FONT=Arial][SIZE=12px]DEFINE_DEVICE[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px]dvMy_IP = 0:3:0[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px]DEFINE_EVENT[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px]button_event[TP,1]{ // do the thing:[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] push:{[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] stack_var sinteger result[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] result=ip_client_open(dvMy_IP.port,'<URL or IP of SERVER>',< IP PORT>,TCP);[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] send_string 0, " 'tried to open web server. result was',itoa(result)";[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] } // push[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] } //b_e[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px]data_event[dvMy_IP]{[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] online:{ // this event fires when the web server opens the port for you[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] send_string dvMy_IP,'whatever string you need to send to the server - usually a "GET" comand'[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] send_string 0, " 'web server port opened' ";[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] }[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] string:{[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] // data.text will be the response from the server.[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] send_string 0, " 'web server said:',data.text ";[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] }[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] offline:{[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] // will let you know when the web server hangs up.[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] send_string 0, " 'web server port closed' ";[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] }[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] onerror:{[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] // reports any errors.[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] }[/SIZE][/FONT][/COLOR] [COLOR=#111111][FONT=Arial][SIZE=12px] }[/SIZE][/FONT][/COLOR][COLOR=#111111][FONT=Arial][SIZE=12px]Maybe I don't understand the example completely, but I do have multiple commands to send to the same server, so is using the DATA_EVENT still my best option?
I can't nest the DATA_EVENT inside the PUSH of the button event, or am I missing something?
This is my current chunk of code to do a channel select, please keep in mind how green I am!
Code:
DEFINE_DEVICE dvTriplePlay = 0:2:0 dvIP_TV = 10001:3:0 #IF_NOT_DEFINED dvTP dvTP = 10001:1:0 #END_IF DEFINE_CONSTANT CHAR ServerIP[] = '10.3.18.??' INTEGER nIPPort = 80 DEFINE_VARIABLE VOLATILE INTEGER uChannel[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, 17,18,19,20,21,22,23,24,25,26,27,28,29, 30,31,32,33,34,35,36,37,38} VOLATILE INTEGER uTVID[] = {1,2,3,4,5} DEFINE_START DEFINE_EVENT BUTTON_EVENT[dvIP_TV,uChannel] // Channel Select { PUSH: { IP_CLIENT_OPEN(dvTriplePlay.PORT,ServerIP,nIPPORT,IP_TCP) WAIT 100 { SEND_STRING 0, "'http://',ServerIP,'/triplecare/JsonRpcHandler.php?call={"jsonrpc":"2.0", "method":"SelectChannel","params":"[',uTVID,',',uChannel,']"'" } } RELEASE: { WAIT 100 { IP_CLIENT_CLOSE(dvTriplePlay.PORT) } } }HTTP communication is kinda like ordering a pizza. It's asynchronous...
With your method, you'd
1) call and order the pizza - (ip_client_open)
2) some time later you hear a strange doorbell ringing for no apparent reason
3) you go to the door exactly 30 minutes later - toss the money out the door and wonder where the heck your pizza is.
The pizza delivery process is asynchronous. It'd be better to do it this way:
1) Order the pizza (send the IP_client_open command)
2) get your money read and wait for the doorbell (The doorbell detector is DATA_EVENT[]>Online:
3) when you hear the doorbell - open the door and hand the driver the money This is the send_string 'your HTTP command Here> in the DATA_EVETN>Online:
4) The driver hands you the delicious pizza (this is in the DATA_EVENT[]>String: the pizza is data.text)
the secret is DATA_EVENT is always waiting to hear the doorbell and will tell you when it rings.
Edited to add...
Also, I'm not sure if this code is just pseudo-code for the example or if this is your real code.
IP_CLIENT_OPEN(dvTriplePlay.PORT,ServerIP,nIPPORT,IP_TCP) WAIT 100 { [SIZE=12px][B] SEND_STRING 0, "'http://',ServerIP,'/triplecare/JsonRpcHandler.php?call={"jsonrpc":"2.0", "method":"SelectChannel","params":"[',uTVID,',',uChannel,']"'"[/B][/SIZE] } }But, if it is the real code then a couple things:
1) You assigne dvTriplePlay as 0:2:0 // I'd avoid both port 1 and port 2 and start with port 3. 0:3:0 1 is reserved and port 2 is kinda in the zone where, while it's not official, I've found occasionally traffic happens there that is obviously 'under the hood' Just start with port 3 and up and you'll be good.
2) you don't send the string to '0' You'd send it to dvTriplePlay.
and now 3) I don't know the exact nature of the message you're sending but from my working with the TriplePlay, it's just an HTTP message. That is a bit more complicated in netlinx. When in your browser you type http://www.whatever.com/php?<some php stuff here> then hit return - a lot more happens than it just sending a string to port 80 on the server. Basically the same thing happens with your computer. it...
1) requests a socket on port 80 of the server at address: www.whatever.com
2) if/when the server opens the port and lets the computer know it's open, the browser then sends a preamble with information like "what HTML version I am speaking, What kind of browser I am, My ipaddress, and/or a buch of stuff" Once the preamble is sent, the message is sent via the "GET" command. The GET will look like this:
GET <the stuff aftere the www.whatever.com portion of the URL>
This block of stuff ends with 2 sets of CR/LF ($13,$10)
So, you'll need to break apart your html command like this. My advice is get WireShark if you don't have it and scrape the conversation between your web browser and the server and mimic that.
#include 'json-builder' #include 'http' /** * Send a reset command to a TriplePlay server. * * @param ip the IP address (or resolveable hostname) of the server * @return the HTTP request ID */ define_function long tripleplay_reset(char ip[]) { stack_var json_item rpc_call[3] json_set_str(rpc_call, 'jsonrpc', '2.0') json_set_str(rpc_call, 'method', 'Reboot') json_set_value(rpc_call, 'params', '[1]') return http_get("'http://', ip, '/triplecare/JsonRpcHandler.php?call=', json_stringify(rpc_call)") }This will take care of all the low level socket connectivity and HTTP protocol side of things so you can just focus on the device you're trying to control.
And yes, that is indeed the string I am sending, so it is HTTP, despite what tech support told me. (Don't remember who exactly I spoke with, but I was told just to send that HTTP address out on port 80 and it was the same as entering it into the browser, apparently I have been mislead.)
So, the only thing I don't understand is, I have multiple commands to send to the server based on user presses (i.e. channel changes,) so how would I separate those using the DATA_EVENT online? I obviously don't understand it completely, but how would I distinguish the DATA-EVENT online sending out the command for say channel up over channel down?
I will indeed grab the http library and JSON builder and see where I can get. Thanks!
As far as time sensitive, I'll be heading to the site tomorrow to hopefully begin testing and/or scraping strings to go that route.
[USER="1623"]ericmedley[/USER] , you say you've had some experience with TriplePlay? Any chance you'd be willing to share the code? I know that's asking a lot, but I would appreciate it greatly!
Thank you all again for your help and patience!
Okay, here's a bare-bones example to illustrate how one could differentiate for the different commands. Bear in mind that you'd need to do a few things to handle the fact that in theory the user could push a button midway through dealing with the previous command being sent (client mashing buttons because seemingly nothing is happening., etc...) Plus there's a few things you should do in the middle to deal with bad connections/no connections/etc... This should give you an idea of one way to handle your question, however.
define_device dv_WebClient = 0:03:0 dvTP = 10001:01:0 define_constant integer MyButtons[]={101,102,103} // thre TP buttons for three possible commands being sent. define_variable volatile integer Pending_Command; define_event button_event[dvTP,MyButtons]{ push:{ stack_var integer button_id; button_id=get_last(MyButtons); Pending_Command=button_id; ip_client_open(dv_WebClient.port,'<IP Address of server>',80,TCP) } // push } // b_e data_event[dv_WebClient]{ online:{ // the server opened the port - send command switch(Pending_Command){ case 1:{//commonad one send_string dv_WebClient,'the string for command one...' } case 2:{//commonad two send_string dv_WebClient,'the string for command two...' } case 3:{//commonad three send_string dv_WebClient,'the string for command three...' } } // switch Pending_Command=0; // clear out for next command. } // online: string:{ // data.text will be the response to whatever. } // stirng } // d_evolatile char php_tag_string[85]; volatile char MyBig_String[200] volatile char current_Location[50] php_tag_string=" '/triplecare/JsonRpcHandler.php?call={"jsonrpc":"2.0","method":"Reboot","params":[1]' " MyBig_String="'GET ',php_tag_string,' HTTP/1.1',$0d,$0A, 'Connection: Close',$0d,$0A, 'User-Agent: Mozilla/4.0 ', '(compatible; NetLinx 3.12.335;AMX NetLinx)',$0d,$0A, 'Host: ',current_Location " // current location is my URL send_string dvWebClient,"MyBig_String,13,10,13,10";No offense [USER="1623"]ericmedley[/USER], but I'm gonna cheat and use [USER="6496"]PhreaK[/USER] 's example, I'm having a little bit easier of a time grasping his example for my purposes.
This is where I am at so far, although as you mentioned, Eric, I do need to devise a way to keep the button mashers satisfied (also the possibility that someone will inevitably select a tv at more than one panel at a time.)
But I feel I am going in the right direction, finally.
Any comments/suggestions/critiques/snide remarks are all appreciated!
PROGRAM_NAME='TriplePlay_RPC' #include 'JSON_Builder' #include 'HTTP' DEFINE_DEVICE dvTP1_3PLAY = 10001:3:0 // Touchpanel TV Select dvTP2_3PLAY = 10002:3:0 // Touchpanel TV Select dvTP3_3PLAY = 10003:3:0 // Touchpanel TV Select dvTP4_3PLAY = 10004:3:0 // Touchpanel TV Select dvTP5_3PLAY = 10005:3:0 // Touchpanel TV Select dvTP6_3PLAY = 10006:3:0 // Touchpanel TV Select dvTP7_3PLAY = 10007:3:0 // Touchpanel TV Select dvTP8_3PLAY = 10008:3:0 // Touchpanel TV Select dvTP9_3PLAY = 10009:3:0 // Touchpanel TV Select dvTP10_3PLAY = 10010:3:0 // Touchpanel TV Select dvTP11_3PLAY = 10011:3:0 // Touchpanel TV Select dvTP12_3PLAY = 10012:3:0 // Touchpanel TV Select dvTP13_3PLAY = 10013:3:0 // Touchpanel TV Select dvTP14_3PLAY = 10014:3:0 // Touchpanel TV Select dvTP15_3PLAY = 10015:3:0 // Touchpanel TV Select dvTP1_CH = 10001:4:0 // Touchpanel Channel Select dvTP2_CH = 10001:4:0 // Touchpanel Channel Select dvTP3_CH = 10001:4:0 // Touchpanel Channel Select dvTP4_CH = 10001:4:0 // Touchpanel Channel Select dvTP5_CH = 10001:4:0 // Touchpanel Channel Select dvTP6_CH = 10001:4:0 // Touchpanel Channel Select dvTP7_CH = 10001:4:0 // Touchpanel Channel Select dvTP8_CH = 10001:4:0 // Touchpanel Channel Select dvTP9_CH = 10001:4:0 // Touchpanel Channel Select dvTP10_CH = 10001:4:0 // Touchpanel Channel Select dvTP11_CH = 10001:4:0 // Touchpanel Channel Select dvTP12_CH = 10001:4:0 // Touchpanel Channel Select dvTP13_CH = 10001:4:0 // Touchpanel Channel Select dvTP14_CH = 10001:4:0 // Touchpanel Channel Select dvTP15_CH = 10001:4:0 // Touchpanel Channel Select dvTriplePlay = 0:3:0 DEFINE_CONSTANT CHAR IP[] = '10.3.18.100' //Tripleplay Server IP DEFINE_VARIABLE dev dvTP_3PLAY[] = {dvTP1_3PLAY,dvTP2_3PLAY,dvTP3_3PLAY,dvTP4_3PLAY,dvTP5_3PLAY,dvTP6_3PLAY, dvTP7_3PLAY,dvTP8_3PLAY,dvTP9_3PLAY,dvTP10_3PLAY,dvTP11_3PLAY,dvTP12_3PLAY, dvTP13_3PLAY,dvTP14_3PLAY,dvTP15_3PLAY} dev dvTP_CH[] = {dvTP1_CH,dvTP2_CH,dvTP3_CH,dvTP4_CH,dvTP5_CH,dvTP6_CH,dvTP7_CH, dvTP8_CH,dvTP9_CH,dvTP10_CH,dvTP11_CH,dvTP12_CH,dvTP13_CH,dvTP14_CH, dvTP15_CH} VOLATILE INTEGER nCH_Select[38] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, // IPTV Channel Numbers 17,18,19,20,21,22,23,24,25,26,27,28,29, 30,31,32,33,34,35,36,37,38} VOLATILE INTEGER nTV_sELECT[] = {1,2,3,4,5} // STB ID/TV ID VOLATILE INTEGER uTVID VOLATILE INTEGER uChannel define_function long tripleplay_reset(char ip[]) { // Reset the Server stack_var json_item rpc_call[3] json_set_str(rpc_call, '"jsonrpc"', '"2.0"') json_set_str(rpc_call, '"method"', '"Reboot"') json_set_value(rpc_call, '"params"', '[1]') return http_get("'http://',ip,'/triplecare/JsonRpcHandler.php?call={',json_stringify(rpc_call),'}'") } define_function long tripleplay_tv_power_on(char ip[]) { // TV Power ON stack_var json_item rpc_call[3] json_set_str(rpc_call, '"jsonrpc"', '"2.0"') json_set_str(rpc_call, '"method"', '"PowerOnTv"') json_set_value(rpc_call, '"params"', '') return http_get("'http://',ip,'/triplecare/JsonRpcHandler.php?call={',json_stringify(rpc_call),'[',uTVID,']}'") } define_function long tripleplay_tv_power_off(char ip[]) { // TV Power OFF stack_var json_item rpc_call[3] json_set_str(rpc_call, '"jsonrpc"', '"2.0"') json_set_str(rpc_call, '"method"', '"PowerOffTv"') json_set_value(rpc_call, '"params"', '') return http_get("'http://',ip,'/triplecare/JsonRpcHandler.php?call={', json_stringify(rpc_call),'[',uTVID,']}'") } define_function long tripleplay_channel_select(char ip[]) { // IPTV Channel Select stack_var json_item rpc_call[3] json_set_str(rpc_call, '"jsonrpc"', '"2.0"') json_set_str(rpc_call, '"method"', '"SelectChannel"') json_set_value(rpc_call, '"params"', '') return http_get("'http://',ip,'/triplecare/JsonRpcHandler.php?call={', json_stringify(rpc_call),'[',uTVID,',',uChannel,']}'") } DEFINE_EVENT BUTTON_EVENT[dvTP_3PLAY,nTV_sELECT] { PUSH: { uTVID = GET_LAST(nTV_sELECT) // Select a TV } } BUTTON_EVENT[dvTP_CH,nCH_Select] { PUSH: { uChannel = GET_LAST(nCH_Select) // Select a Channel } RELEASE: { TRIPLEPLAY_TV_POWER_ON(IP) // TV Power ON WAIT 10 { TRIPLEPLAY_CHANNEL_SELECT(IP) // Change the channel } } }According to the API given to me from TriplePlay, it is indeed port 80 for HTTP, and 443 for HTTPS. Not sure if it supports COMETD or not. Based on what I have seen so far, I doubt it.
None taken! There are many ways to go about this. Actually, the example I gave was not all that practical in a 'real coding" sense and was intended to illustrate a working method with the full intention of you crafting your own way. Phreak's method is perfect and a good example to follow.
Edit: Fixed it! Thank you so much for all of your help everyone, I could not have gotten this system functioning without your assistance!
http_post("'http://10.0.9.203:5005/House/favorite/KPLU'", request)