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.