Universal Remote Control

Part I: Server

Contents

All the IR servers/tools that I found were either bloated or did not provide the functionality that I required. I had created a web server in Java a couple years ago so I made a branch and modified it for my singular purpose.

Disclaimer: I used to be a software engineer (a lifetime ago) – my code these days is not nearly as eloquent or efficient as it could be. To be frank, I wanted a functional piece of equipment quickly that my wife could use effectively and appreciate – and selfishly, not to be seen as “just playing on my computer”.

    public static void main(String[] args) {
        if(args.length > 0){
            for(int i = 0; i < args.length; i++) {
                switch(args[i]){
                    case "-path": //required: path to www
                        path = args[i+1];
                        break;
                    case "-port": //optional: default 9000
                        port = parseInt(args[i+1]);
                        break;
                    case "-allowremote": //optional
                        allowRemote = true;
                        break;
                }
            }
        }
        httpServer = new SimpleHttpServer();
        httpServer.Start(port, allowRemote);
    }
    void Start(int port, boolean allowRemote) {
        try {
            if(!allowRemote)
                server = HttpServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), port), 0);
            else {
                System.out.println("CAUTION: SERVER IS ALLOWING REMOTE CONNECTIONS!");
                server = HttpServer.create(new InetSocketAddress(port), 0);
            }
            System.out.println("Universal Remote Backend started (" + port + ")");
            server.createContext("/", new Handlers.RootHandler());
            server.createContext("/IR", new Handlers.IRHandler());
            server.createContext("/status", new Handlers.StatusHandler());
            server.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
Below is the handler code for file requests to the web server.
    public static class RootHandler implements HttpHandler {

        @Override
        public void handle(HttpExchange he) throws IOException {
            String fileName = he.getRequestURI().getPath();
            File file = new File(Main.path + fileName).getCanonicalFile();

            if (!file.isFile()) {
                // Object does not exist or is not a file: reject with 404 error.
                String response = "404 (Not Found)\n";
                he.sendResponseHeaders(404, response.length());
                OutputStream os = he.getResponseBody();
                os.write(response.getBytes());

                he.close();
                os.close();
            } else {
                // Object exists and is a file: accept with response code 200.
                String mime = MimeTypes.getMimeType(FilenameUtils.getExtension(fileName));
                
                he.sendResponseHeaders(200, file.length());

                byte[] bytearray = new byte[(int) file.length()];
                FileInputStream fis = new FileInputStream(file);
                BufferedInputStream bis = new BufferedInputStream(fis);
                bis.read(bytearray, 0, bytearray.length);

                OutputStream os = he.getResponseBody();
                os.write(bytearray, 0, bytearray.length);

                fis.close();
                bis.close();
                he.close();
                os.close();
            }
        }
    }
The following code creates the handler for POST calls for IR commands. It also includes the logic to handle device status – it will be covered in Part III – HMI.
public static class IRHandler implements HttpHandler{
        public void handle(HttpExchange he) throws IOException {
            InputStreamReader isr = new InputStreamReader(he.getRequestBody(), "utf-8");
            BufferedReader br = new BufferedReader(isr);
            String query = br.readLine();

            Map<String, String> parameters = parseQueryString(query);

            String response = "";
            String key = "";
            String cmd = "";

            Main.currentActivity = parameters.get("mac");

            ArrayList <Map.Entry <String,String>> commands = parseMacro(parameters.get("commands").replace("\"", ""));

            for(int i = 0; i < commands.size(); i++){
                key = commands.get(i).getKey();
                cmd = commands.get(i).getValue();

                if(cmd.equals("KEY_POWER")){
                    switch(key){
                        case "Projector":
                            Main.ProjectorStatus = (Main.ProjectorStatus) ? false : true;
                            break;
                        case "Receiver":
                            Main.ReceiverStatus = (Main.ReceiverStatus) ? false : true;
                            break;
                        case "XBOX":
                            Main.XboxStatus = (Main.XboxStatus) ? false : true;
                            break;
                        case "Cox":
                            Main.CoxStatus = (Main.CoxStatus) ? false : true;
                            break;
                        default:
                            break;
                    }
                }

                response += (!key.equals("delay")) ? sendIR("SEND_ONCE", key, cmd) : "";
            }

            OutputStream os = he.getResponseBody();
            he.sendResponseHeaders(200, response.length());
            os.write(response.getBytes());

            he.close();
            os.close();
        }
    }
Below is the code that executes the irsend command that is package with the LIRC: Linux Infrared Remote Control package. Getting the remotes programmed will be covered in Part II: IR Blaster.
    public static String sendIR(String type, String device, String key){
        String response = "";

        try {
            Process p = Runtime.getRuntime().exec("irsend " + type + " " + device + " " + key);

            BufferedReader in = new BufferedReader(
                    new InputStreamReader(p.getInputStream()));
            String line = null;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
                response += line + "\n";
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return response;
    }

Daniel Blair Written by: