Your comments
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
Customer support service by UserEcho
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