Home of the Squeezebox™ & Transporter® network music players.
Page 1 of 3 123 LastLast
Results 1 to 10 of 24
  1. #1
    Junior Member
    Join Date
    Mar 2017
    Posts
    9

    Subscribing to server events from Python?

    Hi all,
    Newly registered (although I think I did register seveal years ago....) member here - long time user of Squeezebox Classic, for the past two years replaced by different other HW (thin clients running Daphile, Raspberry Pis running various incarnations of LMS....).

    I also dabble in making stand-alone music players/servers, and have some (very basic) experience with messing with the internals of various Linux-based systems.
    I've made a nice server using RasPi and Rune Audio (MPD-based audio server), putting it in a nice enclosure with built-in 16x2 character LCD, with the additon of a nice IR remote (for which I also did some work on the Python I2C driver) - see the attached photo...

    Now I've decided to do the same, but using LMS (LMS server and squeezelite player in one compact standalone solution). I can reuse large part of the Python code responsible for communicating with LCD from my earlier work with Rune Audio - that's not the issue here.

    However, since my Perl is quite rusty (and I never was any good at it, to be honest), even after several days of digging through the forum, and trying this and that, I still need some rather basic help.

    Namely, I need to find (or insert into existing code) some kind of "trigger" which would "notify" my Python daemon that one of the events I'm interested in has happened - i.e. start/stop/pause/play, new track and volume change - in order to show those events immediately on the LCD.

    I've checked the "subscribe" CLI command, using "telnet localhost 9090", and saw that I could e.g. use something like:
    Code:
    subscribe mixer,pause,stop,play,playlist newsong
    ... and I *do* get notified of the events I'm interested in.

    However, I'm at a loss of how to use this functionality as a kind of "service" that my Python daemon would subscribe to. I don't have a problem with parsing the received results, I can take care of that...

    I've also managed to extract useful information from json/rpc, by using, e.g. this:

    Code:
    curl -s -d '{"id":1,"method":"slim.request","params":["OPiSqueeze",["status","-",1,"tags:al"]]}' my-local-host:9000/jsonrpc.js | ./myhandler.py
    where "myhandler.py" parses the JSON result, and gives me something like this:

    Artist: Bob Dylan
    Title: Blowin' in the Wind
    Album: The Freewheelin' Bob Dylan
    Source: File

    I can also see whether it's a file or e.g. radio playing, by seeing if the JSON result has 'remote' string in it, so that's also taken care of.... (I can see if the SOURCE is either e.g. "file" or "streaming").

    I'd actually like more to use the JSON results than mess with telnet CLI (and the JSON result using curl also seems faster....), so if anyone has any suggestions/advise how to get the JSON result using the above mentioned "trigger event", I'm all ears.

    In short, I need advice on either/or:

    1) how to "subscribe" to CLI events as described above using Python
    and/or
    2) how to do detect a "trigger" for the events I'm interestd in, and get a full json response (like with 'curl' command above)?

    The system I have worked on (Rune Audio) has a PHP worker script, and the developers have provided for such requirements - in their source code I can insert invocation of my bash script or a Python script, whatever.... I know exactly the place where the event has happened, and can insert my code there...
    Rune Audio example (PHP script):

    Code:
    //// ORIGINAL CODE
    // save JSON response for extensions
    $status['actPlayer'] = "MPD";
    $redis->set('act_player_info', json_encode($status)); // this provides a JSON encoded status info (track, artist, volume, etc.) - similar to LMS status 
    
    ////MY ADDITION BELOW
    // here goes the call to my Python script with $status - for MPD
    shell.exec('juggler.py ' . escapeshellarg(json_encode($status)) . '> /dev/null 2>&1 &'); // calls my Python script which parses the JSON data and sends info to LCD
    // end of my addition
    So, it would be nice if someone could direct me exactly how I could achieve something like this on LMS Linux (RasPi) installation...
    Basically, I want to reflect changes in the Web UI (change of track, change of volume, stop/start/pause) on my LCD, showing artist and track (if the file or stream is playing) or "Stopped" or "Paused" if that is the status.
    BTW, I've already solved the IR remote and remote comands, like this:

    Code:
    #!/bin/bash
    (echo "playlist index +1")|nc -w1 localhost 9090
    - this is a bash script command assigned to the "next" button on the remote....

    So, most of the stuff is in place, but I just need to find the way to "glue" everything together - and for that, I need to find where and how to activate the proper "event trigger(s)"....

    Sorry for the rather long-winded first post

    Any help would be greatly appreciated!

    TIA,
    Denis
    Attached Images Attached Images  

  2. #2
    Senior Member
    Join Date
    Aug 2012
    Location
    Austria
    Posts
    599
    subscribe using cometd
    Or just use polling - even the native Web UI uses this approach.
    [ extGUI4LMS - an alternative web interface: forum / homepage | music visualizer for squeezelite ] [ Howto: build a self-contained LMS | Howto: play Ogg Opus files ]

  3. #3
    Junior Member
    Join Date
    Mar 2017
    Posts
    9
    Quote Originally Posted by Roland0 View Post
    subscribe using cometd
    Or just use polling - even the native Web UI uses this approach.
    I'll check comet, although at first sight it looks awfully complicated
    As for polling, that's an approach I'm trying to avoid at all costs, since it seems like a huge waste of processing power - and the response times are not actually immediate....

    In the meantime, I've found one existing Python script for just this purpose:
    https://github.com/surfatwork/lcd_sq...lcd_squeeze.py
    The last part of the script ("# Now start main telnet session and listen") shows that the author used subscription via telnet, and I think that's an example I could use, with perhaps slight modifications.
    So far it looks like it's doable even with my poor programming skills, unlike a couple of other examples I've stumbled upon.... We'll see...

    After reading lots of threads here on the forum, I'm actually surprised that there is no obvious way to "pinpoint" an exact location in the code where a new event has occurred (song change, start/stop, etc.), so that one can use that information as a trigger in e.g. various plugins and add-on scripts - or at least I couldn't find anything of the kind....

  4. #4
    Senior Member Greg Erskine's Avatar
    Join Date
    Sep 2006
    Location
    Sydney, Australia
    Posts
    1,143
    hi Den_HR,

    Slimmer might be worth looking at as well.

    https://github.com/terba/slimmer/

    There are also few other LCD threads over the years using various python scripts.

    Jivelite might be worth looking at as well. This is closer to the "real" Squeezebox solution. It uses lua instead of python. The underlying code must be talking to LMS.

    regards
    Greg

  5. #5
    Senior Member
    Join Date
    Aug 2012
    Location
    Austria
    Posts
    599
    Quote Originally Posted by Den_HR View Post
    As for polling, that's an approach I'm trying to avoid at all costs, since it seems like a huge waste of processing power -
    It's not - Logitech themselves are using this approach (and so do most clients - the other subscribe with cometd), and it doesn't register even on a very slow server.

    and the response times are not actually immediate....
    The LMS Web UI polls every 750/950/... ms, seems to be fast enough - nobody needs real time for something like this

    In the meantime, I've found one existing Python script for just this purpose:
    Well, if you are really this worried about inefficiencies, then you shouldn't use it - it opens a new telnet session for every single piece of metadata, so for your example, that's 4 external processes, network connections and server requests.

    After reading lots of threads here on the forum, I'm actually surprised that there is no obvious way to "pinpoint" an exact location in the code where a new event has occurred (song change, start/stop, etc.), so that one can use that information as a trigger in e.g. various plugins and add-on scripts - or at least I couldn't find anything of the kind....
    For server plugins, there is a event subscribe API function (so you could call your script directly from it after receiving the event). For external clients, you have subscription with cometd and telnet, and polling via JSON/RPC, http and telnet. Seems to me there are really a lot of options.
    [ extGUI4LMS - an alternative web interface: forum / homepage | music visualizer for squeezelite ] [ Howto: build a self-contained LMS | Howto: play Ogg Opus files ]

  6. #6
    Senior Member pippin's Avatar
    Join Date
    Oct 2007
    Location
    Berlin
    Posts
    13,956
    Quote Originally Posted by Den_HR View Post
    I'll check comet, although at first sight it looks awfully complicated
    As for polling, that's an approach I'm trying to avoid at all costs, since it seems like a huge waste of processing power - and the response times are not actually immediate....
    But JSON/RPC is a request/response protocol, you can't subscribe using it, the server would have no place to send the reply to.

    If you want to subscribe you need to use cometd or the raw CLI.
    I would avoid the CLI since it doesn't have all the functionality and you need a separate port and do your own browsing which leaves cometd or polling.

    I do both in iPeng: I use cometd for the updates in the main app and polling on the watch and in the widget.

    BTW you are wrong about resource usage. If you use reasonable polling intervals (like every 15s or so) the load for polling is typically lower since you don't have to keep a streaming connection open and also depending on the updates you use LMS can be a bit chatty.
    ---
    learn more about iPeng, the iPhone and iPad remote for the Squeezebox and
    Logitech UE Smart Radio as well as iPeng Party, the free Party-App,
    at penguinlovesmusic.com
    New: iPeng 9, the Universal App for iPhone, iPad and Apple Watch

  7. #7
    Junior Member
    Join Date
    Mar 2017
    Posts
    9
    Thanks for all the replies so far, that's really helpful.

    Quote Originally Posted by Roland0 View Post
    For server plugins, there is a event subscribe API function (so you could call your script directly from it after receiving the event). For external clients, you have subscription with cometd and telnet, and polling via JSON/RPC, http and telnet. Seems to me there are really a lot of options.
    Could you please provide a bit more detail on how to do use the "event subscribe API function"?

    Another possibility is to subscribe using telnet, as in the linked script - however, avoiding calling telnet for each event - that part is messy and unnecessary, agree with that

    As for polling, I'm trying to avoid it, since I would have to poll at least every half a second, if I want the LCD to be at least reasonably responsive....

    The thing is, I want the LCD to provide visual feedback in real time (almost). Any lag leads to a lot of grief - e.g. if you have a user who's not familiar with the system, he'll pres "VOL UP" key on the remote, and if he doesn't see the LCD info change, he might press it again immediately, thus queuing the keypresses unnecessarily, and clogging the LCD display stack.... Best avoided - ask me how I know

    So, the point is to have the 16x2 character LCD show any changes (start/stop, volume change, track change) as quickly as possible. Polling every 15 secs is absolutely out of the question, since I'm talking about headless use situation, when the user is controlling the device using IR remote, and the only feedback he has is the built-in LCD. That's how I set up my Rune Audio-based systems.

    Perhaps I'm too prejudiced as regards polling, but I'm leaning more towards the telnet "subscribe" solution. The server replies do tend to be rather verbose, though - particularly with track change. E.g. when I subscribe to "playlist newsong", the info I get back includes also the loading of new file, and the actual track change (with track name) comes only as the last line after several lines of "surplus" info... Volume changes and start/stop/pause events are much better, simple one-liners

    I'm even thinking about a combination of telnet subscribe to events I'm interested in, and then, after the event has been triggered, getting more detailed (and structured) information using the one-liner CLI command, as mentioned previously, like this:

    Code:
    curl -s -d '{"id":1,"method":"slim.request","params":["OPiSqueeze",["status","-",1,"tags:al"]]}' my-local-host:9000/jsonrpc.js | ./myhandler.py
    - and then parsing that in my "myhandler.py" script... Not very efficient, probably, but I'll see how fast the response times are. Perhaps the "event subscribe" API that Roland mentions could be put to use instead, if it provides a more elegant (and faster) solution...

    Everything depends on how quickly I can get the relevant info displayed on the LCD....

  8. #8
    Senior Member pippin's Avatar
    Join Date
    Oct 2007
    Location
    Berlin
    Posts
    13,956
    That kind of response time won't work with subscriptions as well.
    The server doesn't necessarily send the notifications that fast and especially for volume events it waits up to a few seconds because it accumulates several volume change events to not send out too many status updates.
    I believe the notification only goes out if the volume hasn't changed for a second or so.

    Half-seconds polling would probably bring down your server.

    If you need that fast a response time you need to write a Perl plugin and use the API functions Roland0 mentioned - don't ask me for details, I'm not a server programmer.
    ---
    learn more about iPeng, the iPhone and iPad remote for the Squeezebox and
    Logitech UE Smart Radio as well as iPeng Party, the free Party-App,
    at penguinlovesmusic.com
    New: iPeng 9, the Universal App for iPhone, iPad and Apple Watch

  9. #9
    Senior Member
    Join Date
    Aug 2012
    Location
    Austria
    Posts
    599
    Quote Originally Posted by Den_HR View Post
    Could you please provide a bit more detail on how to do use the "event subscribe API function"?
    Code:
    Slim::Control::Request::subscribe( \&commandCallbackVolume, [['mixer']]);
    As for polling, I'm trying to avoid it, since I would have to poll at least every half a second, if I want the LCD to be at least reasonably responsive....
    I'd still maintain that there is basically no performance penalty in polling, even at this rate
    - LMS WebUI polls for all information (even the song position / progress bar)
    - The above mentioned slimmer (which does setting & displaying volume on a LCD) polls every 500ms

    As an example, polling with the request you use puts no load on the server. Here are some measurements (server CPU is a low-end Celeron from 2011):
    every 500ms (0%-1% CPU on one core):
    Name:  poll500ms.png
Views: 119
Size:  5.5 KB
    every 100ms (1%-3% CPU on one core):
    Name:  poll100ms.png
Views: 120
Size:  5.8 KB

    Perhaps the "event subscribe" API that Roland mentions could be put to use instead, if it provides a more elegant (and faster) solution...
    Sure - but it runs on the server, so you would again need an efficient mechanism to get the data to the client, which you would have to implement yourself...
    [ extGUI4LMS - an alternative web interface: forum / homepage | music visualizer for squeezelite ] [ Howto: build a self-contained LMS | Howto: play Ogg Opus files ]

  10. #10
    Senior Member pippin's Avatar
    Join Date
    Oct 2007
    Location
    Berlin
    Posts
    13,956
    OP wants to run this code on the server
    ---
    learn more about iPeng, the iPhone and iPad remote for the Squeezebox and
    Logitech UE Smart Radio as well as iPeng Party, the free Party-App,
    at penguinlovesmusic.com
    New: iPeng 9, the Universal App for iPhone, iPad and Apple Watch

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •