Sunday, May 15, 2022

Radio Now Playing plugin for LMS

-Enhancing the Squeezebox (LMS) with information about what is now playing

Over the years I have developed a few plugins for the Logitech Media Server (LMS aka slimserver).
A "plugin" is software that is added to LMS that brings additional functionality.

My first, back in 2017, was to show what is now playing on FIP - artist, track name, image and duration.
It was quite hard work to get the first one done because there is not very much documentation on how to do this in LMS and it is a long time since I have written some Perl and even when I did, it really was not very much.

Anyway - I managed to get it working and had some good responses from listeners.

I built on that and made a more generic one for Radio France (and therefore retired the FIP one) - which included their stations in the various groups (for example FIP, France Musique, France Bleu).
I made contact with a couple of people in Radio France to explain what I was doing and they seemed OK with it ... so I built more into it ... to include the ability to browse the radio schedules and replay shows from the last few days.

A few requests came in asking for stations from other broadcasters ... and I was able to make a few of them as well. Over time this meant that I had released plugins for:
ABC Australia
CBC Canada (English and totally different French service)
Planet Radio (Bauer Media) - Jazz FM, Planet Rock, Absolute etc
Supla (Finland)
KCRW
RTE (Ireland)

Each one was heavily based on one of the earlier ones but as time went on the code was diverging and becoming painful to look after. If I had to fix or enhance something then there was a chance that the change would need to be applied to 2 or 3 other code bases.
In the back of my mind was building something more generic that would allow me to add or change things in one set of code and also add new stations by simply adding a new configuration file.

I September 2021 I released the first version of this new plugin - called Radio Now Playing.

The first station that I included in it was Juke Radio - a new station from another LMS user. They were starting up and wanted to get their cover art (album covers) to appear in LMS but were not in a position to feed the image URL into their flac audio stream. So I offered to help and used this as the starting point for the more generic plugin. As I write this, that station is currently off-air - but it gave me the incentive to turn my original idea into something real.

Since then I have migrated some of the stations from individual plugins to this new one (Supla, KCRW and RTE) plus added a lot more. At the moment there are around 40 - 50 different station groups with many of them having multiple stations meaning that there are hundreds of stations in the plugin.




All sorts of different techniques are used by the plugin to get the data that it needs to show.
The most common approach is to use the JSON data that the broadcaster presents to their own web interface.
It might be as simple as a HTTP GET to return something like:
{
    "artist": "Someone",
    "title": "Something",
    "image": "h t t p :// somewhere / xxx.jpg"
}
although it is usually a lot more complex than that.

The approach has meant that sometimes it is really very easy to add in something new.
For example - a request to the Squeezebox forum asking about a station that had been removed from the usual radio listing service was added (along with 2 sister stations) in about 15 minutes without a single change to the underlying code - just the addition of a configuration file.

From here .... the only way is up






Monday, October 01, 2018

Revitalising an Audiotron - Part 1

- New life to an old device

///THIS IS A FIRST DRAFT TO GIVE SOME POINTERS SO THAT SOMEONE ELSE CAN TRY IT OUT .. it might have mistakes and sections that are not clear because this started simply as a scribble pad as I experimented.
So - if you are going to try it out then let me know and we can go through things slowly together and improve the guide.
Sorry - no pictures yet///


Long ago I wrote about my first experiences with Internet radio devices. It was the Audiotron that I started with. It still works fine but I wanted to have a go at converting it so that it can have a new lease of life.
My efforts of a while ago to get the "TurtleRadio" function within it live again and then to keep it alive plus the likelihood that keeping the old SMB client within the embedded Windows operating system working against changing household infrastructure would become more difficult in the future so I speculated to others about reusing much of the hardware but putting a Raspberry Pi inside the case to do most of the work.
This resulted in a quick response from Sam Zantos to say that it he had already done it - although his approach used a combination of Raspberry Pi and Arduino.
So I thought that I would try to do it myself and see how far I could get with only a Raspberry Pi and document the steps.

I have had this working on a Rev 1 Raspberrry Pi and the Raspberry Pi 2 that was released in February 2015.

In my case, I want it to become a "Squeezebox" client (and possibly a LMS server) so that it works with the other main components dotted around the house.
The hardware parts (display, infra-red remote, keys, rotary encoder) would be largely the same solution regardless of the software - so I will cover that first.

But before we get into that, it is important to note that if you follow the steps described here then you would be opening up your Audiotron and taking things apart and then putting them back together in a different way.
Clearly any such actions need to be taken with great care since you are working with a device that connects to an electricity supply. At no time during these steps do you need the Audiotron power to be switched on - so disconnect that first of all. But if you do reconnect it then be very careful to ensure that everything is safe and you have done nothing silly like leaving a bare wires or some jumper wires lying around inside the case.

Everything described here is undertaken at your own risk.

The detailed description of using a compatible display controller and rotary encoder at http://www.bobrathbone.com/raspberrypi_radio.htm (the PDF in particular) was the ideal starting point.

I wanted to do this in a way that would be easily reversible and something that could be tackled by someone with almost no electronics skills - so I have avoided cutting wires or soldering.

