Ultimate Vera Remote Control : IrScrutinizer & IrpTransmogrifier & Broadlink Pro

What started out as a project to discover the IR codes for a device I’d lost the original remote control for has opened me up to the world or Infrared, which like RS-232, I thought was a dying area of device control, what with Bluetooth/web/IP access becoming so popular etc. However I’m coming across so many things that still use (need) it, and as I wanted to be able to control/automate as much as I can, I’ve invested a bit of time to explore some capabilities. Unfortunately not being a developer, I can only invest so much of my spare time learning, hence I’ve been hugely grateful for all the support/advice given to me by the likes of @akbooer and @a-lurker - but fearing I’ve worn their patience down, and I’ve reached the end of my capabilities - I’m hoping others in this forum might see some value in it and either help me, or take it on themselves.

My Objective(s)

  1. Have a way to discover the ir remote control codes for a devices I’ve lost the original remote for.
  2. To create a look-up facility where you can find a remote make/model and test any command you want
  3. More maybe…

Requirements:

Disclaimer : I’m still learning so much of this, so what follows is my (mis?)interpretation :slight_smile:

Ok, so let’s get going… Starting with the IRBD, and the great work they’ve done to build a huge library of ir protocols/codes - now it’s important to point out that the information in the IRDB itself are stored in their protocol/design format, and not in the format you would need to send them via the Vera IR plug-ins mentioned above. So that instantly sets the scene for us needing to convert them into the format I want, and for the purposes of this project, I am focussing on having them all in the ProntoCode IR format…

So what do I mean by protocol/design format, well, here’s an example of the file within the IRDB for a standard Samsung TV (file name = 7,7.csv) - which uses a specific protocol called NECx2. If you want to know more about the protocols and their decoding requirements, here’s a link

functionname,protocol,device,subdevice,function
INPUT SOURCE,NECx2,7,7,1
POWER,NECx2,7,7,2
1,NECx2,7,7,4
2,NECx2,7,7,5
3,NECx2,7,7,6
VOLUME +,NECx2,7,7,7
4,NECx2,7,7,8
5,NECx2,7,7,9
6,NECx2,7,7,10
VOLUME -,NECx2,7,7,11
7,NECx2,7,7,12
8,NECx2,7,7,13
9,NECx2,7,7,14
MUTE,NECx2,7,7,15
CHANNEL -,NECx2,7,7,16
0,NECx2,7,7,17
CHANNEL +,NECx2,7,7,18
LAST,NECx2,7,7,19
MENU,NECx2,7,7,26
INFO,NECx2,7,7,31
AD/SUBT,NECx2,7,7,37
EXIT,NECx2,7,7,45
E-MANUAL,NECx2,7,7,63
TOOLS,NECx2,7,7,75
GUIDE,NECx2,7,7,79
RETURN,NECx2,7,7,88
CUSOR UP,NECx2,7,7,96
CURSOR DOWN,NECx2,7,7,97
CURSOR RIGHT,NECx2,7,7,98
CURSOR LEFT,NECx2,7,7,101
ENTER,NECx2,7,7,104
CH LIST,NECx2,7,7,107
SMART HUB,NECx2,7,7,121
3D,NECx2,7,7,159

There are 100s of these manufacturer device csv files in IRDB and for us to convert and use them, this is where the IrpTransmogrifier or IrScrutinizer programs come. In regards to which one to use, I understand, IrpTransmogrifier focuses more on the conversion e.g via a command line , where as IrScrutinizer is much more comprehensive IR validation/conversion tool, with a nice UI etc.

In order to achieve my 1st objective, I decided to download all the ircodes .csv files that’s are in the IRDB’s GitHub and then have Vera go through them al to extract the lines that have a ‘POWER’ function entry. Code below.

Note: I have a mapped drive on my Vera to my NAS where I stored the csv files

function scanIndexFiles ()
  local lfs = require "lfs" 
  local dir = "mnt/nas/vera/ircodes/"   -- make this your path to the files 
  local split = "^([^,]+),(.*)"  -- (func_name,protocol,D,S,F) 

  local file = io.open ("/www/powerircodes.txt", “wb”)
  for filename in lfs.dir(dir) do 
    if filename: match "%.csv$" then 
      for line in io.lines(dir .. filename) do 
        local func_name,etc = line: match (split) 
        if etc then
          local params = "([^,]+),([^,]+),([^,]+),([^,]+)"
          local protocol, D,S,F = etc: match(params)
          if 'POWER' == func_name:upper() then 
            local info = table.concat ({"Power", protocol, D, S, F, filename}, "; ") 
            print(info)
            file:write(info .. "\n")
          end
        end
      end
    end
  end
  file:close()
end

scanIndexFiles()

The above then creates a single .csv with all the discovered ‘Power’ commands and their associated protocol/design. See extract below.

Note: To ensure I know the source file, I also appended the originating file name to the end of each line, however as those file names include a comma and the file being generate is a .csv I’ll need to re-work the code at some point, but for now it’s not crucial (just a nice to have)

