Chef de Cambuse

...cooking, cruising and wine

Entries in the Category “python”

Pont Mirabeau - an UPnP bridge

written by Frank, on Jun 30, 2009 10:56:00 PM.

What started over a year ago as a vague idea and got more concrete in a first prototype last October, is now ready for a first public beta - Mirabeau, an application level proxy for UPnP devices using XMPP as a transport to establish a connection between two or more local networks over the Internet.

Or in less technical terms, it allows the DLNA capable TV at your parents place to access for instance the images of your last vacation stored on an UPnP MediaServer in your home.

Mirabeau is part of Coherence and utilizes the D-Bus interface there to create a transport layer over XMPP with the help of Telepathy’s tubes.

Philippe and I will give a presentation about it during this years Gran Canaria Desktop Summit.

Mirabeau addresses the issue that UPnP is only meant to be used in a local network. With Mirabeau we are able to easily interconnect two or more networks and the UPnP devices therein. All that with a simple, well-used setup - Jabber, and without the need for complicated VPN-tunnels or similar techniques.

Philippe wrote already about our first successful - world premiere - connection with our two networks in Spain and here in Germany, where we tested the whole infrastructure with the UPnP-Inspector.

What I would like to highlight here is the point that arbitrary UPnP devices do participate in this.
Mirabeau is a transparent bridge for UPnP devices on the application level, not only an ‘I can share my media collection between two instances of the same software’ setup.
Which is of course nice too, but we lifted that to a more higher level and instantly integrate everything that can talk UPnP - PS3, Xbox 360, Totem

Nokia MediaStreamer browsing Phil's server in Spain

An unmodified UPnP application on the N810 - Nokia’s MediaStreamer is browsing Phil’s server in Spain.

And the same by a Playstation 3:

PS3 browsing Phil's server in Spain PS3 browsing Phil's server in Spain

So if you are interested in this or want to know more don’t miss our talk @ GCDS, or join us on IRC freenode #coherence.

Coherence 0.6.0 - the late pumpkin

written by Frank, on Jan 1, 2009 1:54:00 PM.

One of my last computer related activities in 2008 was releasing version 0.6.0 of the Coherence DLNA/UPnP framework.

The plain facts first:

Kudos go especially to jmsizun, lightyear and superdump for their work on the new backends and their patient debugging sessions!

There are some remarkable things - beside the technical improvements or the feature additions - that make this release special.

Community created backends - just awesome!
A huge THANK YOU to you guys! And seeing them appear in such a short time of development shows that the backend, the data-provider centric approach of Coherence was the right way to go.

More online and social content providers!
The Flickr MediaServer was only the beginning. With more backends that retrieve their media via some RSS feed or an API provided by an service like You-Tube or GoogleVideo, Coherence will more and more evolve into a media-hub.
A media-gateway that does provide a central place to go for accessing digital media of different origins and types, via an unified and standardized form. And still leaving the choice to you which device or application to use for that.

Applications!
With the new Eye of Gnome plugin one of the last UPnP jigsaw piece for the Gnome desktop has found its place.
After the RhythmBox plugin for audio, the Totem plugin for audio and video, images served via UPnP can now be accessed via the Eye of Gnome image viewer.
And with Nautilus on the other side there is an easy way to instantly share media or interact with other UPnP devices.

The last puzzle piece is enabling Nautilus to browse UPnP A/V MediaServers in its native way. I'm confident that this is a solvable, short-term task.

Wouldn't it be amazing if other environments would be able to benefit from the work done there too.

And there a more things to come.
In the pipeline for the next releases there are amongst others:

A Happy and Peaceful New Year!

Coherence and Nautilus - Brothers in Arms

written by Frank, on Oct 26, 2008 10:30:00 PM.

One of the things I had on my list - unfortunately that list is quite long atm - was bringing Nautilus - Gnomes filemanager - and Coherence together.
Nautilus has the possibility to add something via an extension - luckily these extensions can be in Python too.

So it was pretty straight forward to add to Nautilus:

  • sharing one or more folders as a DLNA/UPnP MediaServer, allowing clients like the PS3 or the Nokia N810 to access these files
  • accepting files send from an ControlPoint
  • uploading files itself to other DLNA/UPnP MediaServers that allow media to be imported
  • instruct a MediaRenderer to playback a given file
