LCD Display

There are many, many clients for MPD. Many of them are old and unsupported, but maybe someone here can help you with them anyway...
Post Reply
Ran
Posts: 144
Joined: February 25th, 2013, 3:47 am

LCD Display

Post by Ran » April 4th, 2013, 2:56 am

Is there a good tutorial on how to send MPD data (status, track, album, etc...) to a LCD display? There are some scripts but most of them are old and do not run on Ubuntu 12.04. Again, I am looking for a tutorial / how-to.

Thanks!

Qball
Forum team
Posts: 54
Joined: January 15th, 2013, 4:03 pm

Re: LCD Display

Post by Qball » April 5th, 2013, 11:24 am

You are _Very_ vague in your question..

If you are not going to provide atleast a minimum set of information, we cannot help.
The current amount of information is so limited, there is no way we could answer without having to make a whole bunch of assumptions.

For example? What type of LCD? I assume it is not an LCD monitor...

Ran
Posts: 144
Joined: February 25th, 2013, 3:47 am

Re: LCD Display

Post by Ran » April 5th, 2013, 3:03 pm

I am currently in a research mode. I will probably go with the most documented solution. I am open to any suggestions. ANY proper how to will help. I am looking into LCDProc and some 2x20, 4x20 LCD units.

ichneumon
Posts: 2
Joined: April 9th, 2013, 5:33 pm

Re: LCD Display

Post by ichneumon » April 9th, 2013, 6:10 pm

Whilst I can't comment on lcdproc, I'm currently using the 16x2 lcd Raspberry Pi UI from bitwizard.nl (i2c version), along with the following simple bash script I stitched together. This both controls mpd and shows information about the current track, and can also work with either local or remote mpd servers.
It assumes MPD_HOST is set correctly, and requires both bw_tool and bw_i2c_lcd.
I've used this script as a remote for mpd 0.17 on Ubuntu 10.04, and it illustrates one way to customize the output to an LCD.
I'm slowly working on a more advanced version in python that'll have more functions and display options, but I haven't looked at it for a little while.

Code: Select all

#!/bin/bash

DEVICE=/dev/i2c-1
ADDRESS=94
BRIGHTNESS=255

PREV_TITLE=NONE
MPC_STATE=NONE

# read buttons once to clear any old values
bw_tool -D $DEVICE -a $ADDRESS -R 0x30:b > /dev/null