This Part 1 goes through the steps to get the LCD and infra-red remote control working with a Raspberry Pi (RPi).

So - here we go ...

Disconnect the Audiotron and open up the case - 5 screws on the back and 3 on each side. The 2 screws on each side towards the front are longer than the other. The case slides out backwards - nothing else is attached to it.
Then use Dupont/jumper cables to join up various parts of the Audiotron to the RPi.

Disconnect the ribbon cable at JP4 - by carefully pulling it upwards using the edges of the connector - not the cable. There is a red line on the cable to denote pin 1.
You can then plug in your jumper cables into the end of the cable - male in this cable and female onto the RPi GPIO connector.
Following the numbering guide below.

The Audiotron infra-red and rotary controller connects to JP3 on the Audiotron board.
My Audiotron did not have ZIF a socket for this cable. If your is the same then simply pull the cable straight up and out of the socket - do not wiggle it.
If yours has a ZIF socket then release the lock (typically by pulling up the sides) and the cable comes out very easily.

This cable is more difficult to get connected to the RPi. I managed to find a supplier of an adapter that can take this 1mm pitch FFC/FPC cable and connect it to a breadboard. They even modified their standard product to make all new shipments use ZIF sockets. So top marks to Technological Arts, Inc of Toronto Canada. I bought 2 of their ADIMMFLEX24 connectors. These are for 24-way FPC cables but we do not need that many for the Audiotron. So take care when putting the cable in to make sure that you have pin 1 lined up exactly. They were contemplating making some adapters for different numbers of pins - so if you get the choice then you need a 10 way (rotary and IR) and a 22 way (keys).
Now plug the adapter into the breadboard and then run cables to hook up the IR device.
NOTE: I could not get the IR device to work at 3.3v (3v3) so I connected it up to a 5v pin on the RPi GPIO connector. This then brings the danger of feeding 5V back into the GPIO data pin and causing damage because it cannot take that much. So it is essential to put a resistor into the circuit.

Note - shows how long ago I was working on this ... the RPi pin numbers below are for the very first Raspberry Pi model that had only 26 GPIO pins. Devices after that have 40 and that should make it much easier to connect up more of the Audiotron buttons. However, check carefully that the pins described below do remain the same for 40 pins versions (for example some might have dual purpose and need to be configured at boot time).

RPi
Pin Number
RPi
Pin Name
Audiotron
LCD
JP4
Audiotron
Rotary knob  and IR
JP3
Audiotron
Keypad
JP2
13V3


25V2 (+5V)1 (+5V) IR ***
3GPIO2
45V
5GPIO3
6GND5 (RW)6 (GND)
7GPIO4
8GPIO14
9GND1 (GND)
10GPIO15
11GPIO17
12GPIO1814 (D7)
13GPIO21 (GPIO27)
14GND3 (Contrast)
15GPIO222 (DATA) ***
16GPIO2313 (D6)
173V3
18GPIO2412 (D5)
19GPIO10
20GND
21GPIO9
22GPIO2511 (D4)
23GPIO11
24GPIO86 (EN)
25GND
26GPIO74 (RS)
Unused:
3 (Contrast adjustment)
7,8,9,10 (D1,D2,D3,D4)

*** Take care with the IR voltage. Mine would not work at 3.3V but Sam said that his did.
If you go with 5V then you need to protect the GPIO pin with a resistor.
So try 3.3V first (pin 1 on RPi) and if the IR tests do not work then try 5V but fit a resistor first (certainly if using an old RPi like I was). I put a 4k7 resistor in series between the data pin and the GPIO pin.

The software starting point of these instructions is Squeezeplug - http://www.squeezeplug.eu
At the time of writing the version of Squeezeplug was 7.5 (released December 2014).
However, the instructions are likely to work with other releases but it might miss some of the prerequisites and you would have to resolve them yourself.

The commands below assume that you are logged into your Raspberry Pi as user "pi".


Bringing the LCD to life:

Install LCDproc

sudo apt-get install lcdproc

Then check the version that was installed with the following command
lcdproc -v

This should respond with something like:
LCDproc 0.5.5


If the version is lower than 0.5.7 then this version does not include the built-in support for Raspberry Pi GPIO driven support of the HD44780-compatible LCD controller.

Also - if you are using a "Raspberry Pi 2" then there might be a problem - depending on whether or not the version that you have recognises the RPi. I made a change to my version to handle this but at the time of writing this that update had not been made in the official source. If that is still a problem then I'll put my version somewhere for download or contact me if I have not yet done that.


# If you need to make and install the CVS version of LCDproc:   

  sudo apt-get install cvs autoconf automake

  # download the CVS source, then make and install
  cvs -z3 -d:pserver:anonymous@lcdproc.cvs.sourceforge.net:/cvsroot/lcdproc \
      checkout -P lcdproc

  # make and install the CVS source
  cd lcdproc
  sh ./autogen.sh
  ./configure --prefix=/usr --sysconfdir=/etc  --localstatedir=/var \
              --enable-drivers=hd44780
  make

  # do a sanity check on LCDd before installing it
  sudo invoke-rc.d LCDd stop
  server/LCDd -f    # a curses LCD emulation window should show.
           # terminates LCDd

  # install the new version over the old version
  sudo make install