You can watch the demonstration video here:

the link to Google Video, just in case that embedded player isn’t working

More details, download and install instructions as usual on the Coherence site.

As you might notice, there is one part missing - having Nautilus display and access the content of other MediaServers in the network.
This can’t be done with an extension, here the gvfs backend needs to be modified. But as Coherence exposes the MediaServers via DBus, a small layer mapping Nautilus’ requests to Coherence’ signals and methods shouldn’t be that difficult?

there will be light

written by Frank, on Mar 16, 2008 12:35:00 PM.

Over the last days I’ve added support for the UPnP Lighting Controls V 1.0 to Coherence.

Although there aren’t yet much application areas for this specification outside of maybe some futuristic showrooms and research laboratories - and here at my place with my little UPnP <-> EIB bridge - but that specification addresses one of the biggest obstacles when it comes to home-automation.

The need to know/to program the unique id of a new device you bring into your household and to establish the connection between a switch and that device, is in all serious automation systems diametrically opposed to the wish of the ordinary customer who just wants to buy a new lamp, plug it in and have it working.

Newer systems like digitalstrom or ZigBee take that (partially) into account, but here too UPnP has the potential to model a unified layer above the system and vendor specific peculiarities.

And having that in Coherence is a nice demonstration of the simplicity implementing a device with it anyway.

class SimpleLight(Backend):

    """ this is a backend for a simple light
        that only can be switched on or off

        therefore we need to inform Coherence
        about the state, and a method to change it

        everything else is done by Coherence
    """

    implements = ['BinaryLight']
    logCategory = 'simple_light'

    def __init__(self, server, **kwargs):
        self.name = kwargs.get('name','SimpleLight')
        self.server = server
        self.state = 0 # we start switched off
        louie.send('Coherence.UPnP.Backend.init_completed', None, backend=self)

    def upnp_init(self):
        if self.server:
            self.server.switch_power_server.set_variable(0, 'Target', self.state)
            self.server.switch_power_server.set_variable(0, 'Status', self.state)

    def upnp_SetTarget(self,**kwargs):
        self.info('upnp_SetTarget %r', kwargs)
        self.state = int(kwargs['NewTargetValue'])
        if self.server:
            self.server.switch_power_server.set_variable(0, 'Target', self.state)
            self.server.switch_power_server.set_variable(0, 'Status', self.state)
        print "we have been switched to state", self.state
        return {}
Yep, that’s all. :-)

From the three UPnP actions the SwitchPower service defines, only one is actually needed to implement, the other two actions can be handled by Coherence autonomously.

Coherence 0.5.0 release

written by Frank, on Jan 1, 2008 12:54:00 PM.

Exactly one year after Coherence went public, I had the pleasure to release version 0.5.0.

The topics of this release are:

  • better DLNA support, in particular for the Sony Playstation 3
  • a MediaServer backend for Shoutcast internet radio streams
  • an experimental last.fm MediaServer backend for the last.fm service
  • methods to remove local devices from a Coherence instance
  • slow move to an XML based configuration file
  • support for BSD systems - thx kraft!
  • an emerging D-Bus interface
  • more platform independency for our Twisted inotify module,
    using libc when possible
  • and a lot more of the usual bugfixes and enhancements

A Happy New Year!

import antigravity

written by Frank, on Dec 5, 2007 8:44:00 AM.

Python IS awsome.

Welcome Randall Munroe, had much fun reading your strips even before!

accessing Flickr the UPnP way

written by Frank, on Jan 20, 2007 9:46:00 PM.

As a follow-up to my last post about the GStreamer backend for Coherence I’m happy to announce now the Coherence Flickr UPnP A/V MediaServer backend.

What does it do:

  1. it connects to Flickr via the Flickr API and enquires a list of interesting photos for the most recent day
  2. it provides that list via the ContentDirectory service to other UPnP A/V enabled devices

So if you have such a multi-functional home-automation touch-panel like mine or one of these tvs with a build-in UPnP A/V client you can now enjoy an ever changing stream of photos coming to your living room.

Of course there will be Flickr enabled picture frames popping up from every manufacturer climbing on the bandwagon - which will definitly have their right to exist, especially if they are used in a isolated environment - but if you are in a connected home it sounds unreasonable to supply configuration to every device all over the place.

Hence the charm of these few lines of Python code lies in its possibility to make Coherence the one-stop-shopping media gateway.

I'll add a few more features over the next days:

  • enquire user, group or tag based photo lists
  • optionally only show photos in landscape format
  • define picture quality to download
  • make the number of photos returned configurable, currently it is limited to 100
  • recheck with the Flickr service every e.g. 180 minutes and fetch new photo urls
  • maybe act as a proxy to Flickr for devices which are not able to connect to something outside the home lan

And something I would like to add too, but this will take some more time, is a mapping between the UPnP ContentDirectory ImportResource() and CreateObject()/MoveObject()/… actions to the Flickr upload API.

glueing together GStreamers playbin and Coherences UPnP A/V MediaRenderer

written by Frank, on Jan 11, 2007 2:28:00 PM.

In an attempt to work on the documentation and as a practice finding the words to explain how Coherence ticks I'll try to throw some light on how the GStreamer playbin backend and Coherence are glued together to form an UPnP A/V MediaRenderer device.

A device in UPnP speak is a logical something - a grouping of services. A MediaRenderer as an example needs to support

  • a RenderingControl service, which is responsible for adjustment of volume, loudness, brightness,…
  • a ConnectionManager service, used to enumerate and select the transfer protocol (http, rtsp/rtp,…) and
    data format (mp3, ogg,…) to be used for transferring the content
  • an AVTransport service, optional - depending on the transfer protocols the ConnectionManager supports. But if available used to specify the content to be played, start/stop/pause a playback, seek in the content stream,…

These services can be controlled and queried with so called Actions, e.g. SetVolume() and GetVolume(), and hold their current state in so called StateVariables, e.g. Volume. A call to SetVolume() sets the volume value on the actual rendering engine and reflects that change in the variable Volume. And a call to GetVolume() retrieves the value from that variable. Furthermore a service is supposed to propagate the values of these variables on change to interested parties, e.g. to an UPnP ControlPoint.

Now one of the basic principles of Coherence is to seal off the backend – the actual rendering engine, in this case the GStreamer playbin – from the UPnP related tasks (and later from the D*AP ones) as much as possible.

This means that a backend should only need to

  1. tell Coherence what kind of device(s) it wants to resemble, e.g. a MediaRenderer
  2. define specific conditions, e.g. that is supports only decoding of mp3 content
  3. provide methods Coherence can access when an action is called that has effects on the backend engine, e.g. a volume change
  4. inform Coherence about state changes, e.g. the end of the media content is reached and playback has stopped

Everything else is the job of Coherence:

  • propagate the device on the network (SSDP/MSEARCH)
  • generate the necessary device and service descriptions with reasonable defaults, corresponding to the backends capabilities
  • provide the control interfaces to the actions the services have
  • handle all event subscription and propagation tasks (GENA)

This means also, that all actions with no effects on the backend engine are handled completely within Coherence, like an action that retrieves only a variable value. Of course a backend can override this if it wants to, but basically there is no need to do it.

In our GStreamer playbin case this (simplified) looks like this:

class Player:

    """ see item 1. above """
    implements = ['MediaRenderer']

    """ see item 2. above """
    vendor_value_defaults = {'RenderingControl': {'A_ARG_TYPE_Channel':'Master'},
                             'ConnectionManager': {'SinkProtocolInfo', 'http-get:*:audio/mpeg:*'}}
    vendor_range_defaults = {'RenderingControl': {'Volume': {'maximum':100}}}

    def __init__(self, device):
        self.player = gst.element_factory_make("playbin", "myplayer")
        self.device= device

    def set_volume(self, volume):
        """ here the actual volume change takes place """
        """ gstreamer playbin has a volume range from 0.0-10.0 """
        self.player.set_property('volume', float(volume)/10)

         """ feed back the new state - our item 4. """
        rcs_id = self.device.connection_manager_server.lookup_rcs_id(self.current_connection_id)
        self.device.rendering_control_server.set_variable(rcs_id, 'Volume', volume)

    def upnp_SetVolume(self, *args, **kwargs):
    """ that's a method referred in item 3. """
        InstanceID = int(kwargs['InstanceID'])
        Channel = kwargs['Channel']
        DesiredVolume = int(kwargs['DesiredVolume'])
        self.set_volume(DesiredVolume)
        return {}

