Raising the bar with the IRTrans driver

The last few days I’ve been busy developing a driver for my IRTrans LAN IR transmitter/receiver. I chose the IRTrans because it’s not being used that much (anymore), but still enough to detect bugs within a few hours. And another nice thing is that the IRTrans LAN Gateway accepts multiple connections, so testing a new driver is easy – I won’t have to completely shut down my previous (and still actively used) driver developed in Delphi. While working on this driver, I took the time to also improve some other things (which I should have done earlier).

Settings

I didn’t like the way some drivers have IP-addresses of hardware interfaces hard-coded, so I fixed that. Mosquitto (the MQTT broker I’m using) looks like the best place to store settings like the IP-address & port the driver has to connect to, poll intervals and other parameters that influence how a driver behaves. But first, I needed a way to find out where my broker is – for that I created 2 system-wide environment variables by adding the following to the file /etc/environment on the Raspberry Pi:

DDMC_BROKER_HOST=192.168.10.13
DDMC_BROKER_PORT=1883

If you’re using a Windows PC for development, you’ll have to add those environment variables on that machine as well, or add them to the nodevars.bat that starts the Node.js environment on Windows:

@echo off
rem Ensure this Node.js and npm are first in the PATH
set PATH=%APPDATA%npm;%~dp0;%PATH%
rem settings specific to DDMC
set DDMC_BROKER_HOST=192.168.10.13
set DDMC_BROKER_PORT=1883

A simple change in how the Node.js MQTT client connects and this issue was fixed:


var host = process.env.DDMC_BROKER_HOST;
var port = process.env.DDMC_BROKER_PORT;
mqttClient = mqtt.createClient(port, host);

When the connection has been established, the rest of the required settings can be retrieved from the MQTT broker by subscribing to a topic and wait for a message to arrive:


// get required settings
tools.mqttClient.on('connect', function(packet) {
  tools.settings.require('host');
  tools.settings.require('port');
  tools.settings.require('subdelay');
});

Of course, the script has to wait for the required settings to arrive; this is done by keeping track of all the required settings and ‘pause’ execution until all required settings are ‘set’ by the incoming messages. I picked up this idea by browsing the HomA source code which was brought to my attention in a comment recently. Now I can remove all the hard-coded stuff from the driver code and clean them up a bit.

OK, back to the IRTrans driver. During all the years I’ve been working with the IRTrans, I added some ‘features’ which I didn’t want to lose:

Channels.

I’m used to working with TV station names instead of channel numbers for my cable STB. An example: I have a page on my Philips Pronto TSU9600 with icons for all the TV station we’re able to receive. Let’s say that each icon (a button, actually) has on onClick() method which looks like this: SetDevice(‘upc’, ‘EUROSPORT’);

Why? Because I can’t remember that EuroSport is on channel 401, but I can remember the ‘short-codes’ like ‘EUROSPORT’, ‘NED1’, ‘BBC1’, ‘WDR’,’DISCOVERY’…

But the IRTrans doesn’t know what ‘EUROSPORT’ means, so I made a ‘mapping’ table on my SQL Server to translate ‘EUROSPORT’ to ‘401’. But because the Node driver has no way to connect to my SQL Server, I added an extra setting to the IRTrans driver, so I don’t have to change all the UI’s when something changes and I can keep on using these ‘short-codes’ for ever:

{"EUROSPORT":201,
"BBC1":50,
"BBC2":51,
"ANIMAL":21,
"NATGEO":18,
....
"CNN":401}

The JSON formatted data shown above is parsed and used as an associative array.

Delays

Let’s take the example above a little further. Eurosport, channel 401. All the buttons on the remote of the Cable set-top box (STB) were learned with the Philips Pronto (PEP1) and added to a IRTrans .rem file. That means that I have an IR code for the button ‘1’, another one for ‘2’, ‘3’ and so forth. But I don’t have an IR code for ‘401’. So, to mimic selecting channel 401 with the remote, I have to send the IRTrans 3 IR codes: the code for ‘4’,’0′ and ‘1’. And I have to add a delay between those 3 IR codes because if I don’t, the STB doesn’t always recognize what’s being sent! Hmm… delay, event-driven, timeouts… challenge.

Adding a delay is not such a problem, because the Node.js setTimeout() command allows you to add a minimum(!) delay before something’s being executed. But no matter what I tried, instead of sending the ‘4’,’0′,’1′ sequence to the IRTrans, my driver code sent ‘1’,’1′,’1’… Okay, those who are familiar with Javascript will probably know what is causing this, but for me this ‘scope’ problem was new!

After I read this excellent page, I knew what to do… well, that’s the down-side of immediately start coding instead of learning the language first.

Toggle codes.

A more detailed explanation of the problem with our current STB is described here as well as how I handled it, although the issue can also be fixed with newer IRTrans firmware. The new Node.js based IRTrans driver has to automatically handle this toggle problem as well of course, as if toggle codes don’t even exist. That’s because I don’t want to send up#1, up#2, up#1 from my UI’s to go from channel X to X+3, but just up, up, up – it’s ridiculous and it wouldn’t work anyway, with more than 1 UI – capiche?

So the IRTrans driver should keep track of the last-used IR code for ‘up’.  The ‘old’ Delphi driver already retrieved a lot of information from the IRTrans gateway – the identifications of all the remotes (upc, onkyo, hdmax, …) and all the commands (up, down, vol+, poweron,..) of those remotes, so I did the smae thing in my Node driver.

So the physical STB remote has 2 different IR codes for the ‘up’ button, which I named ‘up#1’ and ‘up#2’. I use the ‘#’ in the command name to detect that we’re dealing with a so-called toggle code for the ‘up’ command. So all I had to do was collect all the commands starting with ‘up#’ into a single object instance, add an index counter and all goes automatically…

During startup of the new IRTrans driver I query the IRTrans driver with ‘Agetremotes‘ and ‘Agetcommands‘ and store the information in an array. Here’s the code of the class that ‘hides’ the toggle code issue:

var InfraRedCommand = function(remotecommand) {
  this._command = remotecommand;
  this._index = 0;
  this._toggleCodes = [];
}
InfraRedCommand.prototype.addCode = function(code){
  this._toggleCodes.push(code);
}
InfraRedCommand.prototype.getCode = function(){
  if(this._toggleCodes.length > 0){
    this._index++;
    if(this._index >= this._toggleCodes.length) this._index = 0;
    return this._toggleCodes[this._index];
  } else {
  	parts = this._command.split(",");
    return parts[parts.length-1];
  }
}

module.exports = InfraRedCommand;

Now the toggle codes are hidden, in just a few lines of code 🙂

From time to time I test this new IRTrans driver by sending an ‘off’ command to the TV or STB, or switching to ‘CNN’. Judging by the amount of uproar coming from the living-room, this new driver is working very well!

 

Tagged , , . Bookmark the permalink.

2 Responses to Raising the bar with the IRTrans driver

  1. Jason says:

    I know this is a pretty old post and I am not completely through ALL your posts yet. But I was wondering if you had though about doing DNS records on your network or doing something with bonjour to announce your broker?

Leave a Reply

Your email address will not be published. Required fields are marked *