Configure LCDproc:

Then edit the LCDproc configuration file to use the hd44780 compatible LCD
locate:
sudo nano /etc/LCDd.conf

Locate the section that starts
## Server section with all kinds of settings for the LCDd server ##
[server]

In there you will see
DriverPath=
If the full line is
DriverPath=server/drivers/
then it has been set to that via the installation of the special lcdproc
but since the installation has been done then change it to the usual value
DriverPath=/usr/lib/lcdproc/
If you do not do this then the process will not start properly

Then look for
Driver=
and above that are a list of supported devices.

Probably it shows:
Driver=curses
Change to
Driver=hd44780

Then look for
## Hitachi HD44780 driver ## [hd44780] # Select what type of connectiDriverPath=server/drivers/on. See documentation for types. ConnectionType=4bit

and change to
ConnectionType=raspberrypi

The scroll down to find Size=
and change from
Size=20x4
to
Size=40x2


You can also change the lcdproc startup and exit message to personalise things.
These appear on the LCD screen
# Hello message: each entry represents a display line; default: builtin #Hello=" Welcome to" #Hello=" LCDproc!" # GoodBye message: each entry represents a display line; default: builtin #GoodBye="Thanks for using" #GoodBye=" LCDproc!"

You could change these to something like:
# Hello message: each entry represents a display line; default: builtin Hello=" Welcome to" Hello=" rpitron" # GoodBye message: each entry represents a display line; default: builtin GoodBye="Thanks for using" GoodBye=" rpitron"


Next is to get the audio player installed.

Squeezelite with LCD support

sudo apt-get install libasound2-dev libflac-dev libmad0-dev libvorbis-dev libfaad-dev libmpg123-dev liblircclient-dev libncurses5-dev


git clone https://github.com/fpasteau/squeezelite.git

cd squeezelite
OPTS=-DINTERACTIVE make

Assuming all goes well - it should look something like this:
pi@rpitron ~/squeezelite $ OPTS=-DINTERACTIVE make cc -Wall -fPIC -O2 -DINTERACTIVE main.c -c -o main.o cc -Wall -fPIC -O2 -DINTERACTIVE slimproto.c -c -o slimproto.o cc -Wall -fPIC -O2 -DINTERACTIVE buffer.c -c -o buffer.o cc -Wall -fPIC -O2 -DINTERACTIVE stream.c -c -o stream.o cc -Wall -fPIC -O2 -DINTERACTIVE utils.c -c -o utils.o cc -Wall -fPIC -O2 -DINTERACTIVE output.c -c -o output.o cc -Wall -fPIC -O2 -DINTERACTIVE output_alsa.c -c -o output_alsa.o cc -Wall -fPIC -O2 -DINTERACTIVE output_pa.c -c -o output_pa.o cc -Wall -fPIC -O2 -DINTERACTIVE output_stdout.c -c -o output_stdout.o cc -Wall -fPIC -O2 -DINTERACTIVE output_pack.c -c -o output_pack.o cc -Wall -fPIC -O2 -DINTERACTIVE decode.c -c -o decode.o cc -Wall -fPIC -O2 -DINTERACTIVE flac.c -c -o flac.o cc -Wall -fPIC -O2 -DINTERACTIVE pcm.c -c -o pcm.o cc -Wall -fPIC -O2 -DINTERACTIVE mad.c -c -o mad.o cc -Wall -fPIC -O2 -DINTERACTIVE vorbis.c -c -o vorbis.o cc -Wall -fPIC -O2 -DINTERACTIVE faad.c -c -o faad.o cc -Wall -fPIC -O2 -DINTERACTIVE mpg.c -c -o mpg.o cc -Wall -fPIC -O2 -DINTERACTIVE interactive.c -c -o interactive.o cc main.o slimproto.o buffer.o stream.o utils.o output.o output_alsa.o output_pa.o output_stdout.o output_pack.o decode.o flac.o pcm.o mad.o vorbis.o faad.o mpg.o interactive.o -lasound -lpthread -lm -lrt -ldl -lcurses -llirc_client -o squeezelite


Then make a backup of the original Squeezelite and copy the newly built one into place

Edit /etc/default/squeezelite to add a -L option
(in this special version of Squeezelite ... -L means use LCDproc)

Probably will find that the Squeezelite output is being alternated with information about the state of the Raspberry Pi.
This is useful when checking that things are working - but is a distraction when in normal use.
To disable this you can edit /etc/LCD.conf and change
#AutoRotate=off
to
AutoRotate=off

and
#ServerScreen=off
to
ServerScreen=off


Using infrared remote control:

To get the infrared remote control working:

sudo apt-get install lirc
Then get lirc working with your remote control ...

Edit /etc/modules to add:
# Load RPi lirc support for GPIO driven IR device
lirc_dev
lirc_rpi gpio_in_pin=22

e.g. using
sudo nano /etc/modules
Note - the number shown is GPIO22 which is pin 15 on the GPIO connector


Edit /etc/lirc/hardware.conf (for example by using nano) and make it look like this:

