himbeerecouch

nEDM Experiment

himbeerecouch

Repository

Sub-pages:

Python module for handling communication/code deployment on to the nEDM Raspberry Pis.

Information

himbeerecouch provides a daemon which obtains code from the CouchDB database to run on a particular Raspberry Pi. It also listens for changes and restarts itself whenever code is updated in the central database. Code is generally updated on the web interface.

Installation/Upgrade:

With pip:

pip install --upgrade --process-dependency-links https://github.com/nEDM-TUM/HimbeereCouch/tarball/master#egg=himbeerecouch

Requirements

  1. RPi.GPIO (optional), needed to access GPIO pins in user code.

Note: on the nEDM raspberries that Netboot, this is already installed. See that documentation for instructions on how to update.

Deploy on a standalone Raspberry Pi:

(Note, one can do this once on a single Raspberry Pi, and copy the SD card for future Raspberry Pi. If this is done, then you only need to start from step #3.) For the nEDM experiment, we use an NFS boot so that the Rasp-Pis always have the same OS/software.

There are two options:

  1. (preferred) on systems with supervisord installed, install the following in e.g. /etc/supervisord/conf.d/raspberry.conf:
[program:raspberry]
command=python -c 'import himbeerecouch.prog as p; p.run("/etc/rspby/server")'
autostart=true
autorestart=true
stopsignal=INT
redirect_stderr=true
stdout_logfile=/var/log/rspby_daemon.log

or

  1. Download/install the daemon at init_scripts/rspby:
  2. e.g. in /etc/init.d
  3. Set up folders for log/pid file/server file (default, /var/rspby)
  4. Edit /etc/rc.d or relevant file to start daemon on boot

then:

  1. Connect Rasp Pi to network.

Determine credentials

Once connected, there are two options to determine which password/user name to setup in the database:

  1. (Option 1) On local machine also connected to network, run:
>>> import himbeerecouch
>>> himbeerecouch.broadcast_message("http://server.name:5984")
# ... should return the following
{ "MacID" : 1234566, "password" : "apassword" }

Sometimes this doesn’t work (depending upon UDP forwarding on network). If so, use (Option 2)

  1. (Option 2) On Rasp Pi
>>> import himbeerecouch
>>> himbeerecouch.util.getmacid()
12345678901234L
>>> himbeerecouch.util.getpassword()
'apassword'

Use these credentials to set up a user on CouchDB with access to the chosen database (default nedm/raspberries). (See here for more information.)

Running code

Single module mode

The Daemon expects documents to be submitted to the database (default nedm/raspberries) that look like:

{
  "type" : MacID # This is an integer!
  "name" : "Name of code"
  "code" : "   ... python code here "
}

It attempts to load the code in "code" as a module, and runs the main function in the module. The daemon will react whenever a new document is loaded/updated. The code should look like:

def main():
    # This code is executed.  It has access to the following functions:
    #     log(*args)  : logging function
    #     should_quit()  : check if this code should exit (useful for daemons)
    #     register_quit_notification(afunc)  : registers a quit notification, i.e. function 'afunc' is called when this code should exit
    #     remove_quit_notification(afunc)  : deregisters a quit notification

Multiple module mode

Note, that it is also possible to pass your code in module form, for example:

{
  "type" : "macid_of_rasperry<int>", # i.e. value returned by getmacid()
  "name" : "name of the code",
  "modules" : { # these are modules used by this local code
    "name_of_module1" : "<python code>",
    "name_of_module2" : "<python code>",
    ...
  },
  "global_modules" : { # these modules will be exported to *all*
                       # code in this database
    "name_of_global1" : "<python code>",
    "name_of_global2" : "<python code>"
  },
  "code" : "<python code>" # This is the main module, it *must* include a
                           # `main` function
}

Note, all of these are optional. If e.g. "code" is omitted and there is no "main" in "modules", then only "global_modules" will essentially have any effect as they will be exported to other code in the database.

Running arbitrary commands

The daemon will respond to the insertion of a document that look like:

{
  "type" : "MacID_cmd" # MacID is an integer in the string!
  "cmd" : [ "acommand", "flag1", "flag2" ... ]
}

and update the document to be:

{
  "type" : "MacID_cmd" # MacID is an integer in the string!
  "cmd" : [ "acommand", "flag1", "flag2" ... ],
  "ret" : [ "return string from accomand" ]
}

Available pages