This is not perfect and not final yet and there will be some changes especially in the way how item 4. is handled. But the purpose of that backend is among other things to straighten out the bumpiness of these glue points.

And btw., in this backend the engine is embedded, but as stated in an earlier post, there is absolutly no reason why instead of calling self.player.set_property to set the volume this couldn’t be some ipc call (xml-rpc, dbus, Twisted PB,…) or an IR/ZigBee/ZWave signal emitted.

Coherence - a Python framework for the Digital Living

written by Frank, on Dec 31, 2006 4:51:00 PM.

As one of my last computer related acts this year I want to set Coherence free.

Coherence is a framework, written in Python and based on Twisted, enabling your application to participate in digital living networks. At the moment it is focused on the UPnP universe, but others will follow.

It is not (yet) for instance an UPnP MediaServer with all bells and whistles, although the enclosed device implementation is already quite functional.

But I see its utility in any case more as a bridging tool to connect something so far isolated straightforward e.g. to other UPnP devices. It is somehow part of a concept I’ve worked on in the home-automation area over the last years - a thing I called ‘Weltenkoppler’, building bridges between the (digital) islands.

Thus Coherence will in some future allow us to

But for now I wish all of you out there a truly Happy New Year and cu again in 2007!

EIB time-signals

written by Frank, on Apr 27, 2006 1:27:00 PM.

Quite some EIB devices have time-controlled actions nowadays, for example the GIRA Tastsensor 2plus. But apparently their internal clock has its own interpretation of time and seems to lose any contact with reality shortly.

One way to get around this is to use an EIB time emitter, something with a buildin DCF77 receiver, cyclically sending a time telegram on the bus.

On the other hand, with our eibcontrol homeserver and a simple NTP setup, we can achieve the same with just a few lines of code.

We need to add a dummy group address to the homeserver’s xml-database, something like this:

<node name="0" alias="central functions">
    <node name="0">
        <node name="40" alias="timer">
            <node name="valuelength">3</node>
            <node name="eistype">3</node>
            <node name="curvalue">0</node>
        </node>
    </node>
</node>

Now armed with some knowledge about the time encoding in an EIS 3 type (p.15) writing a little (Python) script that, when invoked, sends the current time to the above defined group address isn’t a big deal anymore.

#!/usr/bin/python
#
# _example_(!) python program for eibcontrol communication
# (c) 2006 Frank Scholz, dev * netzflocken . de
#
# eib_sendtime.py -a 0/0/40 
#

import socket,string,time,struct

HomeServer        =       '127.0.0.1'
HomeServerPort    =       8081 
EIBaddress        =       (0,0,40)

write_request = """<eib type="write" path="/eib/groups/%d/%d/%d/curvalue" data="%ld"/>\n"""

def eib_set( server, port, address, value):
    result=""
    state="false"
    s=socket.socket( socket.AF_INET, socket.SOCK_STREAM)
    s.connect( (server, port))
    request = write_request % ( address[0], address[1], address[2], value)
    s.send( request)
    result = s.recv( 1024)
    s.close()

    if( string.find( result, "state=\"true\"") != -1):
        state="true"
        result=result[ string.find( result, "data=\"")+6:]
        state=result[ 0 : string.find( result, "\"")]

    return( state)

def eis3_build( day, hour, minute, second):
    r = day<<21|hour<<16|minute<<8|second
    return struct.unpack("L", struct.pack("!L", r))[0]>>8


t = time.localtime(time.time())
value = eis3_build( t[6]+1, t[3], t[4], t[5])
eib_set( HomeServer, HomeServerPort, EIBaddress, value)

Download: a slightly longer version with parameter handling

Now put this in a crontab and you are all set.

Currently the eibcontrol homeserver whinges about not receiving an ack from the bus for his “write”-request. As there is no “send-only”-request we need to simulate this for now and live with the otherwise effectless nagging.