# /etc/lirc/hardware.conf
#
# Arguments which will be used when launching lircd
LIRCD_ARGS=""

#Don't start lircmd even if there seems to be a good config file
#START_LIRCMD=false

#Don't start irexec, even if a good config file seems to exist.
#START_IREXEC=false

#Try to load appropriate kernel modules
LOAD_MODULES=true

# Run "lircd --driver=help" for a list of supported drivers.
DRIVER="default"
# usually /dev/lirc0 is the correct setting for systems using udev
DEVICE="/dev/lirc0"
MODULES="lirc_rpi"

# Default configuration files for your hardware if any
LIRCD_CONF=""
LIRCMD_CONF=""


create a new directory to hold the lirc configuration files

cd $HOME
mkdir rpitron
cd rpitron

Now create the configuration file for the remote control that you are going to use.
In my case I want to use the remote control that came with the Audiotron.
I have made some configuration files for that - which you should then download and copy to the default for lirc.

wget ... (info to be added in here)...

cp /etc/lirc/lircrc ./lircrc.backup
cp audiotron.lircrc /etc/lirc/lircrc

cp /etc/lirc/lircd.conf ./lircd.conf.backup
cp audiotron.lircd.conf /etc/lirc/lircd.conf


Then modify the startup parameters for the modified Squeezelite to include
-i -F /etc/lirc/lircrc
The "-i" means use Infrared via lirc - and the -F gives the location of the lirc remote control configuration file that maps the various key presses into Squeezelite commands.


In theory ... if you now reboot then things should work!
If they do not then you will have to go back through the steps one at a time to work out what went wrong.
Most likely if that cables were connected to the wrong pins. Hopefully that did not break anything!

You will probably find that the scroll rate on the display is too fast when long track names are being shown.

In LMS (via web browser to port 9000 on your LMS server) you can change the scroll rate - via
Settings/Player/Display - and change the scroll rate from 0.033 to 0.8 or some other value that suits.
It does not look good when scrolling through - so probably best to set the title format (in Settings/Player/Basic) to something that is less likely to need scrolling.


To be done:
Add some pictures to show the inside of the Audiotron and the mass of cables.
Clear up the various sections and provide breakpoints and test methods so that steps can be verified
Upload the Audiotron remote control configuration files
Add links
Add list of parts

Useful tools:
To check or set GPIO pins
WiringPi -

While working on this I submitted updates to the modified Squeezelite (to make the -F parameter work) and to LCDproc to add support for Raspberry Pi 2 B.



Tuesday, August 19, 2014

Infra-red remote controlling LMS on RPi

Acronym soup follows - but as a quick summary ... this is about controlling, via an infra-red remote control, the sounds from a Logitech Media Server.

I wanted to get a Creative Labs Soundblaster X-Fi Surround 5.1 Pro USB Sound Card (part number SB-1095 with remote RM-820) working with one Raspberry Pi that is set-up as a Squeezebox music server (LMS) and player (Squeezelite) and a different RPi working with the IQaudIO DAC and a generic Philips remote control.

Getting the sound working was pretty straight-forward but I also wanted to make use of the infra-red remote controls to at least control the volume and ideally do much more.

Why not simply use the web interface or a smartphone or tablet or a real Squeezebox to control it?
Well, they can be used of course and are needed to select what to play but leaving the simple remote near the player makes it very easy for someone to pause the music when the phone rings, skip a track or pump up the volume.

Getting it to work required pulling a few things together and then doing some custom scripting.

Most of this is not Raspberry Pi specific - it should work on nearly any Linux system. The exception is the installation of the IR receiver for the Philips (and in theory any other regular remote).
Note: there is no need to install an IR receiver for the Soundblaster because there is one built-in to the device and for this particular device this also works with the rotary control that is on top of the device (twist for volume and push for mute/pause).

Here is what it looks like. This is the RPI with the IQaudIO DAC installed and the lid removed from the IQaudIO case. The DAC is attached to the RPi in the top right.
Attached to that is the infra-red receiver - with the "eye" attached (using blue sticky stuff) so that a signal can get through the holes along the top edge of the IQaudIO case (you cannot see them),



So here is how I did it.

I decided to use the "expect" application to drive LMS because it has can send data in "telnet" style, as made available through the LMS CLI, and then take actions using a simple built-in scripting language based on the reply.

Text below that is in monospaced font and/or red shows what appears on the console or needs to be typed.

