Your comments

any update on this driver? 


I would be happy to maintain it as a server driver and sign any necessary NDA to protect any Intellectual Properties that maybe necessary 



So i have spend a couple of hours today with this issue, and also trying to determine is i might have some alternative options. 


The objective is simple, I need to have an external service trigger a variable/tag on the iridium server. I am not locked to a HTTP server implementation; I was looking at the potential to use MQTT as an option - have not had any luck on the back channel.


In any case, my HTTP server code works only when i force close the device; but this upsets the sender as it may not have had a response back with a HTTP 200/400 etc in the session.


I have purchased the Iridium Gate; does this open any additional options, as by design this device sends JSON and accepts JSON from the internet hosted services - exactly what i need!


cheers

Damian

Not sure this is an appropiate response here, but I have stopped using the Iridium Sonos driver due to been on the Sonos beta and this driver essentially never working for me.


On my Iridium server i am running an opensource Node application called Node-Sonsos-Http-API (https://github.com/jishi/node-sonos-http-api/) and on my Iridium server i have created a basic module, which leverages the application to do all the UPNP work. So far this has been running solid for 8 months, and I am currently running Sonos 8.0.371245110 


I have not converted all the functions to this model, but the following will show the basic framework I use, and is maintainable


Apologies if this is inappropriate here, and please delete if needed


Sonos_API = function(DriverName)
{
   //-------------------------------------------------------
   // Driver Data
   //------------------------------------------------------- 
   this.DriverName = DriverName;
   this.device;
   this.Online = false;
   var that;
   
   var deviceList = [];
   this.error = false; // Error flag
  
   // Log Levels
   // 0 = No logging 
   // 1 = Information
   // 2 = Verbose
   // 3 = Debug
   var loggingLevel = 3;
   //-------------------------------------------------------
   // Device Initialization
   //------------------------------------------------------- 
   function initialization() // Initialization method of the class instance
   {
 
      //this.device= IR.CreateDevice(IR.DEVICE_CUSTOM_HTTP_TCP, this.DriverName, {Host: "172.16.1.5", Port: 5005, ReceiveWaitTimeMax: 5000}); // Defining the indicator of the base driver by its name 
      this.device= IR.GetDevice(this.DriverName); // Defining the indicator of the base driver by its name 
      that = this; // Receiving the link to the object for its using inside the function
      //-------------------------------------------------------
      // Device Online
      //-------------------------------------------------------     
      IR.AddListener(IR.EVENT_START,that.device,function()
      {
         Log("DEVICE is Initializing..."); // Write to the log that the device is Online
         
         Log("DEVICE is Initialized"); // Write to the log that the device is Online
      }, that);
        
      //-------------------------------------------------------
      // Device Online
      //-------------------------------------------------------     
      IR.AddListener(IR.EVENT_ONLINE, that.device, function(text)
      { 
         Log("DEVICE is Online"); // Write to the log that the device is Online
         that.Online = true; // Assign the true value to the that.Online variable
         deviceList = getSonosDevices();
      }, that);
      //-------------------------------------------------------
      // Device Offline
      //-------------------------------------------------------
      IR.AddListener(IR.EVENT_OFFLINE, that.device, function(text)
      { 
         Log("DEVICE is Offline"); // Write to the log that the device is Offline
         that.Online = false; // Assign the false value to the that.Online variable
      }, that);  
      //-------------------------------------------------------
      // Receive Text
      //-------------------------------------------------------
      IR.AddListener(IR.EVENT_RECEIVE_TEXT, that.device, function(text)
      {
         Log("Text Received: " + text);  // Output the received data in the log
      }, that);
        
      //-------------------------------------------------------
      // Channel Set
      //-------------------------------------------------------
      IR.AddListener(IR.EVENT_CHANNEL_SET, that.device, function(name, value) {
         name  = TrimString(name);
         value = TrimString(value);
        
         Log("Issue Command: " + name + " :: " + value, "Verbose");
        
         //name is the command
         switch (name){
            case "Speak":
                //a1 = arm away
                var payload = value.split(":");
                
                var zone = payload[0] ? payload[0].toString() : 'Kitchen';
                var announcement = (payload[1]) ? payload[1].toString() : 'Just Because I Can!';
                               
                announce(zone, announcement)
                break;
         }
      }, that);
  
   }
   
   function getSonosDevices ()
   {
      var sonosDevices = [];
      NodeSonosAPIrequest = function(in_callback)
      {
         that.device.SetParameters({ConnectWaitTimeMax: 5000, ReceiveWaitTimeMax: 10000});
         that.device.Connect();
         that.device.SendEx(
         {
            Type: "GET",
            Url: "/zones",
            cbReceiveText: function(text, code, headers) 
            {
               if (code != 200) return; //parse other error codes
               var resp = JSON.Parse(text);
               //IR.Log(text); 
               that.device.Disconnect();                    
               in_callback(resp);
            },
         });
      };
      //Attach data to channels here
      NodeSonosAPIrequest(function(resp)
      {
         for (var i = 0; i < resp.length; i++) {
            IR.Log(resp[i].coordinator.roomName);
            sonosDevices[i] = resp[i].coordinator.roomName;
         }
         //IR.GetDevice("mqtt").Set("temp",coordinators.roomName); 
         //IR.GetDevice("mqtt").Set("pressure",resp.main.pressure);
      });
      return sonosDevices;
   }
   function announce(Zone, Message, Volume) 
   {
      var vol = (Volume) ? Volume.toString() : '40';
      var httpCmd = 'Get,/' + Zone + '/say/' + encodeURIComponent(Message) + '/' + encodeURIComponent(vol);
      Log("Speaking ["+ Message +"]");
      Log("Sending: " + httpCmd, "Debug");  // Output the received data in the log
      that.device.Send([httpCmd]);
   }
   
   
   
   //**************************************************\\
   var TrimString = function (str) {
      var localStr = str;
      if (!str) return str; // Don't alter the empty string
      try {
         return str.replace(/^\s+|\s+$/g, ""); // Regular expression magic, barfs if the type is a number,
                                                // but we need to be able to trim Strings that are made up of numbers, eg " 0" -> "0"
      }
      
      catch(err) {
         return localStr;
      }
   }
   
   var Log = function(logText, logMode) {
      var log = logMode ? logMode.toString() : 'Info';
      switch(log) {
         case 'Verbose':
            if (loggingLevel >= 2)  IR.Log("VERBOSE: [" + that.DriverName + "] " + logText);
            break;
            
         case 'Debug':
            if (loggingLevel >= 3)  IR.Log("  DEBUG: [" + that.DriverName + "] " + logText);
            break;
                
         case 'Error':
            if (loggingLevel >= 1)  IR.Log("  ERROR: [" + that.DriverName + "] " + logText);
            break;
          
         default:
            if (loggingLevel >= 1)  IR.Log("   INFO: [" + that.DriverName + "] " + logText);
            break;
      }
   }
  
   //-------------------------------------------------------
   // Public
   //-------------------------------------------------------
   this.Init = initialization; // Make the initialization function public
   this.Speak = announce;
};  
var SonosAPI = new Sonos_API("Node-Sonos");
SonosAPI.Init();
var primaryAnnouncementZone = "Kitchen";
SonosAPI.Speak(primaryAnnouncementZone,"System Update, The Iridium Pro Server has been restarted.","50");


From there to get a list of Favorites i would just send a request of the following to the Node Sonos Instance


http://nodeSonosAPI/favourites


and then from the list returned, i can play it in the zone with the following command


http://nodeSonosAPI/zone/favourite/item name


This is what the code might look like, as an example of how easy this can be to work with Iridium and Sonos


   // Helper Function to Play a playlist in group or zone, with an optional volume
   function playPlaylist(Zone, Playlist, Volume) {
      playQueue(Zone, Playlist, "Playlist", Volume);
   }    // Helper Function to Play a favorite in group or zone, with an optional volume
   function playFavorite(Zone, Favorite, Volume) 
   {
      playQueue(Zone, Favorite, "Favorite", Volume);
   }    // Worker Function to Play a favorite or playlist in group or zone, with an optional volume
   function playQueue(Zone, QueueName, QueueType, Volume) {
      var queue = '';
      if (QueueType == "Playlist") { queue = "playlist"; }
      else if (QueueType == "Favorite") { queue = "favorite"; }
      else { break; }       
      var httpCmd = 'Get,/' + Zone + '/' + encodeURIComponent(queue) + '/' + encodeURIComponent(QueueName);
      Log("Playing "+ QueueType + ' ' + QueueName +" in " + Zone);
      Log("Sending: " + httpCmd, "Debug");  // Output the received data in the log
      that.device.Send([httpCmd]);       if (Volume) {
         // If the Volume is also provided, we will update Sonos to implement this request also
         var httpCmd = 'Get,/' + Zone + '/volume/' + encodeURIComponent(volume);
         Log("Setting Volume to "+ Volume + " in " + Zone);
         Log("Sending: " + httpCmd, "Debug");  // Output the received data in the log
         that.device.Send([httpCmd]);
      } else {
         Log("No Change to Volume to "+ Volume + " in " + Zone);
      }
   }
   


Both reply with JSON, so parsing is not hard in Iridium.

Done ! :)


What the current direction on this, is this a feature still planned? 

Is it a direction for the Iridium Gate appliance?


The option for a TCP/IP Server with a webhook from IFTTT is not working due to the TCP/IP HTTP bug for not closing the connection properly, as per other threads.  

Hi Guys,


Has this driver been released, or is Beta 6 the current drop?


I have been converting all my drivers to be Server, is it possible to get a version of the project which will permit access to the scripts so that i can refactor this. Happy to do under NDA, and send back the updated version for signing, testing and release.


thanks

Damian

Ian 


If you still need help and have the protocol document, I’ll create a skeleton driver to get you going. 


Let me know

Damian 

I have been working on this a little more, running on the Server (not client), and this TCP connection, even with the demo code is not working as suggested.


Can we have this reopened for investigation, as this does feel like a bug.

thanks

Damian

@Aleksandr,


I have attempted to get the response to work also, but have the same experience as Martin in the efforts i have made.


For full reference this is the code which I have been testing from, its a ready to run script, just paste and go :). 


You will observe the issues at the end of the Switch Statement in the IR.EVENT_RECEIVE_TEXT anon func.  Any guidance on how to solve this would be appreciated. 


I also understand your security concerns, so this is at my own risk - fully accepted.



//
// Iridium TCPServer Feature
//

