This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Alternative Method LCD Display

Hi all,

I have put together a method for using an LCD screen like a HD44780 based 16x2 or 20x4. I had tried to use LCD4Linux, but couldn't get it working properly, and the more I stuffed around with the system the more problamatic it became.

It goes without saying that the below is NOT supported in any way shape or form and may void any support contracts, however I am using this in an Home UTM environment, so that suits me fine. You do not need to install any 3rd party utilities or programs on the system, only a small bash script and a crontab entry.

The concept:
Instead of a USB connected device, I have gone for a network based LCD running off an Arduino with an ethernet shield. I send a small HTTP request to the arduino, which converts the data into something that can be displayed on an LCD. This gives me a LOT of flexibility in customizing both the data sets and the LCD display itself, as well as possible expansion to multiple screens (not to mention it can be mounted away from the server itself).

I don't claim to be an expert in any of this, but it works, and works well, so I'm open to other ideas for improvement!

What you need:
Sophos UTM Box (Duh)
Arduino with an Ethernet shield (few options out that there but I'm using an Uno with Ethernet Shield)
HD44870 LCD (I'm using a 20x4 via 2IC, and you can actually use any display you want, you just need to change the libraries used with the arduino)

Arduino Configuration:
Nice and easy and I won't go into detail, but plug in the ethernet shield to the arduino, then, if you are using a 2IC model LCD, plug in VCC, GND, and SDA/SCL and that's it.

Aduino Code, which is heavily commented:

///////////////////////////////////////////////////////////////////////
//                          Include Libaries                         //
///////////////////////////////////////////////////////////////////////
#include  
#include 
#include 
#include 

////////////////////////////////////////////////////////////////////////
//                     CONFIGURE ETHERNET SHIELD                      //
////////////////////////////////////////////////////////////////////////


// Set Mac Address (comment out if not needed)
byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

EthernetServer server = EthernetServer(80); //port 80


////////////////////////////////////////////////////////////////////////
//                      Define custom chracters                       //
////////////////////////////////////////////////////////////////////////

#if defined(ARDUINO) && ARDUINO >= 100
#define printByte(args)  write(args);
#else
#define printByte(args)  print(args,BYTE);
#endif


byte DownArrow[8] = {
  B00100,
  B00100,
  B00100,
  B00100,
  B00100,
  B11111,
  B01110,
  B00100
};

byte UpArrow[8] = {
  B00100,
  B01110,
  B11111,
  B00100,
  B00100,
  B00100,
  B00100,
  B00100
};

////////////////////////////////////////////////////////////////////////
//                         Define LCD Display                         //
////////////////////////////////////////////////////////////////////////


LiquidCrystal_I2C lcd(0x27,20,4);  //0x27 is standard address, 20,4 is screen size


////////////////////////////////////////////////////////////////////////
//                         Declare Variables                          //
////////////////////////////////////////////////////////////////////////

char charnew;
String down = "";
long downnum = 0L;
long upnum = 0L;
String up = "";
String uptime = "";
String cpuload = "";
int switcher = 0;
String dlspeed = "";
String upspeed = "";
int firstrun = 1;
float cpupercent = 0;
String uptimeformat = "";
boolean connecteddhcp = 0;
int finished = 0;
boolean reading = false;


////////////////////////////////////////////////////////////////////////
//                             Setup Program                          //
////////////////////////////////////////////////////////////////////////

void setup()
{

  //Uncomment to enabled serial feedback
  //Serial.begin(115200);


  //Initialize the LCD
  lcd.init();

  //Initialize Custom LCD Characters
  lcd.createChar(0, DownArrow);
  lcd.createChar(1, UpArrow);


  // Print a loading message to the LCD.
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("     LCD Display");
  lcd.setCursor(0,1);
  lcd.print("     Sophos UTM");
  lcd.setCursor(0,3);
  lcd.print("Waiting for network");

  //Try to get DHCP IP address and loop until there is one
  connecteddhcp = Ethernet.begin(mac);
  while(connecteddhcp == 0){
    connecteddhcp = Ethernet.begin(mac);
  }

  //Start Ethernet server once IP address is assigned and received
  server.begin();
  
  //Print IP ADdress to LCD screen
  lcd.setCursor(0,3);
  lcd.print("                   ");
  lcd.setCursor(5,3);
  lcd.print(Ethernet.localIP());



}

////////////////////////////////////////////////////////////////////////
//                           Main Program Loop                        //
////////////////////////////////////////////////////////////////////////

void loop()
{

  //Listen for incoming clients, and run main function when received
  checkForClient();

}



////////////////////////////////////////////////////////////////////////
//                            Main Function                           //
////////////////////////////////////////////////////////////////////////

void checkForClient(){

  //Reset Variables for start of function
  reading = false;
  switcher = 0;
  down = "";
  downnum = 0L;
  upnum = 0L;
  cpupercent = 0L;
  uptimeformat = "";
  up = "";
  dlspeed = "";
  upspeed = "";
  cpuload = "";
  uptime = "";

  //Mark server as available
  EthernetClient client = server.available();

  //Check if Client has data for us
  if (client) {

    Serial.println("Data Received and available");
    //Confirm request - an http request ends with a blank line
    boolean currentLineIsBlank = true;
    boolean sentHeader = false;


    //Start read loop
    while (client.connected()) {
      //Debugging Level 1
      Serial.println("Pass Level 1");
      if (client.available()) {
        //Debugging Level 2
        Serial.println("Pass Level 2");

        //Pause for the entire message to arrive
        delay(100);


        if(!sentHeader){
          //Send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          sentHeader = true;
        }

        //Start read in of characters from HTTP Request
        char charnew = client.read();

        if(reading && charnew == ' ') reading = false;
        if(charnew == '?') reading = true; //Found the ?, begin reading the valid info


        if (reading){
          //Debugging level 3
          Serial.println("Pass Level 3");
          
          //Starting main data split, reads in the characters and splits them into strings based on the / found
          if (charnew == '?') {
            //Do nothing - skipping ? character
          }          
          else if (charnew != '/' && switcher == 0 ){
            down = down + charnew;
            switcher = 0;
            Serial.print("Download Speed: ");
            Serial.println(down);
          }
          else if (charnew == '/' && switcher == 0){
            switcher = 1;
            Serial.println("Detected Switch 1");
          }
          else if (charnew != '/' && switcher == 1){
            up = up + charnew;
            Serial.print("Upload Speed: ");
            Serial.println(up);
          }
          else if (charnew == '/' && switcher == 1){
            switcher = 2;
            Serial.println("Detected Switch 2");
          }
          else if (charnew != '/' && switcher == 2){
            cpuload = cpuload + charnew;
            Serial.print("CPULoad: ");
            Serial.println(cpuload);
          }
          else if (charnew == '/' && switcher == 2){
            switcher = 3;
            Serial.println("Detected Switch 3");
            cpuload = cpuload + "  ";
          }
          else if (charnew != '!' && switcher == 3){
            uptime = uptime + charnew;

            Serial.print("Uptime: ");
            Serial.println(uptime);
          }
          else if (charnew == '!' && switcher == 3){
            //Mark as finished, all data received
            finished = 1;
            break;
          }
        }
      }

      //Clean up HTTP Request
      if (charnew == '\n' && currentLineIsBlank)  break;

      if (charnew == '\n') {
        currentLineIsBlank = true;
      }
      else if (charnew != '\r') {
        currentLineIsBlank = false;
      }
    }

    Serial.println("Read in complete");

    //Confirm that data was received and needs to be printed
    if (finished == 1){
      
      //Convert string to intergers and float values
      downnum = down.toInt();
      upnum = up.toInt();
      cpupercent = cpuload.toFloat();
      long seconds = uptime.toInt();

      //Work out uptime
      long s = seconds % 60;
      long m = (seconds / 60) % 60;
      long h = (seconds / (60 * 60)) % 24;
      long d = (seconds / 60 / 60 / 24);

      cpupercent = cpupercent/2;
      cpupercent = cpupercent*100;

      //Format Download Speed
      if (downnum >= 1024) {
        downnum = (downnum/1024);
        dlspeed = " KB/s";
      }
      else {
        dlspeed = " B/s";
      } 

      //Format Upload Speed
      if (upnum >= 1024) {
        upnum = (upnum/1024);

        upspeed = " KB/s";

      }
      else {
        upspeed = " B/s";
      } 

      //If first time run, load labels
      if (firstrun == 1) {
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("WAN");
        lcd.printByte(0);
        lcd.setCursor(0,1);
        lcd.print("LNK");
        lcd.printByte(1);
        lcd.setCursor(0,2);
        lcd.print("CPU Load:");
        lcd.setCursor(0,3);
        lcd.print("Uptime:");
        firstrun = 0;
      }

      //Update LCD Screen with data
      lcd.setCursor(5,0);
      lcd.print("               ");
      lcd.setCursor(5,0);
      lcd.print(downnum);
      lcd.print(dlspeed);
      lcd.setCursor(5,1);
      lcd.print("               ");
      lcd.setCursor(5,1);
      lcd.print(upnum);
      lcd.print(upspeed);
      lcd.setCursor(10,2);
      lcd.print(cpupercent,0);
      lcd.print("%  ");
      lcd.setCursor(8,3);
      lcd.print(d);
      lcd.print("D");
      lcd.print(" ");
      lcd.print(h);
      lcd.print(":");
      lcd.print(m);
      lcd.print(":");
      lcd.print(s);
      lcd.print(" ");
      finished = 0;

    }
    
    //Give the web browser time to receive the data
    delay(1);
    //Close the connection
    client.stop();
    Serial.println("Data Read complete");

  } 

}






Sophos configuration:

You will need to update my below code based on the location of your scripts, but it is easy enough to follow. For the purpose of the below, the scripts are simply in /home/login/

create a file called statupdate in the /home/login directory

Open the file and copy/paste the following script, update the IP address with the IP address of the Arduino (I suggest a DHCP reservation (static)).



#!/bin/bash -x
IP='10.0.0.185'
while :
do
#echo "Start Loop"
DN=$(S=1; F=/sys/class/net/ppp0/statistics/rx_bytes; X=`cat $F`; /bin/sleep $S; Y=`cat $F`; BPS="$(((Y-X)/S))"; /bin/echo $BPS)
UP=$(S=1; F=/sys/class/net/ppp0/statistics/tx_bytes; X=`cat $F`; /bin/sleep $S; Y=`cat $F`; BPS="$(((Y-X)/S))"; /bin/echo $BPS)
CPU=$(/usr/bin/uptime | /bin/grep -oh "load average: [0-9].[0-9][0-9]")
CPU=$(/bin/echo $CPU | /bin/sed -r 's/^.{14}//')
UPTIME=$(/bin/cat /proc/uptime)
UPTIME=$(/bin/echo $UPTIME | cut -f1 -d" ")
#echo $DN
#echo $UP
#echo $CPU
#echo $UPTIME
#echo /usr/bin/curl $IP/?$DN/$UP/$CPU/$UPTIME!
/usr/bin/curl $IP/?$DN/$UP/$CPU/$UPTIME!
/bin/sleep 1
#echo "Finished Loop"
done



You can uncomment the Echos for debugging if needed, and change the interface you want to monitor (I'm using ppp)

Save the file and then set the execution permissions:

 sudo chmod u+x /home/login/statupdate  


Lastly, you need to add the script to crontab so that it starts on reboot.

Login to your server via SSH and run the following:

Sudo crontab -e


Hit I for insert when VI loads, then copy/paste (or type) the following:

@reboot /home/login/statupdate


Hit ESC, then type :wq and hit enter.

Hit reboot and you should be done, your LCD should now start updating every 5-6 seconds.


Hopefully someone finds this useful!



This thread was automatically locked due to age.