The full "expect" script is below. Some key points from it are:

  • This assumes that you have already installed Squeezelite and it has access to LMS either locally on same system or somewhere remote that can be accessed through the network (for example by installing SqueezePlug on RPi)
  • "expect" and possibly "telnet" might not be installed on your system. In which case you will have to install them yourself. On Debian-based systems (like Raspbian for Raspberry Pi) you can do this with
    sudo apt-get install expect telnet
  • If you are going to force actions via infra-red (IR) remote control then you will also need to install "lirc"
    sudo apt-get install lirc
  • You might not have the ALSA sound utilities installed. They are used to control some of the sound settings ... to install them you would do
    sudo apt-get install alsa-utils
  • Settings (such as where is the LMS server relative to this controlling client) are included in the file but they can also come from the settings file for Squeezelite ... in which case you probably would not have to edit this file at all.
  • Lines that start with "# " are comments. Some of them have some tracing statements to help if things are not working as expected. Simply remove the "#" from the front
    e.g.
    # puts "settings: host:\"$params(SBSHOST)\" and player MAC:\"$params(SLMAC)\""
    becomes
    puts "settings: host:\"$params(SBSHOST)\" and player MAC:\"$params(SLMAC)\""
    In this case this will output (puts = put string on console) the settings that were found
  • There are some special functions in there - such as treating the OK button as a special case (to restore things to a default configuration with middle volume, mute off, power on, shuffle off, repeat off) but they should be easy to understand simply by reading the script
  • Take care with line wrapping when copying the file below. It is up to you to work out where the blogging software has wrapped lines that should not have been wrapped. If you cannot do that then contact me directly and ask for a copy of the file to be sent by email to you
  • I stored this file as lmscli.exp in /home/pi/lmscli and performed a chmod on it
    i.e. I logged in as "pi" then
    mkdir lmscli
    cd lmscli

    (then copy the file and save as lmscli.exp)

    chmod +x lmscli.exp
    You can test this by hand like this:
    ./lmscli.exp pause
    You should see something like this if it worked (and any music that was playing via your local Squeezelite should have then paused or resumed)
    spawn telnet 127.0.0.1 9090
    Trying 127.0.0.1...

    Connected to 127.0.0.1.

    Escape character is '^]'.

    login user pass 
    b8:27:eb:aa:bb:cc

    pause

    exit

    login user ******

    Connection closed by foreign host.

    Note: the output above is slightly out of sequence but do not worry about it if it worked


Here is the lmscli.exp script (between but not including the separator lines):
------------------------------------------------------------------------------
#!/usr/bin/expect -f

# lmscli "Expect" script
# Author:       Paul Webster
# Version:      0.1
# Date: 29-Mar-2014
##
# Simple script (with no error checking) to send Logitech Media Server (SqueezeCenter) CLI commands to control a player
# Attempts to read parameters from Squeezelite defaults file - where syntax is
# keyword="value"
#
# "Expect" and telnet are required
# sudo apt-get install expect telnet
# Also - if this is to be driven via infrared remote (expected use) then also install lirc
# sudo apt-get install lirc
#

set settingsfile /etc/default/squeezelite

# Defaults
# Values here are overridden by values found in /etc/default/squeezelite (if present)
# SBSHOST = ip address of the LMS/Squeezebox Server
# SBSPORT = port number on LMS that cli runs on (rarely changed)
# SLMAC = the MAC address claimed by the player to be controlled - not always the real MAC address and is specified to Squeezelite
# SBSUSER / SBSPASS = username and password to access LMS. Usually not configured - in which case leave as is
# - if used then make sure that the user/pass fields are URL-encoded (e.g. %20 for space)
array set params {
    SBSHOST     127.0.0.1
    SBSPORT     9090
    SLMAC       00:11:22:33:44:55:66
    SBSUSER     user
    SBSPASS     pass
}