while [ 1 ]; do
  MPC_STATE=`mpc | head -n 2 | tail -n 1 | cut -f 1 -d" "`
  if [ $MPC_STATE = "[playing]" -o $MPC_STATE = "[paused]" ]; then
    bw_i2c_lcd -D $DEVICE -a $ADDRESS -b $BRIGHTNESS
  else
    bw_i2c_lcd -D $DEVICE -a $ADDRESS -b 0
  fi

  BTNS=`bw_tool -D $DEVICE -a $ADDRESS -R 0x30:b`
  if [ $BTNS -gt 0 ]; then
    if [ $(( 16#$BTNS & 1 )) -ne 0 ]; then
      mpc -q clear
      mpc -q search album "$(mpc list album | shuf -n1)" | mpc add
      mpc -q play
    fi
    if [ $(( 16#$BTNS & 2 )) -ne 0 ]; then
      mpc -q next
    fi
    if [ $(( 16#$BTNS & 4 )) -ne 0 ]; then
      mpc -q prev
    fi
    if [ $(( 16#$BTNS & 8 )) -ne 0 ]; then
      mpc -q stop
    fi
    if [ $(( 16#$BTNS & 16 )) -ne 0 ]; then
      if [ $MPC_STATE = "[playing]" ]; then
        mpc -q pause
      else
        mpc -q play
      fi
    fi
  fi

  TITLE=`mpc -f '%title% - %artist%' | head -n 1`
  if [ "$PREV_TITLE" != "$TITLE" ]; then
    if echo "$TITLE" | grep -q "volume:"; then
      bw_i2c_lcd -D $DEVICE -a $ADDRESS -C
      bw_i2c_lcd -D $DEVICE -a $ADDRESS -b 0
      PREV_TITLE=NONE
    else
      bw_i2c_lcd -D $DEVICE -a $ADDRESS -C
      bw_i2c_lcd -D $DEVICE -a $ADDRESS -p 0,0 -t "$TITLE"
      bw_i2c_lcd -D $DEVICE -a $ADDRESS -p 0,1 -t "`mpc -f %album% | head -n 1`"
      PREV_TITLE="$TITLE"
    fi
  fi

  sleep 1
done

Ran
Posts: 144
Joined: February 25th, 2013, 3:47 am

Re: LCD Display

Post by Ran » April 9th, 2013, 6:50 pm

I am currently using Ubuntu 12.04 server. I have successfully installed LCDProc to work with Hitachi's hd44780 LCD display. The LCDProc server identifies the LCD devices without a problem. I am in the process of learning how to send commands to the display. There is very limited documentation about sending the data to a LCD panel. I tried using mpdlcd (https://github.com/rbarrois/mpdlcd) but ran into issues with Python...

ichneumon
Posts: 2
Joined: April 9th, 2013, 5:33 pm

Re: LCD Display

Post by ichneumon » April 9th, 2013, 9:13 pm

Hmm... looks my RPi UI does indeed have an HD44780 display, driven over i2c. Which is apparently supported by lcdproc. A quick skim through the lcdproc docs looks like it should be able to cover a lot of what I was planning to add in my python version. I'll get back to you on this one, although I can't guarantee when...

Ran
Posts: 144
Joined: February 25th, 2013, 3:47 am

Re: LCD Display

Post by Ran » April 10th, 2013, 2:39 am

I got LCDProc 5.5 to work without a problem. I can post data on the LCD panel without a problem (system load, time, hd space, etc..). I am stuck with MPD... I am trying to find a way to send to the LCD panel the following:

Track Name
Album Name
Artist Name
Bit Rate / Time / Format

I can't get mpdlcd (https://github.com/rbarrois/mpdlcd) to work. There are many issues with python that I can't resolve (not a python developer). Also, I am looking into lcd-stuff (http://lcd-stuff.berlios.de/) but I am not sure it has all the functionality I need.

Ran
Posts: 144
Joined: February 25th, 2013, 3:47 am

Re: LCD Display

Post by Ran » April 10th, 2013, 8:05 am

From the following site: http://user.enterpriselab.ch/~zdweber/unuklcd.html I found a python script that actually works. The issue here is that the script was written specifically to work with the PicoLCD, which has a 4x20 resolution. My LCD has 4x40. Can anyone look at the script and suggest how to hack it?

Thanks

Code: Select all

#!/usr/bin/python
#
# Copyright (c) 2008, Mathias Weber <mathew.weber@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.

import mpd
import socket
import time

ADDRESS_MPD = 'localhost'
ADDRESS_LCD = 'localhost'
PORT_LCD = 13666
PORT_MPD = 6600

class LCDClient(object):
    ''' Provide access to the LCDd deamon. It offers simple methods for 
        sending commands to the LCDd and offers an interface for receiving
        key events.
        Currently the key listening only works for one client. For a more
        generic version we would need to check the current view and map the
        event to the right view.
    '''
    def __init__(self, address, port):
        self.Connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.Connection.connect( (address, port) )
        self.Connection.setblocking(0)
        self.Keys = {}
        self.send_view('hello')
        self.send_view('client_set -name unuk')

    def remove(self):
        self.Connection.close()

    def update(self):
        answ = self._check_event()
        if answ:
           self._parse_answer(answ) 

    def send_view(self, request):
        self.Connection.send("%s\n" % request)
        answ = False
        while not answ: 
            time.sleep(0.1)
            answ = self._check_event()
            if type(answ) == bool:
                answ = False
            elif answ.strip() == "success":
                return True
            else:
                if self._parse_answer(answ):
                    answ = False
                else:
                    return False

        return answ

    def register_key(self, key, function):
        self.send_view('client_add_key %s' % key)
        self.Keys[key] = function

    def unregister_key(self, key):
        self.send_view('client_del_key %s' % key)
        try:
            self.Keys.pop(key)
        except:
            pass


    def _check_event(self):
        try:
            answ = self.Connection.recv(4096)
            if len(answ) > 0:
                return answ
            else:
                return False
        except:
            return False

    def _parse_answer(self, answ):
        if not answ:
            return False
        elif answ.startswith('key'):
            key = answ.split(' ')[1].strip()
            if self.Keys.has_key(key):
                self.Keys[key]()
            else:
                print "UNKNOWN KEY: %s" % key
        elif answ.startswith('listen'):
            print "LISTEN: %s" % answ.strip()
        elif answ.startswith('ignore'):
            print "IGNORE: %s" % answ.strip()
        elif answ.startswith('huh'):
            # Got an wrong command return this.
            print "Error: %s" % answ.strip()
            return False



class MPDStatusView(object):
    ''' This is a simple view, which uses the LCDClient for showing the 
        information about the MPD server that it is connected to.
    '''
    def __init__(self, lcdclient, mpdclient):
        self.LcdClient = lcdclient
        self.MpdClient = mpdclient
        self.Run = True

    def _init_screen(self):
        self.LcdClient.send_view('screen_add unuk_mpd')
        self.LcdClient.send_view('screen_set unuk_mpd -priority foreground '\
                '-heartbeat off')
        self.LcdClient.send_view('widget_add unuk_mpd line1 scroller')
        self.LcdClient.send_view('widget_add unuk_mpd line2 scroller')
        self.LcdClient.send_view('widget_add unuk_mpd line3 scroller')
        self.LcdClient.send_view('widget_add unuk_mpd line4 string')
        self.LcdClient.send_view('widget_add unuk_mpd state string')
        self.LcdClient.register_key('F2', self._play)
        self.LcdClient.register_key('F1', self._prev)
        self.LcdClient.register_key('F3', self._next)
        self.LcdClient.register_key('Up', self._prev)
        self.LcdClient.register_key('Down', self._next)
        self.LcdClient.register_key('Enter', self._stop)
        self.LcdClient.register_key('Back', self._stop)
        self.LcdClient.register_key('Home', self._stop)

    def _play(self):
        if self.MpdClient.status()['state'] == 'play':
            self.MpdClient.pause(1)
        else:
            self.MpdClient.play()

    def _next(self):
        self.MpdClient.next()

    def _prev(self):
        self.MpdClient.previous()

    def _stop(self):
        self.MpdClient.stop()

    def _deinit_screen(self):
        self.LcdClient.send_view('screen_del unuk_mpd')

    def _parseCurrentTimes(self, statusline):
        return [int(x) for x in statusline.split(':')]
        

    def run(self):
        self._init_screen()
        title = ""
        album = ""
        artist = ""
        state = ""
        current_length = ""
        while self.Run:
            self.LcdClient.update()
            status = self.MpdClient.status()
            song = self.MpdClient.currentsong()
            if status['state'] in ['play', 'pause']:
                values = self._parseCurrentTimes(status['time'])
                length = "%02d:%02d / %02d:%02d" % (values[0]//60, \
                        values[0]%60, values[1]//60, values[1]%60)
            else:
                value = int(song['time'])
                length = "%02d:%02d" % (value//60, value%60)
            
            if artist != song['artist']:
                artist = song['artist']
                self.LcdClient.send_view('widget_set unuk_mpd line1 '\
                        '1 1 19 1 h 2 {%s}' % song['artist'])
            if album != song['album']:
                album = song['album']
                self.LcdClient.send_view('widget_set unuk_mpd line2 '\
                        '1 2 19 2 h 2 {%s}' % song['album'])
            if title != song['title']:
                title = song['title']
                self.LcdClient.send_view('widget_set unuk_mpd line3 '\
                        '1 3 19 3 h 2 {%s}' % song['title'])
            if artist != status['state']:
                state = status['state']
                self.LcdClient.send_view('widget_set unuk_mpd state 15 4 {%s}'\
                        % status['state'])

            if current_length != length:
                current_length = length
                self.LcdClient.send_view('widget_set unuk_mpd line4 1 4 {%s}'\
                        % length)

            time.sleep(0.2)
        self._deinit_screen()


if __name__ == '__main__':
    lcd = LCDClient(ADDRESS_LCD, PORT_LCD)
    mpd_client = mpd.MPDClient()
    mpd_client.connect(ADDRESS_MPD, PORT_MPD)
    view = MPDStatusView(lcd, mpd_client)

    view.run()

Ran
Posts: 144
Joined: February 25th, 2013, 3:47 am

Re: LCD Display

Post by Ran » April 11th, 2013, 2:28 am

Got it to work with unuklcd:

Image

It is far from being stable. I will try to tackle mpdlcd next.

Qball
Forum team
Posts: 54
Joined: January 15th, 2013, 4:03 pm

Re: LCD Display

Post by Qball » April 11th, 2013, 9:57 am

Looks pretty good.

Post Reply