{"id":557,"date":"2017-11-06T14:53:10","date_gmt":"2017-11-06T19:53:10","guid":{"rendered":"http:\/\/markwheeler.com\/wordpress\/?p=557"},"modified":"2017-11-06T14:53:10","modified_gmt":"2017-11-06T19:53:10","slug":"raspberry-pi-with-an-i2c-enabled-lcd-screen-for-system-and-mpd-music-display","status":"publish","type":"post","link":"https:\/\/markwheeler.com\/?p=557","title":{"rendered":"Raspberry Pi with an I2C enabled LCD screen for system and MPD music display"},"content":{"rendered":"<p>UPDATE: <a href=\"http:\/\/markwheeler.com\/wordpress\/wp-content\/uploads\/2017\/11\/lcd_display_v2.txt\">This file<\/a> combines the code below into one script.<\/p>\n<p>I gutted an old RCA RC970 speaker into a RPI MPD Jukebox with LCD Screen.<br \/>\n<a href=\"https:\/\/www.markwheeler.com\/wordpress\/wp-content\/uploads\/2017\/11\/IMG_04311.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.markwheeler.com\/wordpress\/wp-content\/uploads\/2017\/11\/IMG_04311-150x150.jpg\" alt=\"\" width=\"150\" height=\"150\" class=\"alignnone size-thumbnail wp-image-558\"><\/a><br clear=\"all\"><\/p>\n<p>On boot, the LCD screen shows RPI data. If the MPD daemon is actively playing a song, the screen switches over to music data.<br \/>\n<a href=\"https:\/\/54.91.57.241\/wordpress\/wp-content\/uploads\/2017\/11\/IMG_0429.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/54.91.57.241\/wordpress\/wp-content\/uploads\/2017\/11\/IMG_0429.jpg\" alt=\"\" width=\"150\" height=\"100\" class=\"alignnone size-thumbnail wp-image-559\"><\/a><br \/>\n<a href=\"https:\/\/54.91.57.241\/wordpress\/wp-content\/uploads\/2017\/11\/IMG_0430.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/54.91.57.241\/wordpress\/wp-content\/uploads\/2017\/11\/IMG_0430.jpg\" alt=\"\" width=\"150\" height=\"100\" class=\"alignnone size-thumbnail wp-image-560\"><\/a><br clear=\"all\"><\/p>\n<p>I am using a <a href=\"https:\/\/www.ebay.com\/sch\/i.html?_osacat=0&amp;_odkw=+Blue-Serial-IIC-I2C-TWI-2004-204-20X4-Character-LCD-Module-Display-For-Arduino++Blue-Serial-IIC-I2C-TWI-2004-204-20X4-Character-LCD-Module-Display-For-Arduino+Have+one+to+sell%3F+Sell+now+Blue+Serial+IIC%2FI2C%2FTWI+2004+204+20X4+Character+LCD+Module+&amp;_from=R40&amp;_from=R40&amp;_trksid=p2334524.m570.l1313.TR0.TRC0.H0.XBlue-Serial-IIC-I2C-TWI-2004-204-20X4-Character-LCD-Module-Display-For-Arduino.TRS0&amp;_nkw=Blue-Serial-IIC-I2C-TWI-2004-204-20X4-Character-LCD-Module-Display-For-Arduino&amp;_sacat=0\">20&#215;4 Blue LCD display with I2C backpack<\/a> from eBay.<br \/>\n<br clear=\"all\"><br \/>\n<strong>Wiring Diagram:<\/strong><br \/>\n<a href=\"https:\/\/54.91.57.241\/wordpress\/wp-content\/uploads\/2017\/11\/PI-LCDI2C_bb.png\"><img decoding=\"async\" src=\"https:\/\/54.91.57.241\/wordpress\/wp-content\/uploads\/2017\/11\/PI-LCDI2C_bb.png\" alt=\"\" height=\"100\" class=\"alignnone size-thumbnail wp-image-561\" srcset=\"https:\/\/markwheeler.com\/wp-content\/uploads\/2017\/11\/PI-LCDI2C_bb.png 1644w, https:\/\/markwheeler.com\/wp-content\/uploads\/2017\/11\/PI-LCDI2C_bb-300x300.png 300w, https:\/\/markwheeler.com\/wp-content\/uploads\/2017\/11\/PI-LCDI2C_bb-1024x1024.png 1024w, https:\/\/markwheeler.com\/wp-content\/uploads\/2017\/11\/PI-LCDI2C_bb-150x150.png 150w, https:\/\/markwheeler.com\/wp-content\/uploads\/2017\/11\/PI-LCDI2C_bb-768x768.png 768w, https:\/\/markwheeler.com\/wp-content\/uploads\/2017\/11\/PI-LCDI2C_bb-1536x1536.png 1536w\" sizes=\"(max-width: 1644px) 100vw, 1644px\" \/><\/a><br \/>\n<br clear=\"all\"><br \/>\n<strong>Installation:<\/strong><br \/>\nFrom Terminal &#8211;<br \/>\nsudo raspi-config<br \/>\nSelect Advanced Option -&gt; I2C -&gt; Enable I2C -&gt;Finish<br \/>\nThe Pi will reboot after you click the Finish Button<\/p>\n<p>After rebooting the Pi, we need to modify the module\u2019s config file. Type the following command in terminal:<br \/>\nsudo nano \/etc\/modules<br \/>\nAdd following two lines in modules file if they do not exist:<br \/>\ni2c-bcm2708<br \/>\ni2c-dev<br \/>\nThen Type Ctrl X and Yes to save the file.<\/p>\n<p><strong>Install smbus and i2c python library<\/strong><br \/>\nsudo apt-get update<br \/>\nsudo apt-get install -y python-smbus i2c-tools<br \/>\nsudo reboot<br \/>\nAfter rebooting the system, type the following command in order to check software installation:<br \/>\nlsmod | grep i2c_<br \/>\nYou should see i2c_bcm2708 in a list, this means the library has been installed successfully.<\/p>\n<p><strong>If you want to use this for MPD display:<\/strong><br \/>\nsudo apt-get install mpd mpc<\/p>\n<p><strong>Testing Hardware<\/strong><br \/>\nDepending on your Raspberry Pi version, please run one of following commands in terminal:<br \/>\nsudo i2cdetect -y 1<br \/>\nor<br \/>\nsudo i2cdetect -y 0<\/p>\n<p>You should see something as follows; the value you see is for I2C_ADDR in the Python code included below.<\/p>\n<pre>0 1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n00: \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014\n10: \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014\n20: \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014\n30: \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 27\n40: \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014\n50: \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014\n60: \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014\n70: \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014\n<\/pre>\n<p><strong>Python Requirements:<\/strong><br \/>\nsudo apt-get install python-pip<br \/>\nsudo pip install python-mpd2<br \/>\nsudo pip3 install python-mpd2<br \/>\nsudo pip install psutil<br \/>\nsudo pip3 install psutil<\/p>\n<p><strong>Start LCD Display at Boot:<\/strong><br \/>\nsudo nano \/etc\/rc.local<br \/>\nAdd the following line BEFORE the &#8216;exit 0&#8217; line.<br \/>\nsudo python \/home\/pi\/scripts\/lcd_display.py &amp;<br \/>\nYou may want to store the following scripts somewhere else, so adjust the path above accordingly.<\/p>\n<p>Copy and save the following as lcd_display.py<\/p>\n<pre>#!\/usr\/bin\/env python3\n# Project Tutorial Url:http:\/\/www.markwheeler.com\n#  \n\nimport smbus\nimport time\nimport os\nimport glob\nimport subprocess\nfrom datetime import datetime\nimport threading\nfrom multiprocessing import Process\nimport psutil\n#import mpd\n#from socket import error as SocketError\n \n#client = mpd.MPDClient()\n\n\n# Define some device parameters\nI2C_ADDR  = 0x3f # I2C device address, if any error, change this address to 0x3f\nLCD_WIDTH = 20   # Maximum characters per line\n\n# Define some device constants\nLCD_CHR = 1 # Mode - Sending data\nLCD_CMD = 0 # Mode - Sending command\n\nLCD_LINE_1 = 0x80 # LCD RAM address for the 1st line\nLCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line\nLCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line\nLCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line\n\nLCD_BACKLIGHT  = 0x08  # On\n#LCD_BACKLIGHT = 0x00  # Off\n\nENABLE = 0b00000100 # Enable bit\n\n# Timing constants\nE_PULSE = 0.0005\nE_DELAY = 0.0005\n\n#Open I2C interface\n#bus = smbus.SMBus(0)  # Rev 1 Pi uses 0\nbus = smbus.SMBus(1) # Rev 2 Pi uses 1\n\ndef lcd_init():\n  # Initialise display\n  lcd_byte(0x33,LCD_CMD) # 110011 Initialise\n  lcd_byte(0x32,LCD_CMD) # 110010 Initialise\n  lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction\n  lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off \n  lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size\n  lcd_byte(0x01,LCD_CMD) # 000001 Clear display\n  time.sleep(E_DELAY)\n\ndef lcd_byte(bits, mode):\n  # Send byte to data pins\n  # bits = the data\n  # mode = 1 for data\n  #        0 for command\n\n  bits_high = mode | (bits &amp; 0xF0) | LCD_BACKLIGHT\n  bits_low = mode | ((bits&lt;&lt;4) &amp; 0xF0) | LCD_BACKLIGHT\n\n  # High bits\n  bus.write_byte(I2C_ADDR, bits_high)\n  lcd_toggle_enable(bits_high)\n\n  # Low bits\n  bus.write_byte(I2C_ADDR, bits_low)\n  lcd_toggle_enable(bits_low)\n\ndef lcd_toggle_enable(bits):\n  # Toggle enable\n  time.sleep(E_DELAY)\n  bus.write_byte(I2C_ADDR, (bits | ENABLE))\n  time.sleep(E_PULSE)\n  bus.write_byte(I2C_ADDR,(bits &amp; ~ENABLE))\n  time.sleep(E_DELAY)\n\ndef lcd_string(message,line,style):\n  # Send string to display\n  # style=1 Left justified\n  # style=2 Centred\n  # style=3 Right justified\n\n  if style==1:\n    message = message.ljust(LCD_WIDTH,\" \")\n  elif style==2:\n    message = message.center(LCD_WIDTH,\" \")\n  elif style==3:\n    message = message.rjust(LCD_WIDTH,\" \")\n\n  lcd_byte(line, LCD_CMD)\n\n  for i in range(LCD_WIDTH):\n    lcd_byte(ord(message[i]),LCD_CHR)\n\n# Is MPD playing a song?\ndef mpc_status():\n    playing = (os.popen('mpc status | grep playing')).readline()\n    if playing==\"\":\n        return(0)\n    elif playing != \"\":\n\t    return(1)\n\n\t\t\n# Stuff to Display\ndef measure_temp():\n    temp = os.popen('vcgencmd measure_temp').readline()\n    return(temp.replace(\"temp=\",\"\").replace(\"'C\\n\",\"\"))\n\ndef ip_address():\n    ip = os.popen('hostname -I').readline()\n    return(ip.strip())\n\ndef cpu_load():\n    CPU_Pct=str(round(float(os.popen('''grep 'cpu ' \/proc\/stat | awk '{usage=($2+$4)*100\/($2+$4+$5)} END {print usage }' ''').readline()),2))\n    return(str(CPU_Pct))\n\ndef ram_used():\n    mem_used = (psutil.virtual_memory().used  \/ (1024.0 ** 2))\n    return(str(round(mem_used,2)))\n\ndef current_song():\n    song = os.popen('mpc -f %title%').readline()\n    return(song.strip())\n\ndef current_artist():\n    title = os.popen('mpc -f %artist%').readline()\n    return(title.strip())\n\ndef current_time():\n    stime = os.popen('mpc -f %time%').readline()\n    return(stime.strip())\n\ndef current_album():\n    album = os.popen('mpc -f %album%').readline()\n    return(album.strip())\n\ndef long_album():\n    str_album = \" \" * 20\n    long_album = str_album + current_album()\n    for i in range (0, len(long_album)):\n        lcd_text = long_album[i:(i+20)]\n        lcd_string(lcd_text,LCD_LINE_2,1)\n        time.sleep(0.4)\n        lcd_string(str_album,LCD_LINE_2,1)\n        continue\n\ndef radio_song():\n    sstring = os.popen('mpc -f %title%').readline()\n    astring = os.popen('mpc -f %title%').readline()\n    song = sstring.split('-')[1]\n    artist = astring.split('-')[0]\n    lcd_string(artist.strip(),LCD_LINE_1,2)\n    lcd_string(song.strip(),LCD_LINE_2,2)\n\t\ndef long_song():\n    str_song = \" \" * 20\n    long_song = str_song + current_song()\n    for i in range (0, len(long_song)):\n        lcd_text = long_song[i:(i+20)]\n        lcd_string(lcd_text,LCD_LINE_1,1)\n        time.sleep(0.05)\n        lcd_string(str_song,LCD_LINE_1,1)\n        lcd_string(song_elapsed()+\"\/\"+current_time(),LCD_LINE_4,3)\n\ndef scroll_title():\n    str_title = \" \" * 20\n    str_album = \" \" * 20\n    long_title = str_title + current_song()\n    long_album = str_album + current_album()\n    while True:\n        for i in range (0, 32):\n            lcd_text1 = long_title[i:(i+20)]\n            lcd_text2 = long_album[i:(i+20)]\n            lcd_string(lcd_text1,LCD_LINE_3,1)\n            lcd_string(lcd_text2,LCD_LINE_2,1)\n            time.sleep(0.05)\n            lcd_string(str_title,LCD_LINE_3,1)\n            lcd_string(str_album,LCD_LINE_2,1)\n            continue\n\n# MPD connection times out\n#def song_elapsed():\n#    elapsed = client.status()['elapsed']\n#    m, s = divmod(int(float(elapsed)), 60)\n#    h, m = divmod(m, 60)\n#    elapsed_min = (\"%02d:%02d\" % (m, s))\n#    return(elapsed_min)\n\ndef song_elapsed():\n    elapsed = os.popen('mpc status | awk \\'NR==2 { split($3, a, \"\/\"); print a[1]}\\'').readline()\n    return(elapsed.strip())\n\ndef main():\n  # Main program block\n\n  # Initialise display\n  lcd_init()\n\n# Display Method\n  while True:\n# Call MPD Display if Running\n#    client.connect(\"localhost\", 6600)\n#    if client.status()['state'] == \"play\":\n#        lcd_string(\"MPD is PLAYING\",LCD_LINE_2,1)\n#        client.disconnect()\n#        os.system('\/home\/pi\/scripts\/mpd_display.py')\t\n#    else:\n#        client.disconnect()  \n\n# Call MPD Display if Running\n    if mpc_status() == 0:\n        #os.system('\/home\/pi\/scripts\/mpd_display.py')\n        # Display Data\n        lcd_string(datetime.now().strftime('%m\/%d\/%Y %H:%M'),LCD_LINE_1,2)\n        lcd_string(ip_address(),LCD_LINE_2,2)\n        lcd_string(\"CPU: \"+measure_temp()+\"c \"+cpu_load()+\"%\",LCD_LINE_3,2)\n#       lcd_string(\" \",LCD_LINE_3,1)\n        lcd_string(\"RAM FREE: \"+ram_used()+\"Mgb\",LCD_LINE_4,2)\n        time.sleep(1)\n    elif mpc_status() == 1:\n        if (len(current_artist()) == 0):\n            sstring = os.popen('mpc -f %title%').readline()\n            astring = os.popen('mpc -f %title%').readline()\n            song = sstring.split('-')[1]\n            artist = astring.split('-')[0]\n            lcd_string(artist.strip(),LCD_LINE_1,2)\n            lcd_string(song.strip(),LCD_LINE_2,2)\n            lcd_string(song_elapsed()+\" \/ Stream Time\",LCD_LINE_4,3)\n        else:\n            lcd_string(current_artist(),LCD_LINE_1,1)\n            lcd_string(current_album(),LCD_LINE_2,1)\n            lcd_string(current_song(),LCD_LINE_3,1)\n            lcd_string(song_elapsed()+\"\/\"+current_time(),LCD_LINE_4,3)\n\n        time.sleep(0.1)\n       \n\nif __name__ == '__main__':\n\n  try:\n    main()\n  except KeyboardInterrupt:\n    pass\n  finally:\n    lcd_byte(0x01, LCD_CMD)\n\n\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>UPDATE: This file combines the code below into one script. I gutted an old RCA RC970 speaker into a RPI MPD Jukebox with LCD Screen. On boot, the LCD screen shows RPI data. If the MPD daemon is actively playing a song, the screen switches over to music data. I [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"footnotes":""},"categories":[6,8,9],"tags":[],"class_list":["post-557","post","type-post","status-publish","format-standard","hentry","category-music","category-projects","category-raspberry-pi"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/markwheeler.com\/index.php?rest_route=\/wp\/v2\/posts\/557","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/markwheeler.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/markwheeler.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/markwheeler.com\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/markwheeler.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=557"}],"version-history":[{"count":0,"href":"https:\/\/markwheeler.com\/index.php?rest_route=\/wp\/v2\/posts\/557\/revisions"}],"wp:attachment":[{"href":"https:\/\/markwheeler.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=557"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/markwheeler.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=557"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/markwheeler.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=557"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}