# Override the defaults that are in this script with the ones from the Squeezelite settings
if {[file exists "$settingsfile"]} {
    set fp [open "$settingsfile" r]
    set file_data [read $fp]
    close $fp

    # get lines
    set data [split $file_data "\n"]
    foreach line $data {
        #parse lines for config data
        if {[regexp {^(\w+)\s*=\s*[\"|](.*)[\"|]} $line -> name value]} {
            # puts "found name of \"$name\" with value \"$value\""
            set params($name) $value
        }
    }
}

# puts "settings: host:\"$params(SBSHOST)\" and player MAC:\"$params(SLMAC)\""
# The settings are now in place

set arg1 [lindex $argv 0]
set arg2 [lindex $argv 1]

# puts "recieved arguments of \"$arg1\" and \"$arg2\""
spawn telnet $params(SBSHOST) $params(SBSPORT)
expect "Escape character is *"
send "login $params(SBSUSER) $params(SBSPASS)\n"
expect "login user"


switch $arg1 {

pause   {
                send "$params(SLMAC) pause\n"
                expect "* pause"
        }

bb      {
                send "$params(SLMAC) time -10\n"
                expect "* time"
        }

ff      {
                send "$params(SLMAC) time +10\n"
                expect "* time"
        }

muteoff {
                send "$params(SLMAC) mixer muting 0\n"
                expect "* mixer muting"
        }

muteon  {
                send "$params(SLMAC) mixer muting 1\n"
                expect "* mixer muting"
        }

next    {
                send "$params(SLMAC) playlist index +1\n"
                expect "* playlist index"
        }

prev    {
                send "$params(SLMAC) playlist index -1\n"
                expect "* playlist index"
        }

power   {
                send "$params(SLMAC) power\n"
                expect "* power"
        }

voldown {
                send "$params(SLMAC) mixer volume -2.5\n"
                expect "* mixer volume"
        }

volup   {
                send "$params(SLMAC) mixer volume +2.5\n"
                expect "* mixer volume"
        }

shuffle {
                send "$params(SLMAC) playlist shuffle\n"
                expect "* playlist shuffle"
        }

repeat  {
                send "$params(SLMAC) playlist repeat\n"
                expect "* playlist repeat"
        }

stop    {
                send "$params(SLMAC) stop\n"
                expect "* stop"
        }

ok      {       #Restore to base values
                send "$params(SLMAC) playlist repeat 0 1\n"
                expect "* playlist repeat"
                send "$params(SLMAC) playlist shuffle 0\n"
                expect "* playlist shuffle"
                send "$params(SLMAC) mixer volume 50\n"
                expect "* mixer volume"
                send "$params(SLMAC) mixer muting 0\n"
                expect "* mixer muting"
                send "$params(SLMAC) power 1\n"
                expect "* power"
}

default {puts "Unknown command issued to lmscli"}

}
# End of switch (do not put on same line as the closing brace)

send "exit\n"
expect eof
------------------------------------------------------------------------------

Next step is to get the commands that are sent by infra-red to get sent to lmscli.
I have not covered all of the steps required to get lirc working (there are plenty of posts and FAQs about that elsewhere) - so all I am showing here are the configuration files to link lirc to the "expect" script.

This first file should be saved as "root" in /etc/lirc as lircrc
To be safe, make a copy of the file that is already there (if there is one).
This particular file is set-up to handle 2 different remote controls, "RM-820" and "philipsdvd".
Therefore you will see that many of the functions are repeated. By doing it this way it meant that I could have the same config file on two different RPi systems, making life easier for me.
The full file is below - some key points from it are:

  • the "remote =" line define which remote control this is referring to. It has to match the name used in other lirc config files (see more about that much further below)
  • the text after the "button =" has to exactly match what you have mapped the button presses to for the particular remote control - via the lirc config files (see more about that much further below)
  • I was still getting occasional lock-ups resulting in no sound coming out or sometimes a few digital burps and in worst case the Ethernet connection stops responding. So while trying to work out why that was happening (and I had tried what was the most recent official firmware and the work-in-progress FIQ handler at the time) I mapped one of the keys to a "reboot" command. I chose the long-back command on the RM-820 or the "scan" button on the Philips remote rather than Power for that as it very unlikely to be used accidentally and the Power key is mapped to the player power function on LMS because sometimes toggling the soft power button is enough to get things working again since Squeezelite releases something when it is told to power down. However, if you face similar problems and you do not have a button/function that you can readily map then you could edit the "#Power" section below to comment out the current "config =" line (by putting a "#" in front of it) and then put in "config = reboot". Applications/scripts that are invoked by lirc are run as "root" so you do not need to put "sudo" in front. This makes it very powerful and dangerous so take care
  • the volume is controlled through ALSA (sound libraries) directly. Therefore I set the command to change the volume via ALSA and also repeat the command to LMS so that it shows the volume change. However, these are not really matched up so it would be easy to have LMS show a very different volume to what is really set in ALSA. To help get around that potential issue I configured things to use the "OK" button to try to return this setting (and some others) to defaults. There is similar trickery in place for the "mute" function for the same reason. The ALSA settings are stored so that they can be restored when needed. The hint for some of this came from http://alsa.opensrc.org/Usb-audio and possibly other places that I found while hunting for a solution but have since forgotten.


------------------------------------------------------------------------------
# Power
begin
    prog = irexec
    remote = RM-820
    button = power
    config = /home/pi/lmscli/lmscli.exp power
    # config = reboot
end

begin
    prog = irexec
    remote = philipsdvd
    button = KEY_POWER
    repeat = 0
    config = /home/pi/lmscli/lmscli.exp power
end

# Hold the menu button down for a long time ... to try to force a reboot
begin
    prog = irexec
    remote = RM-820
    button = menu/back-long
    config = reboot
end

# On philipsdvd remote - there does not seem to be a long-hold ... so use the "scan" button - saved as SYSRQ
begin
    prog = irexec
    remote = philipsdvd
    button = KEY_SYSRQ
    repeat = 0
    config = reboot
end

# S51 Volume Knob
begin
    prog = irexec
    remote = RM-820
    button = knobvoldn
    repeat = 1
    config = amixer sset Master 1- ; /home/pi/lmscli/lmscli.exp voldown
end

begin
    prog = irexec
    remote = RM-820
    button = voldn
    repeat = 1
    config = amixer sset Master 1- ; /home/pi/lmscli/lmscli.exp voldown
end

begin
    prog = irexec
    remote = philipsdvd
    button = KEY_DOWN
    repeat = 1
    config = amixer sset Master 1- ; /home/pi/lmscli/lmscli.exp voldown
end

begin
    prog = irexec
    remote = RM-820
    button = knobMute
    repeat = 1
    config = if [ `amixer sget Master|grep "Front Left:"|awk '{print $3}'` -gt 0 ]; then alsactl store -f ~/.asound.state; amixer sset Master 0; amixer sset 'Power LED' off; /home/pi/lmscli/lmscli.exp muteon; else alsactl restore -f ~/.asound.state; amixer sset 'Power LED' on ; /home/pi/lmscli/lmscli.exp muteoff; fi
end

begin
    prog = irexec
    remote = RM-820
    button = mute
    repeat = 1
    config = if [ `amixer sget Master|grep "Front Left:"|awk '{print $3}'` -gt 0 ]; then alsactl store -f ~/.asound.state; amixer sset Master 0; amixer sset 'Power LED' off; /home/pi/lmscli/lmscli.exp muteon; else alsactl restore -f ~/.asound.state; amixer sset 'Power LED' on ; /home/pi/lmscli/lmscli.exp muteoff; fi
end

begin
    prog = irexec
    remote = philipsdvd
    button = KEY_AUDIO
    repeat = 1
    config = if [ `amixer sget Master|grep "Front Left:"|awk '{print $3}'` -gt 0 ]; then alsactl store -f ~/.asound.state; amixer sset Master 0;  /home/pi/lmscli/lmscli.exp muteon; else alsactl restore -f ~/.asound.state; /home/pi/lmscli/lmscli.exp muteoff; fi
end

begin
    prog = irexec
    remote = RM-820
    button = play-pause
    repeat = 1
    config = if [ `amixer sget Master|grep "Front Left:"|awk '{print $3}'` -gt 0 ]; then alsactl store -f ~/.asound.state; amixer sset Master 0; amixer sset 'Power LED' off; /home/pi/lmscli/lmscli.exp pause; else alsactl restore -f ~/.asound.state; amixer sset 'Power LED' on ; /home/pi/lmscli/lmscli.exp pause; fi
end

begin
    prog = irexec
    remote = philipsdvd
    button = KEY_PAUSE
    repeat = 0
    config = if [ `amixer sget Master|grep "Front Left:"|awk '{print $3}'` -gt 0 ]; then alsactl store -f ~/.asound.state; amixer sset Master 0; /home/pi/lmscli/lmscli.exp pause; else alsactl restore -f ~/.asound.state; /home/pi/lmscli/lmscli.exp pause; fi
end

begin
    prog = irexec
    remote = philipsdvd
    button = KEY_PLAY
    repeat = 0
    config = if [ `amixer sget Master|grep "Front Left:"|awk '{print $3}'` -gt 0 ]; then alsactl store -f ~/.asound.state; amixer sset Master 0; /home/pi/lmscli/lmscli.exp pause; else alsactl restore -f ~/.asound.state; /home/pi/lmscli/lmscli.exp pause; fi
end

begin
    prog = irexec
    remote = RM-820
    button = knobvolup
    repeat = 1
    config = amixer sset Master 1+ ; /home/pi/lmscli/lmscli.exp volup
end

begin
    prog = irexec
    remote = RM-820
    button = volup
    repeat = 1
    config = amixer sset Master 1+ ; /home/pi/lmscli/lmscli.exp volup
end

begin
    prog = irexec
    remote = philipsdvd
    button = KEY_UP
    repeat = 1
    config = amixer sset Master 1+ ; /home/pi/lmscli/lmscli.exp volup
end

begin
    prog = irexec
    remote = RM-820
    button = bb
    repeat = 1
    config = /home/pi/lmscli/lmscli.exp prev
end

begin
    prog = irexec
    remote = philipsdvd
    button = KEY_REWIND
    repeat = 0
    config = /home/pi/lmscli/lmscli.exp prev
end

begin
    prog = irexec
    remote = RM-820
    button = ff
    repeat = 1
    config = /home/pi/lmscli/lmscli.exp next
end

begin
    prog = irexec
    remote = philipsdvd
    button = KEY_FASTFORWARD
    repeat = 0
    config = /home/pi/lmscli/lmscli.exp next
end

begin
    prog = irexec
    remote = RM-820
    button = shuffle
    config = /home/pi/lmscli/lmscli.exp shuffle
end

begin
    prog = irexec
    remote = philipsdvd
    button = KEY_SHUFFLE
    repeat = 0
    config = /home/pi/lmscli/lmscli.exp shuffle
end

begin
    prog = irexec
    remote = RM-820
    button = repeat
    config = /home/pi/lmscli/lmscli.exp repeat
end

begin
    prog = irexec
    remote = philipsdvd
    button = KEY_MEDIA_REPEAT
    repeat = 0
    config = /home/pi/lmscli/lmscli.exp repeat
end

begin
    prog = irexec
    remote = philipsdvd
    button = KEY_MEDIA
    repeat = 0
    config = /home/pi/lmscli/lmscli.exp repeat
end

begin
    prog = irexec
    remote = RM-820
    button = right
    repeat = 1
    config = /home/pi/lmscli/lmscli.exp ff
end

begin
    prog = irexec
    remote = philipsdvd
    button = KEY_RIGHT
    repeat = 1
    config = /home/pi/lmscli/lmscli.exp ff
end

begin
    prog = irexec
    remote = RM-820
    button = left
    repeat = 1
    config = /home/pi/lmscli/lmscli.exp bb
end

begin
    prog = irexec
    remote = philipsdvd
    button = KEY_LEFT
    repeat = 1
    config = /home/pi/lmscli/lmscli.exp bb
end

begin
    prog = irexec
    remote = philipsdvd
    button = KEY_STOP
    repeat = 1
    config = /home/pi/lmscli/lmscli.exp stop
end

begin
    prog = irexec
    remote = RM-820
    button = ok
    config = /home/pi/lmscli/lmscli.exp ok
end

begin
    prog = irexec
    remote = philipsdvd
    button = KEY_OK
    repeat = 0
    config = /home/pi/lmscli/lmscli.exp ok
end

------------------------------------------------------------------------------

Next is the set-up of lirc to know what hardware is being used.
The file shown below is my config file from the RPi that has the Philips Remote control - which is getting the data via a simple IR receiver attached to GPIO pins on the RPi.
However, I have left the RM-820 set-up in there as well - but commented out. So if you are trying to get the Creative device to work then uncomment those lines and comment out the Philips ones.
This file is stored as "root" as /etc/lirc/hardware.conf
------------------------------------------------------------------------------
# /etc/lirc/hardware.conf
#
# Arguments which will be used when launching lircd
#LIRCD_ARGS=""
LIRCD_ARGS=""

#Don't start lircmd even if there seems to be a good config file
#START_LIRCMD=false

#Don't start irexec, even if a good config file seems to exist.
#START_IREXEC=false

#Try to load appropriate kernel modules
LOAD_MODULES=true

# Run "lircd --driver=help" for a list of supported drivers.
# Uncomment the line below (and comment out the one following it) for Creative Labs Soundblaster X-Fi USB DAC
#DRIVER="alsa_usb"
DRIVER="default"
# usually /dev/lirc0 is the correct setting for systems using udev
# Uncomment the line below (and comment out the one following it) for Creative Labs Soundblaster X-Fi USB DAC
#DEVICE="hw:Pro"
DEVICE="/dev/lirc0"
# Uncomment the line below (and comment out the one following it) for Creative Labs Soundblaster X-Fi USB DAC
#MODULES=""
MODULES="lirc_rpi"

# Default configuration files for your hardware if any
# Uncomment the line below (and comment out the one following it) for Creative Labs Soundblaster X-Fi USB DAC
#LIRCD_CONF="creative/lircd.conf.alsa_usb"
LIRCD_CONF="/home/pi/lircd-philipsdvd.conf"
LIRCMD_CONF=""

------------------------------------------------------------------------------

In this case you can see that I put the configuration file for the Philips remote into the /home/pi directory.
Here is the contents of that file.

------------------------------------------------------------------------------
# Please make this file available to others
# by sending it to
#
# this config file was automatically generated
# using lirc-0.9.0-pre1(default) on Wed Apr 16 18:37:15 2014
#
# contributed by
#
# brand:                       lircd-philipsdvd.conf
# model no. of remote control:
# devices being controlled by this remote:
#

begin remote

  name  philipsdvd
  bits            8
  flags RC6|CONST_LENGTH
  eps            30
  aeps          100

  header       2690   871
  one           462   422
  zero          462   422
  pre_data_bits   13
  pre_data       0xEFB
  gap          106190
  toggle_bit_mask 0x10000
  rc6_mask    0x10000

      begin codes
          KEY_POWER                0xF3
          KEY_1                    0xFE
          KEY_2                    0xFD
          KEY_3                    0xFC
          KEY_4                    0xFB
          KEY_5                    0xFA
          KEY_6                    0xF9
          KEY_7                    0xF8
          KEY_8                    0xF7
          KEY_9                    0xF6
          KEY_0                    0xFF
          KEY_BACK                 0x7C
          KEY_DISPLAYTOGGLE        0x10
          KEY_MENU                 0xAB
          KEY_CONTEXT_MENU         0x7D
          KEY_UP                   0xA7
          KEY_DOWN                 0xA6
          KEY_LEFT                 0xA5
          KEY_RIGHT                0xA4
          KEY_OK                   0xA3
          KEY_REWIND               0xDE
          KEY_FASTFORWARD          0xDF
          KEY_STOP                 0xCE
          KEY_PLAY                 0xD3
          KEY_PAUSE                0xCF
          KEY_SUBTITLE             0xB4
          KEY_ANGLE                0x7A
          KEY_ZOOM                 0x08
          KEY_AUDIO                0xB1
          KEY_MEDIA_REPEAT         0xE2
          KEY_MEDIA                0xC4
          KEY_SHUFFLE              0xE3
          KEY_SYSRQ                0xD5
      end codes

end remote
------------------------------------------------------------------------------


For the Creative device I used the default that came with lirc (as you can see from the commented out set-up in the hardware.conf).

For the particular IR module that I used I connected it to GPIO pin 23 - which is one of the pins that the IQaudIO device exports to its connectors on top of the card. I forced this pin to be used by adding the following lines to /etc/modules
lirc_dev
lirc_rpi gpio_in_pin=23
This might not be right for you - so you will need to check the documentation for the IR module that you are using to see how to do it for your particular device. Note - this is not needed for the Creative device because it has a built-in IR receiver and it passes the commands in through the USB connection not GPIO.


As always, if you have questions then ask it in the comments section below and I'll try to answer it.