Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@mkottman
Last active December 18, 2015 09:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mkottman/5759847 to your computer and use it in GitHub Desktop.
Save mkottman/5759847 to your computer and use it in GitHub Desktop.
Remote control your TV from the browser using Luvit / LIRC
#!/usr/bin/env luvit
--[[ lua-remote, Michal Kottman, 2013 MIT License
Control your TV or HiFi using infrared remote control from the browser using LIRC.
This application needs to be run using Luvit [1].
Requires that LIRC is listening for connection (by default on port 8765). lua-
remote will start on the next port, so fire up http://localhost:8766/ in your
browser, select the remote and you can click on any key to send the command
immediately.
You can also use curl/wget to fire the command on the URL:
http://localhost:8766/<REMOTE>/<COMMAND>
Requirements:
- Luvit [1]
- LIRC [2] or WinLIRC [3]
[1] http://luvit.io/
[2] http://www.lirc.org/
[3] http://winlirc.sourceforge.net/
--]]
--
local LIRC_PORT = 8765
local http = require('http')
local net = require('net')
local string = require('string')
local table = require('table')
local url = require('url')
-- http://lua-users.org/wiki/SplitJoin
function string:split(sep)
local sep, fields = sep or ":", {}
local pattern = string.format("([^%s]+)", sep)
self:gsub(pattern, function(c) fields[#fields+1] = c end)
return fields
end
function getRemotes(req, res)
local conn
conn = net.createConnection(LIRC_PORT, 'localhost', function(err)
if err then error(err) end
local all = {}
conn:on('data', function(data)
all[#all+1] = data
if data:match('END') then conn:done() end
end)
conn:on('error', function()
res:writeHead(200, {
["Content-Type"] = "text/html",
})
res:finish('<html><body><font color="red">Failed to connect to LIRC</font></body></html>')
end)
conn:on('close', function()
all = table.concat(all)
all = all:split('\n')
local remotes = {}
if #all >= 7 and all[3] == 'SUCCESS' then
for i=6,#all-1 do
remotes[#remotes + 1] = all[i]
end
end
res:writeHead(200, {
["Content-Type"] = "text/html",
})
res:write('<html><head><title>Remote control</title></head><body>')
if #remotes == 0 then
res:write('<b>No remotes available...</b>')
else
res:write('<ol>')
for i=1,#remotes do
res:write('<li><a href="/'..remotes[i]..'">'..remotes[i]..'</a></li>')
end
res:write('</ol>')
end
res:finish('</body>')
end)
conn:write('LIST\n')
end)
conn:on('error', function()
res:writeHead(200, {
["Content-Type"] = "text/html",
})
res:finish('<html><body><font color="red">Failed to connect to LIRC</font></body></html>')
end)
end
function getCommands(req, res, remote)
local conn
conn = net.createConnection(LIRC_PORT, 'localhost', function(err)
if err then error(err) end
local all = {}
conn:on('data', function(data)
all[#all+1] = data
if data:match('END') then conn:done() end
end)
conn:on('close', function()
all = table.concat(all)
all = all:split('\n')
local commands = {}
if #all >= 7 and all[3] == 'SUCCESS' then
for i=6,#all-1 do
commands[#commands + 1] = all[i]:split(' ')
end
end
res:writeHead(200, {
["Content-Type"] = "text/html",
})
res:write(
'<html><head><title>'..remote..'</title>'..
'<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>'..
'</head><body>')
if #commands == 0 then
res:write('<b>No commands available for ' .. remote .. '</b>')
else
res:write('<ol>')
for _,c in ipairs(commands) do
local url = '/'..remote..'/'..c[2]
res:write([[<li><a href="#" onclick="jQuery.ajax(']]..url..[['); return false;">]]..c[2]..'</a></li>')
end
res:write('</ol>')
end
res:finish('</body>')
end)
conn:write('LIST ' .. remote .. '\n')
end)
conn:on('error', function()
res:writeHead(200, {
["Content-Type"] = "text/html",
})
res:finish('<html><body><font color="red">Failed to connect to LIRC</font></body></html>')
end)
end
function sendCommand(req, res, remote, command)
local conn
conn = net.createConnection(LIRC_PORT, 'localhost', function(err)
if err then error(err) end
conn:on('close', function()
res:writeHead(200, {
["Content-Type"] = "text/plain",
})
res:finish(command..' '..remote)
end)
conn:write('SEND_ONCE ' .. remote .. ' ' .. command .. '\n', function()
conn:done()
end)
end)
conn:on('error', function()
res:writeHead(200, {
["Content-Type"] = "text/html",
})
res:finish('<html><body><font color="red">Failed to connect to LIRC</font></body></html>')
end)
end
function app(req, res)
print("Processing request for: " .. req.url)
local u = url.parse(req.url)
if u.pathname == '/' then
getRemotes(req, res)
else
local path = u.pathname:split('/')
if #path == 1 then
getCommands(req, res, path[1])
elseif #path > 1 then
sendCommand(req, res, path[1], path[2])
end
end
end
local PORT = LIRC_PORT + 1
http.createServer(app):listen(PORT)
print("Server listening at http://localhost:" .. PORT .. "/")
#!/bin/bash
# A simple runner for the remote which will update itself on exit/crash
while true; do
echo "Fetching latest version"
git pull
echo "Running server"
luvit remote.lua
echo "Sleeping for a bit"
sleep 0.1
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment