FooDuinoLCD

FooDuinoLCD is literally nothing more than a project stemming from boredom during the very early part of this initial pandemic bullshit. It uses a combination of a Foobar2000’s “Now Playing Simple” plugin, a Python script, and some Arduino code. It simply scrolls one line containing artist and track info, with the other line containing track format information.

The Arduino script uses a scrolling routine I found on a forum I’ve long since forgotten; it was just a scrap of code in my idea folder.

fooduinolcd.ino

//----------------------------------
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);           // select the pins used on the LCD panel
 
const byte numBytes = 255;
char line1[numBytes];
char line2[numBytes];
//int period = 500;
unsigned long time_now = 0;
//int period2 = 2000;
unsigned long time2 = 0;
//----------------------------------
int Li          = 16;
int Lii         = 0;
int Ri          = -1;
int Rii         = -1;
//----------------------------------
void setup(){
  lcd.init();                           // start the LCD library
  lcd.backlight();
  Serial.begin(9600);
  time_now = millis();
}
//----------------------------------
 
void loop(){
if (Serial.available() > 0) {
  processdata();
}
/*  lcd.setCursor(0,1);            
  lcd.print(line2);  
  lcd.setCursor(0, 0);
  lcd.print(Scroll_LCD_Left(line1));
  time_now = millis();

delay(250); */
//if((millis()-time_now) > 250) {
updatelcd();
//time_now = millis();}
delay(250);
if(Lii==1) {delay(2000);} //wait 2 seconds before starting scroll
}
void updatelcd() { 
    lcd.setCursor(0,1);            
    lcd.print(line2);  
    lcd.setCursor(0, 0);
    lcd.print(Scroll_LCD_Left(line1));
    time_now = millis();
  }

//----------------------------------
String Scroll_LCD_Left(String StrDisplay){
  String result;
   if (StrDisplay.length() < 17) { // why scroll if we're under 16 characters?
    result = StrDisplay;
    return result;
  }
  String StrProcess = StrDisplay + "                ";
  result = StrProcess.substring(Li,Lii);
    Li++;
    Lii++;
  if (Li>StrProcess.length()){
    Li=16;
    Lii=0;
  }
  return result;
}
 
void Clear_Scroll_LCD_Left(){
  Li=16;
  Lii=0;
}
void processdata() {
    int ndx = 0;
    byte startMarker = 0x02;
    char linebreak = '\n';
    byte endMarker = 0x04;
    char rb;
    int topline;
   
topline = 1;
    while (Serial.available() > 0) {
        rb = Serial.read();
        if (rb==startMarker) {
          topline = 1;
          ndx = 0;
        }

        else {
        if (topline == 1) {          
             if (rb == linebreak) {
                line1[ndx] = '\0';
                topline = 0;
                ndx=0;
                Clear_Scroll_LCD_Left();        
             }
             else {
              line1[ndx] = rb;
              ndx++;
             }
                          }
             
        else  {
              if (rb == endMarker) {
                line2[ndx] = '\0';
                Serial.flush();
                clearLCDbuffer();
               
              }
              else {
                line2[ndx] = rb;
                ndx++;
              }
              }}
             
       }}
 
void clearLCDbuffer() {
    lcd.setCursor(0,0);
    lcd.print("                ");
    lcd.setCursor(0,1);
    lcd.print("                ");
}

The Arduino sketch essentially takes data from the serial port, looking for the control characters to indicate start of data, the start of line two, and the end of the data. It’s not a very good script and doesn’t check for errors. When it works, it works well. When it doesn’t…then you’ve got scrambled data until the next play.

foolcd.py

import time
import serial
ser = serial.Serial('COM4', 9600)
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
class MyHandler(FileSystemEventHandler):
    def on_modified(self, event):
        f = open("foodisplay.txt", "r")
        a=f.read()
        ser.write(a.encode('utf-8'))
        time.sleep(1)
        print("Updated")
event_handler = MyHandler()
observer = Observer()
observer.schedule(event_handler, path='D:/foodisplay/foodisplay.txt', recursive=False)
observer.start()
try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    observer.stop()
observer.join()

Most of this code I borrowed from an example for dealing with the watchdog stuff. Basically what we’re doing is watching for a text file to be updated, and then send it over the serial port. The textfile is generated by Foobar2000 and updated everytime the player changes status (stop, play, pause).

Foobar2000: Now Playing Simple

The Foobar2000 plugin “Now Playing Simple” is what we’re using for writing track information to the text file. Due to the flexibility of Foobar2000’s internal scripting, we can have it output a pre-formatted text file that’s largely ready to be sent to the Arduino.

$if(%isplaying%,
$if(%ispaused%,
Paused$crlf()
,
%artist% - %title%
$crlf()$ifequal($crc32($right(%filename_ext%,3)),1633189697, Super Audio CD , $div(%samplerate%,1000)$replace($insert($right($div(%samplerate%,100),1),.,0),.0,)/$ifequal([%__bitspersample%],0,16,%__bitspersample%) - %codec%  )
),
Not Playing   $crlf()
)

And that is basically it. You set Now Playing Simple to write to the text file, you modify the Python script to have your proper COM port and file path, boot up your Arduino, boot up the python script, and play.

The script is very buggy, a lot of times the output isn’t what it should be due to mssing a control character. It can also get confused if you blast too much data at it at once. My code for checking the serial port for control characters could be improved. The nice thing is if you do get total garbage, the only thing it crashes is the display; and most of the time it gets over it on the next track.

Site comments disabled. Please use Twitter.