functionname,protocol,device,subdevice,function,file
Power,Panasonic,144,64,61,144,64.csv     
Power,NEC1,64,223,18,64,223.csv     
Power,Pioneer,163,-1,153,163,-1.csv     
Power,NRC17,74,-1,12,74,-1.csv     
Power,NEC1,0,223,15,0,223.csv     
Power,Fujitsu,132,138,0,132,138.csv     
Power,NEC1,209,-1,194,209,-1.csv     
Power,NEC1,135,123,64,135,123.csv     
Power,NEC1,130,111,24,130,111.csv     
Power,NEC1,132,66,81,132,66.csv     
Power,Pioneer,186,160,76,186,160.csv     
Power,Zaptor-56,16,0,8,16,0.csv     
Power,Sony20,25,37,21,25,37.csv     
Power,NEC1,132,89,4,132,89.csv     
Power,NEC1,96,158,23,96,158.csv     
Power,NEC1,130,110,1,130,110.csv     
Power,NEC,8,19,135,8,19.csv     
Power,NEC1,18,37,0,18,37.csv     
Power,JVC-48,34,48,0,34,48.csv     
Power,NEC1,0,69,128,0,69.csv     
Power,NEC2,92,162,19,92,162.csv     
Power,NEC1,130,93,4,130,93.csv     
Power,MCE,4,15,12,4,15.csv     
Power,Panasonic,144,0,61,144,0.csv     
Power,NEC2,170,-1,28,170,-1.csv     
Power,Panasonic_Old,27,-1,7,27,-1.csv     
Power,NEC1,4,243,1,4,243.csv     
Power,NEC1,133,115,128,133,115.csv     
Power,Zenith,7,0,56,7,0.csv     
Power,XMP-2,14,0,15,14,0.csv     
Power,Fujitsu,132,139,0,132,139.csv     
Power,JVC,83,-1,11,83,-1.csv     
Power,NEC1,128,55,32,128,55.csv     
Power,NEC1,128,55,128,128,55.csv     
Power,XMP-2,15,0,15,15,0.csv     
Power,NEC2,186,75,76,186,75.csv     
Power,NEC,186,75,76,186,75.csv     
Power,NEC1,210,4,203,210,4.csv     
Power,Sony15,57,-1,21,57,-1.csv     
Power,Sony20,26,66,21,26,66.csv     
Power,NEC,1,254,3,1,254.csv     
Power,Dish_Network,0,5,2,0,5.csv     
Power,Dish_Network,0,6,2,0,6.csv     
Power,Dish_Network,0,7,2,0,7.csv     
Power,NEC1,80,79,2,80,79.csv     
Power,NEC1,0,23,0,0,23.csv     
Power,NEC1,0,17,0,0,17.csv     
Power,Proton,54,-1,14,54,-1.csv     
Power,NEC1,132,99,20,132,99.csv     
Power,NEC1,4,2,0,4,2.csv     
Power,NEC1,99,-1,235,99,-1.csv     
Power,XMP-1,42,17,68,42,17.csv     
Power,NEC2,202,85,64,202,85.csv     
Power,NEC2,129,6,64,129,6.csv     
Power,NEC1,133,83,131,133,83.csv     
Power,NEC1,32,-1,0,32,-1.csv     
Power,RC6,39,-1,12,39,-1.csv     
Power,NEC2,186,190,76,186,190.csv     
Power,Panasonic,128,2,189,128,2.csv     
Power,RC5,19,-1,76,19,-1.csv     
Power,NEC,128,255,89,128,255.csv     
Power,Aiwa,81,0,0,81,0.csv     
Power,MCE,2,22,15,2,22.csv     
Power,MCE,18,17,12,18,17.csv     
Power,Nokia32,33,160,12,33,160.csv     
Power,NEC1,85,-1,17,85,-1.csv     
Power,Aiwa,102,0,145,102,0.csv     
Power,NEC1,69,181,18,69,181.csv     
Power,NEC,8,247,11,8,247.csv     
Power,Sony20,23,133,21,23,133.csv     
Power,Dish_Network,0,1,2,0,1.csv     
Power,NEC,2,2,10,2,2.csv     
Power,NEC1,135,69,23,135,69.csv     
Power,NEC2,131,85,144,131,85.csv     
Power,Pioneer,165,-1,28,165,-1.csv     
Power,NEC1,130,100,68,130,100.csv     
Power,NEC1,8,231,67,8,231.csv     

In an ideal world I would like to have used IrpTransmogrifier and have done it all on Vera, but due to that toll needing Java, that sadly does not look possible, so we’re going to have to import the above into IrScrutinizer and convert them outside of Vera into the Pronto format, which I can explain how if your interested , however there’s are somegood guides online, and if needed I can always post that particular part later on.

After running the above .csv file through IrScrutinizer, and exporting the output, I now have the following text.txt file, (extract of which below).

Note: there are other export file formats/options available - however I’ve not found a better or easier one for me to work with yet.

Here is the output file (text1.txt) from IrScrutinizer in the required pronto code format

