Florian Wesch

External data sources: A bitcoin ticker

Posted Nov 02 2014 by Florian Wesch

Often you have external dynamic information that you want to show in an info-beamer visualization. Since info-beamer itself doesn't provide an API to (for example) use HTTP you might wonder how to do this. info-beamer makes this very easy. It's also language agnostic. So you can use the language of your choice to fetch information and then make it available to info-beamer. Here's a pretty basic bitcoin ticker that shows how to do this.

info-beamer was designed with external scripting in mind. Lua, the programming language that info-beamer uses for its scripting interface, is surprisingly powerful once you get used to it. It's also one of the fastest scripting languages available right now. So it's a perfect match for info-beamer.

But that doesn't mean you have to use Lua for everything when using info-beamer. You probably already have a favourite language that you are familiar with. And it probably has libraries to access all kind of APIs. info-beamer embraces this fact by allowing you to send data to a running info-beamer visualization from another program written in the language of your choice. In fact there's multiple ways to get data into a visualization:

  • You can write into files in the directory of a running visualization: info-beamer instantly detects changed files and allows you to react to those changes. So you might write a JSON file in your program which info-beamer then instantly notices and loads. See the function util.file_watch to learn more about this.
  • You can connect using TCP to info-beamer and send data to a running visualization. This way of communicating with info-beamer also allows a running visualization to export data to an external program. There's going to be a blog post about this in the future.
  • You can send data using UDP. This way of communicating is recommended if you have lots of small updates that you want to send to your visualization.

This blog post will use UDP to send the current bitcoin exchange rates in multiple currencies to a visualization that displays those values on screen. First let's have a look at the code for the visualization (save this code in the file node.lua):

gl.setup(1024, 768)

local json = require "json"
local font = resource.load_font "font.ttf"

local currencies = {}

node.alias "bitcoin"

util.data_mapper{
    update = function(data)
        currencies = json.decode(data)
    end
}

function node.render()
    gl.clear(1, 1, 1, 1)
    font:write(30, 10, "Bitcoin", 100, .5,.5,.5,1)
    local y = 120
    for idx, currency in ipairs(currencies) do
        local line = string.format("%.2f %s", currency.val, currency.sym)
        font:write(30, y, line, 160, .3,.3,.3,1)
        y = y + 160
    end
end

In the first line the visualization resolution is set to 1024x768 and the bundled json parser as well as the font file font.ttf is loaded. Just download any Truetype font file and place it in the current directory. I used Arial.ttf and renamed it to font.ttf.

The currencies variable contains a list of exchange rates for different currencies. Since we don't know these values yet we'll initialize it to an empty list for now. This list will later be updated by an external program.

The node.alias function sets the node alias name to bitcoin. Normally the name of a node is its directory name. Using node.alias allows you to set an alias that is independant of the directory name. External programs can address nodes using either of those names. By setting the alias bitcoin, external programs can now be sure that they reach this node when sending data to bitcoin.

Setting up data handlers

The util.data_mapper is where the magic happens. It defines Lua functions that can be called by external programs. To do that these programs send UDP messages to info-beamer. Here's what a messages has to look like:

bitcoin/update:[{"value": 123, "symbol": ":-)"}]

The part before the colon specifies the name of the info-beamer node (bitcoin) and the handler (update) that you want to send data to. The part after the first colon is the data that will be delivered to this handler. Now when you have another look at the usage of util.data_mapper, you'll see that there is a single handler called update defined:

util.data_mapper{
    update = function(data)
        currencies = json.decode(data)
    end
}

This handler will be called with the data as first argument. In this example the handler just parses this data as JSON and updates the variable currencies.

The remaining code in node.render is doing the visualization: It clears the screen, writes Bitcoin in large friendly letters and then iterates over the list of currencies and displays their value.

Let's run this info-beamer visualization:

pi@raspberry ~/bitcoin-example$ info-beamer .

Sending data to your visualization

Well. That's boring. The currencies variable is empty so there's nothing to display right now. Let's send some data to the running info-beamer visualization. So open another terminal and type this command:

pi@raspberry ~$ echo 'bitcoin/update:[{"val": 123, "sym": ":-)"}]' > /dev/udp/localhost/4444

This instructs your command shell (bash) to send data using UDP to the local machine (that's your PI!) on port 4444. info-beamer listens to port 4444 so the data you send ends up being handled by info-beamer. This is what the screen looks like:

Using an external program

Let's use an external program to fetch the current bitcoin value using HTTP and send it to info-beamer. I'll use Python in this example but you can use the programming language of your choice to do that. The important thing is that you send data to info-beamer. Here's what the python program looks like:

#!/usr/bin/python2.7
import socket, json, time, requests

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

DISPLAY_CURRENCIES = ['USD', 'EUR', 'GBP']

while True:
    ticker = requests.get("https://blockchain.info/ticker").json

    currencies = []
    for currency_name in DISPLAY_CURRENCIES:
        currencies.append(dict(
            val = ticker[currency_name]['last'],
            sym = ticker[currency_name]['symbol'],
        ))

    data = json.dumps(currencies, ensure_ascii=False).encode("utf8")
    print data

    sock.sendto("bitcoin/update:%s" % data, ('127.0.0.1', 4444))

    time.sleep(60)

This program uses the awesome requests library for python to do HTTP requests. It gets the current bitcoin exchange rates from the bitcoin.info API.

It gets the currencies to display (as defined in DISPLAY_CURRENCIES) from the returned value of the bitcoin.info API and creates the list that the info-beamer visualization needs.

It then encodes this list as JSON and sends it to the running info-beamer on localhost. It's using an UDP socket for that. Finally it sleeps 60 seconds so it doesn't overload the bitcoin.info API. Here's what info-beamer was showing on Nov 2, 2014:

Summary

I hope that this posting explained the basics of sending data to a running info-beamer visualization. Using external programs is the proper way to get dynamic data into your visualizations. Use the programming language you like the most to fetch and enrich data and send it to info-beamer.

Not only can you use any library and language you're already familiar with - it also decouples the visualization part from the potentially more complex data enrichment part.

To see more examples on how to use external data, have a look at this visualization from a conference, a remote controlled slideshow or an example on how to synchronize two info-beamer nodes.


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!