Florian Wesch

Remote control interfaces

Posted Jan 05 2018 by Florian Wesch

info-beamer hosted now allows a package to include a custom remote control interface that can be used to control the devices running that package in real time.

Remote control interfaces?

When you run an info-beamer setup on a device, it's usually pretty static. If you want to change what your screens are doing you might automate configuration/asset changes through the REST API or manually reconfigure a running setup to update its content. Or of course you can use package services to run code on your device that interacts with the outside world and automatically pulls in new data.

There was no easy way to send one shot events to a device. Those could be used to trigger intermissions, quickly add text to a ticker or other volatile actions that don't justify a full configuration change. Here's an example:

How it works

The clean architecture of info-beamer hosted made it pretty simple to add this feature in a way that is easy to understand. First of all you'll have to declare a control_ui in your node.json file. Here's a complete node.json file of an example package that demonstrates this feature:

{
    "name": "Screen Light",
    "control_ui": "control.html",
    "options": []
}

The control_ui value references a control.html file that is also part of this package. It looks like this:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
  </head>
  <body>
    <button id='on' class='btn btn-default'>Toggle On</button>
    <button id='off' class='btn btn-default'>Toggle Off</button>

    <!-- Provides the interface to info-beamer hosted -->
    <script src="hosted.js"></script>

    <script>
      // Add CSS style, so the interface has the same look & feel like
      // the rest of the info-beamer hosted interface. It's bootstrap 3.
      ib.setDefaultStyle();

      document.getElementById('on').addEventListener('click', function(evt) {
        // Send a command. This ends up in the running lua code on the device
        ib.sendCommand("toggle", "on");
      });

      document.getElementById('off').addEventListener('click', function(evt) {
        ib.sendCommand("toggle", "off");
      });
    </script>
  </body>
</html>

The interesting bits of information in here are:

  • The included hosted.js allows you to interface with the info-beamer hosted system. You don't have to provide it manually. It will be automatically available in the current directory while info-beamer hosted shows your control interface.
  • The ib.setDefaultStyle() includes the bootstrap 3 toolkit, so the style of your interface matches the one used on the info-beamer hosted website without having to include style/link tags manually.
  • ib.sendCommand(...) can be used to send commands to your device. You'll soon see how all this works together. Just keep in mind that we're sending the toggle command with "on" and "off" values.

The next part of the puzzle is the node.lua file that is running on a device and that is also part of the package. It looks like this:

gl.setup(NATIVE_WIDTH, NATIVE_HEIGHT)

local on = false

-- Listen to incoming UDP packets and parses them, so you can
-- easily dispatch them just by defining callback functions.
util.data_mapper{

    -- Listen to the 'toggle' event sent from the hosted service
    toggle = function(status)
        on = status == "on"
    end
}

function node.render()
    if on then
        gl.clear(1,1,1,1)
    else
        gl.clear(0,0,0,1)
    end
end

Here we're using the util.data_mapper helper function to set up a callback that reacts to the toggle event. The status is given as arguments. Inside the callback handler we check if status is "on" and set a boolean variable on accordingly. Finally in the node.render handler we gl.clear differently depending on the on value.

If we create a setup from this package and install it on a device and go to the device page, you'll now see our newly defined interface:

The above control.html file is securely embedded into the device page itself and allows you to send commands to your device in real time! The headline and lightbulb icon are directly taken from the included name value in node.json and node.png file, so you have control over how your remote control feature is presented on the device page.

Clicking on the Toggle on button instantly turns the screen white, while clicking the Toggle off button turns it black. In the background the ib.sendCommand(...) call is forwarded from the iframe that embeds the control.html file to the surrounding info-beamer page which then translates it into an device command API call. The data is then forwarded through the persistent websocket connection to the device. There it is translated to a UDP packet and sent to the running info-beamer process which then handles the event using the util.data_mapper callback.

The result is the same as if you would locally send a UDP packet with to following content to the info-beamer process running on the device to port 4444. Except that you can do it with the click of a button (or automated if using the API):

root/toggle:on

You can play around with the package by browsing the source or importing the example package into your account. Just click this button:

What you can do with it

You can use this feature to provide simple interactions that don't rely on a particular state on the device:

  • Showing overlays
  • Temporarily toggling content on demand
  • Showing debug information
  • Triggering events that decide what to display next

There is no feedback from the device to the frontend (just like with a real remote), so you can't build complex interfaces that depend on knowing the current device state. All actions should work on their own and shouldn't depend on previously sent actions and there is no 100% guarantee that all commands reach the device. This might happen if info-beamer just restarted. Information sent this way is usually lost if info-beamer reloads your node Lua code, so you shouldn't send important information that way.

A real life example use case

During the recent 34c3 conference, I've used this feature (through the API, not the interface on the website) to show intermission screens in the halls. Before each talk, the crew introducing the speaker had the opportunity to quickly toggle an overlay on the screen that explained where to find translated audio streams.

Using device commands is the perfect solution for that: Triggering the overlay is a one-time action that doesn't justify using a full configuration change of the running code and should happen in (almost) real-time, so it feels responsive to the user of the system. Device commands solve this perfectly.


Read more...


info-beamer.com offers the most advanced digital signage platform for the Raspberry Pi. Fully hosted, programmable and easy to use. Learn more...


Get started for free!

Trying out the best digital signage solution for the Raspberry Pi is totally free: Use one device and 1GB of storage completely free of charge. No credit card required.


Follow @infobeamer on twitter to get notified of new blog posts and other related info-beamer news. It's very low traffic so just give it a try.

You can also subscribe to the RSS Feed RSS feed.


Share this post:

Share using Twitter


Questions or comments?
Get in contact!