+2
Martin Lang 2 weeks ago in iRidium Script • updated by Aleksandr Romanov (CTO) 2 days ago 12

Is anyone here having a ready made script for a TCP_CUSTOM_SERVER that acts like a small HTTP-Server?


I thought i ask before i start writing my own...


Thx!


Martin

+1

here's a snippet i just wrote in a few minutes (not good coding), it is working you see the requested file/command in the log and you get a message back to the browser. the only thing i couldn't figured out was how to force the HTTPServer to send out the data to the client without disconnecting and reconnecting them. whats the way to disconnect a client that is connected to a CUSTOM_TCP_SERVER? 


var HTTPServer = IR.CreateDevice(IR.DEVICE_CUSTOM_SERVER_TCP, "HTTPServer",
   {Port: 80, MaxClients: 3});
var httpRequestMessage = "";
IR.AddListener(IR.EVENT_ONLINE,HTTPServer,function()
{
IR.Log("*** HTTP Server online");
});
IR.AddListener(IR.EVENT_OFFLINE,HTTPServer,function()
{
IR.Log("*** HTTP Server offline");
});
IR.AddListener(IR.EVENT_RECEIVE_TEXT, HTTPServer, function(text)
{
  
  httpRequestMessage = httpRequestMessage + text;
  
  var httpRequestEND = httpRequestMessage.indexOf('\r\n\r\n');
  
  var GETstartpos = httpRequestMessage.indexOf('GET ');
  
  if ((httpRequestEND != -1) && (GETstartpos != -1)) {
    
   httpRequestMessage = httpRequestMessage.slice(GETstartpos + 5);
   
   var GETendpos = httpRequestMessage.indexOf(' ');
   
   var httpRequest = decodeURIComponent(httpRequestMessage.slice(0,GETendpos));
   
   IR.Log("*** HTTP Request: " + httpRequest);
   
   httpRequestMessage = "";
   
   switch (httpRequest) {
   
      case 'favicon.ico' :
         HTTPServer.Send(['HTTP/1.1 302 Found\n']);
         HTTPServer.Send(['Location: http://www.iridiummobile.net/favicon.ico\n\n']);
      break;
      default:
         HTTPServer.Send(['HTTP/1.0 200 OK\n']);
         HTTPServer.Send(['Content-Type: text/plain\n\n']);
         HTTPServer.Send(['OK you requested: ' + httpRequest]);
      break;
      } 
   
   IR.SetTimeout(200,function()
   {
   HTTPServer.Disconnect();
   });
   
   IR.SetTimeout(400,function()
   {
   HTTPServer.Connect();
   });
   
   }
 
 });



So maybe the iRidium Team can help out with the Sending flush to the client!?


Ciao

 Martin

Thank you Martin! How to use it? What can we send to it and what to do then?

hi,


you see the switch-part? in that part you can do anything you want like:


   switch (httpRequest) {
   
      case 'favicon.ico':
         HTTPServer.Send(['HTTP/1.1 302 Found\n']);
         HTTPServer.Send(['Location: http://www.iridiummobile.net/favicon.ico\n\n']);
      break;
      case 'command1':
         IR.GetDevice("HDL-BUS Pro Network (UDP)").Set("Curtain1:Curtain Up/Stop/Down",1);
         IR.GetDevice("KNX Router (KNXnet/IP)").Set(1,"red"); 
         IR.GetDevice("BAOS").Set("BAOS Command",100);
         IR.GetDevice("Global Cache").Set("POWER ON","");
         IR.GetDevice("Sonos").Set("Play","");
         HTTPServer.Send(['HTTP/1.0 200 OK\n']);
         HTTPServer.Send(['Content-Type: text/plain\n\n']);
         HTTPServer.Send(['Your command was: ' + httpRequest]);
      break;
      default:
         HTTPServer.Send(['HTTP/1.0 200 OK\n']);
         HTTPServer.Send(['Content-Type: text/plain\n\n']);
         HTTPServer.Send(['OK you requested: ' + httpRequest]);
      break;
      } 

using it with a device that can make a http request, like a browser:

http://<IP_OF_IRIDIUMSERVER/command


like


http://192.168.1.100/command1


then you get back a short message "Your command was: command1" and all the action within the 'command1' switch part will be executed. But thats a really simple example, you can do whatever you want within your JS. you can send back html code too by changing the content-type to text/html.


Ciao

 Martin


Great job, it works! I've made an improvement which helps anyone to use it without getting to script source. You just send drivername, channel and value and it works!


//Control part: send http://[server address]/[driver name],[channel name],[value]
//ex. http://127.0.0.1/ModbusTCP,Channel1,1 
   part = httpRequest.split(",");
   IR.Log("payload: " +part[0] +" " +part[1] +" " +part[2]);
   IR.GetDevice(part[0]).Set(part[1], part[2]);


Here is the project example:

http_server_strings_control_example.sirpz


More improvements are welcome!

I just want to have some time and merge it with http send solution here: http://support.iridiummobile.net/topics/12577-http-command-with-added-dynamic-value-and-no-script/


Then we are going to have a full featured http send-receive example, which people without any script knowledge whould be ableto use

yes, but the iRidium team should please jump in and tell me how to finish the client connection (flushing out the buffered data) without disconnecting and reconnecting the driver itself. it works, but thats a little buggy to me.

Maybe you must join data to one request.

and

HTTP/1.0 defines the octet sequence CR LF as the end-of-line marker for all protocol elements
except the Entity-Body (see Appendix B for tolerant applications). The end-of-line marker
within an Entity-Body is defined by its associated media type, as described in Section 3.6.
HTTPServer.Send(['HTTP/1.0 200 OK\r\nConnection: keep-alive\r\nContent-Type: text/plain\r\n\r\nOK you requested: ' + httpRequest]);

use Wireshark to understand what happens


http://www.cs.columbia.edu/~jae/3157/files/overview-sockets-http.pdf
HTTP 1.1 is better for persist connections

Tried it, doesn't make any changes. Looks like the data is buffered and not sent out directly. When you delete the part:

IR.SetTimeout(200,function()
   {
   HTTPServer.Disconnect();
   });
  
   IR.SetTimeout(400,function()
   {
   HTTPServer.Connect();
   });

You get no answer in the browser until you restart the iridiumserver or upload a new project. On a normal Webserver, the Server closes the connection to the client when the data was sent out. So, how to close a Client connection?

Checked it again with wireshark. The iRidium Server does not send out any data when you call the .Send Method, until you kill the device. Thats a bug i think. iRidium Team?

This topic is discussed by integrators. The Iridium team does not recommend such a solution (it is extremely
unsafe) and requires a good understanding of network interaction, so we do not participate in this discussion.

i understand your side for a http server. you don't have to comment.


but to use the normal tcpserver, why is the .send method not working?

Martin, it works! Try create empty project and send date from web-interface:


var TCPConnection = IR.CreateDevice(IR.DEVICE_CUSTOM_SERVER_TCP, "TCPConnection", "", 55555, 5, IR.BACKGROUND_OFF);
var string = 0;


IR.AddListener(IR.EVENT_RECEIVE_TEXT, TCPConnection, function(text, client_id,  host, port, host_ip, host_port) {
   if(text == "Answer")
      IR.Log("EVENT_RECEIVE_TEXT " + text);
});


function fnStr(in_Type, in_Name, in_Value) {
   IR.Log("Set string to " + in_Value)
   string = in_Value;
}



function fnSend(in_Type, in_Name, in_Value) {
   IR.Log("Send text " + string);
   TCPConnection.Send([string]);
}