Power
0000 0070 0000 0032 0080 0040 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 0010 0030 0010 0030 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0030 0010 0ACD

Power$1
0000 006C 0022 0002 015B 00AD 0016 0016 0016 0016 0016 0016 0016 0016 0016 0016 0016 0016 0016 0041 0016 0016 0016 0041 0016 0041 0016 0041 0016 0041 0016 0041 0016 0016 0016 0041 0016 0041 0016 0016 0016 0041 0016 0016 0016 0016 0016 0041 0016 0016 0016 0016 0016 0016 0016 0041 0016 0016 0016 0041 0016 0041 0016 0016 0016 0041 0016 0041 0016 0041 0016 05F7 015B 0057 0016 0E6C

Power$2
0000 0068 0000 0022 0169 00B4 0017 0044 0017 0044 0017 0017 0017 0017 0017 0017 0017 0044 0017 0017 0017 0044 0017 0017 0017 0017 0017 0044 0017 0044 0017 0044 0017 0017 0017 0044 0017 0017 0017 0044 0017 0017 0017 0017 0017 0044 0017 0044 0017 0017 0017 0017 0017 0044 0017 0017 0017 0044 0017 0044 0017 0017 0017 0017 0017 0044 0017 0044 0017 0017 0017 0636

Next comes the part where I’m stuck, and that’s how Vera can convert the above text file into a format that Vera can then use to iterate through each line and send each command via the ir sender (e.g via the Broadlink plug-in )

Current Output file (text2.txt)

The ‘print’ on screen looks positive, however I can’t seem to get each line in the correct format in the text2.txt file, it always spans 3 lines.

local Power
 = "0000 0070 0000 0032 0080 0040 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 0010 0030 0010 0030 0010 0030 0010 0030 0010 0010 0010 0010 0010 0030 0010 0010 0010 0030 0010 0030 0010 0010 0010 0030 0010 0030 0010 0030 0010 0ACD
"
local Power$1
 = "0000 006C 0022 0002 015B 00AD 0016 0016 0016 0016 0016 0016 0016 0016 0016 0016 0016 0016 0016 0041 0016 0016 0016 0041 0016 0041 0016 0041 0016 0041 0016 0041 0016 0016 0016 0041 0016 0041 0016 0016 0016 0041 0016 0016 0016 0016 0016 0041 0016 0016 0016 0016 0016 0016 0016 0041 0016 0016 0016 0041 0016 0041 0016 0016 0016 0041 0016 0041 0016 0041 0016 05F7 015B 0057 0016 0E6C
"
local Power$2
 = "0000 0068 0000 0022 0169 00B4 0017 0044 0017 0044 0017 0017 0017 0017 0017 0017 0017 0044 0017 0017 0017 0044 0017 0017 0017 0017 0017 0044 0017 0044 0017 0044 0017 0017 0017 0044 0017 0017 0017 0044 0017 0017 0017 0017 0017 0044 0017 0044 0017 0017 0017 0017 0017 0044 0017 0017 0017 0044 0017 0044 0017 0017 0017 0017 0017 0044 0017 0044 0017 0017 0017 0636
"
local Power$3
 = "0000 006D 0011 000E 0013 005F 0013 0026 0026 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0013 0227 0013 005F 0013 0026 0013 0013 0026 0013 0013 0026 0013 0013 0013 0013 0013 0013 0013 0013 0026 0026 0026 0026 0013 0013 0026 0026 0013 1054
"

Latest code is below… All ideas/suggestions welcome

-- CP: does not Work
-- v0.9

function sendProntoCodeToBroadLinkDevice(prontoCode)
   local BROADLINK_DEVICE_ID = 49
   luup.call_action('urn:a-lurker-com:serviceId:IrTransmitter1', 'SendProntoCode', {ProntoCode = prontoCode}, BROADLINK_DEVICE_ID)
end

local write_file_path = "/mnt/nas/vera/text2.txt" -- # path to your file here
local read_file_path = "/mnt/nas/vera/text1.txt" -- # path to your file here
local pattern1 = "^.*Power.*$" -- # your pattern to find
local pattern2 = "^.*0000.*$" -- # your pattern to find
local matches = {}
io.open(write_file_path,"w+"):close()

local function contains(str, pattern)
  return string.match(str, pattern) and true or false
end

for line in io.lines(read_file_path) do
  if contains(line, pattern1) then
	  command = (line)
	-- table.insert(matches, line1)
end
	if contains(line, pattern2) then
		ProntoCode = (line)		  
	-- table.insert(matches, line1, line2)

	local irstr = command .. "" .. ProntoCode
	-- print(irstr)
	print(string.format('local %s = "%s"\n',command,ProntoCode))
	local file = io.open(write_file_path, 'a')
	-- file:write(command .. "" .. ProntoCode .. "\n")
	-- file:write(irstr .. "\n")
	file:write(string.format('local %s = "%s"\n',command,ProntoCode))
	file:close()
	end
end

local INTERVAL_SECS = 2
luup.call_delay('sendProntoCodeToBroadLinkDevice', INTERVAL_SECS, prontoCode)