// Connction Details 
//    TCP Listener
//        Port - Based on the Port Allocated in the driver
//        Clients - Max Clients based on the count set in the driver

// Feedback
//    Currently the server is sending HTTP feedback, but only after a forced
//    Disconnect and Reconnect, as mentioned in the support thread
//    http://support.iridiummobile.net/topics/12528-anyone-here-with-a-ready-made-http-server-tcp_custom_server-script/#

var TCPServer = function(DriverName)
{
   //-------------------------------------------------------
   // Driver Data
   //------------------------------------------------------- 
   this.DriverName = DriverName;
   this.device;
   this.Online = false;
   
   this.Msg = ""; // Variable storing the command for sending to the device 
   this.error = false; // Error flag
 
   var that = this; // Receiving the link to the object for its using inside the function
   
   function initialization() // Initialization method of the class instance
   {
      var port = 8088;
      var max_clients = 10;
      this.device = IR.CreateDevice(IR.DEVICE_CUSTOM_SERVER_TCP, this.DriverName, "", port, max_clients, IR.BACKGROUND_OFF);
      this.device.Connect();

      that = this; // Receiving the link to the object for its using inside the function
  
      //-------------------------------------------------------
      // Device Online
      //-------------------------------------------------------     
      IR.AddListener(IR.EVENT_ONLINE, that.device, function(text)
      { 
         IR.Log("[" + that.DriverName + "] DEVICE is Online"); // Write to the log that the device is Online
         that.Online = true; // Assign the true value to the that.Online variable
      }, that);

      //-------------------------------------------------------
      // Device Offline
      //-------------------------------------------------------
      IR.AddListener(IR.EVENT_OFFLINE, that.device, function(text)
      { 
         IR.Log("[" + that.DriverName + "] DEVICE is Offline"); // Write to the log that the device is Offline
         that.Online = false; // Assign the false value to the that.Online variable
      }, that);  
      
      
      //-------------------------------------------------------
      // Device Registered
      //-------------------------------------------------------
      IR.AddListener (IR.EVENT_ACCEPT, that.device, function (text)   
      {  
          IR.Log("[" + that.DriverName + "] DEVICE is Listening"); // Write to the log that the device is Offline
      }, that);
   
      //-------------------------------------------------------
      // Receive Text
      //-------------------------------------------------------
      IR.AddListener(IR.EVENT_RECEIVE_TEXT, that.device, function(text, client_id, host, port, host_ip, host_port)
      {
         IR.Log("[" + that.DriverName + "] Text Received: " + text);  // Output the received data in the log       
 
         // Parser
         var reqEnd = text.indexOf('\r\n\r\n');
         var reqGET = text.indexOf('GET ');
  
         if ((reqEnd != -1) && (reqGET != -1)) {
            req = text.slice(reqGET + 5);
            var httpRequest = decodeURIComponent(req.slice(0,req.indexOf(' ')));
            IR.Log("[" + that.DriverName + "] HTTP Request: " + httpRequest);  // Output the received data in the log
            //ex. http://127.0.0.1/ModbusTCP,Channel1,1 
            part = httpRequest.split(",");
            IR.Log("[" + that.DriverName + "] HTTP Request Payload: Driver[" + part[0] + "] Channel [" + part[1] +"] Value [" + part[2] + "]");  // Output the received data in the log
            
            
            switch (part[0]) {
               case 'favicon.ico' :
                  that.device.Send(['HTTP/1.1 302 Found\n']);
                  that.device.Send(['Location: http://www.iridiummobile.net/favicon.ico\n\n']);
                  break;
      
               case 'sonos':
                  //IR.GetDevice("Sonos").Set("Play","");
                  IR.GetDevice(part[0]).Set(part[1], part[2]);
                  that.device.Send(['HTTP/1.0 200 OK\n']);
                  that.device.Send(['Content-Type: text/plain\n\n']);
                  that.device.Send(['Your command was: ' + httpRequest]);
                  break;
                  
               case 'notify':
                  // Send Push Notification
                  IR.SendPush("Call from "+part[0], part[0], 1, this, catchError, 1);   
                  IR.Log("[" + that.DriverName + "] Notification Sent: " + part[0]);  // Output the received data in the log
                  that.device.Send(['HTTP/1.0 200 OK\n']);
                  that.device.Send(['Content-Type: text/plain\n\n']);
                  that.device.Send(['OK you requested: ' + httpRequest]);
                  break;
                  
               default:
                  that.device.Send(['HTTP/1.0 200 OK\n']);
                  that.device.Send(['Content-Type: text/plain\n\n']);
                  that.device.Send(['OK you requested: ' + httpRequest]);
                  break;
            }          
   
            IR.SetTimeout(200,function()
            {
               that.device.Disconnect();
            });
   
            IR.SetTimeout(400,function()
            {
               that.device.Connect();
            });
            
         }
         
      }, that);
      

   }
   
    function catchError(object)
    {
      IR.Log("[" +  that.DriverName + "] Error: " + object.Error + ' - ' + object.ErrorDescription);
    }

   //-------------------------------------------------------
   // Public
   //-------------------------------------------------------
   this.Init = initialization; // Make the initialization function public
}


// Create the Instance of the driver with the following sample
var myTCPServer = new TCPServer('Sky Q');

myTCPServer.Init();


Oh that's not what I was hoping to hear.  Do we have any options to externally  change the value on a device. For example remotely turn on or off a light using a HTTP endpoint. 


I would of course prefer to hit the server and not be dependent on a working internet to hit iridium cloud and relay back to the server. 


Obviously with the gateways for Alexa and HomeKit this must be achieved via a cloud endpoint. Can we authenticate to that service as an alternative?


Thank you