Project in progress

16x2 LCD Backpack with Enclosure for the Onion Omega © GPL3+

This is a 3D printable backpack module using ATmega328 that includes an enclosure for all the components. It allows the LCD to be online.

  • 4,732 views
  • 5 comments
  • 18 respects

Components and supplies

Necessary tools and machines

09507 01
Soldering iron (generic)

Apps and online services

About this project

In this project, we are going to build a backpack circuit to enable communication between the Onion Omega2 and the 16x2 LCD display. By doing that, we'll be able to pull data from the web to show in the display!

Full STL files for the project are available at Thingiverse: http://www.thingiverse.com/thing:2125987

Getting Started

Our objective is to power the ATmega328 and the LCD using the 5V output available at the Onion Omega expansion dock. Also we'll connect the Omega TX1 to the ATmega328 RX0 in order to enable communication between them. It should fit the pins at the dock and occupy as less space as possible.

Backpack Circuit

Soldering

Arduino IDE

We'll use the Arduino IDE to upload the program to our ATmega328. The source code is available to download below. It's a work in progress, feel free to modify it to better serve your needs.

Assembly

Testing

When everything is in place, we can start the software side. We'll be talking to the ATmega328 using the Omega TX1. There is a script called lcd-16x2 for that. You can download it and place it at /usr/sbin on the Omega.

Once its there, assuming you are connected to your Omega2, using the console, you can send a text with the command:

lcd-16x2 write "Hello!"

You can clean the display with the command:

lcd-16x2 clean

If your LCD displays supports light, you can turn it on and off:

lcd-16x2 lightOn
lcd-16x2 lightOff

Onion App

An Onion App as far I could understand (I'm new to the platform) is a folder inside /www/console/apps that includes an icon (icon.png) a description file (app.json) and the app file itself (onion-lcd-16x2.html in this case). There may also be other files related to the app, like images, javascript (js) and style sheets (css).

I made a very simple Onion App based on the templates available at GitHub: https://github.com/OnionIoT/Onion-Console/tree/master/www/apps

Feel free to download it and modify to fit your needs. You can uncompress it by using the following commands (assuming you placed lcd-16x2.tgz right there):

cd /www/console/apps 
tar zxvf lcd-16x2.tgz  

Calibrating

The LCD display needs to be calibrated to show the text correctly. In order to do that, just tune the 10k Trimmer Potentiometer until you see the best contrast.

Enclosure

Its a good idea to print some small washers for the bolts so when they make contact with the dock board, they won't harm any tiny component there.

All the files for the enclosure are available at Thingiverse: http://www.thingiverse.com/thing:2125990

Pulling Data

Once the Omega is connected to the web, we can grab data from several sources. The script below uses the Yahoo! Finance API real time data to create and populate a file under /www/data called nasdaq.json

All we need to do is set up a cron to run our script periodically following the instructions: https://docs.onion.io/omega2-docs/running-a-command-on-a-schedule.html

Code

ATmega328 Source CodeArduino
To be uploaded using the Arduino IDE
#include <LiquidCrystal.h>

String display_status = "off"; 
String light_status = "off"; 
String output_status = "off"; 
String marquee_status = "off";
int marquee_max = 1000; 
int marquee_position = 0; 
int input_status = 0; 

int currlin = 0;  
String inputString = "";         // a string to hold incoming data
String inputString2 = "";        // another string to hold incoming data
boolean stringComplete = false;  // whether the string is complete
String temPString = "";  

String inputStringOK = "";
String inputStringOK2 = "";
String inputStringMar = "";
String temPStringVal = "";

unsigned long timer;

// initialize the library with the numbers of the interface pins
//LiquidCrystal(rs, enable, d4, d5, d6, d7);
LiquidCrystal lcd(A5, A3, 13, 12, 11, 10);

void setup() {
  
  pinMode(9, OUTPUT);
  analogWrite(9, 0);
  
  
  Serial.begin(9600);
  // reserve 200 bytes for the inputStrings:
  inputString.reserve(200);
  inputString2.reserve(200);
  
  timer=millis();

              lcd.begin(16, 2);
              lcd.setCursor(0, 0);
              lcd.print("                ");
              lcd.setCursor(0, 1);
              lcd.print("                ");
              lcd.noDisplay();
}

void loop() {
  
  unsigned long mils=millis();
        //Serial.print("+");
        Serial.print("{ \"input_status\": ");
        Serial.print(analogRead(A4));
        Serial.print(", \"output_status\": \"");
        Serial.print(output_status);
        Serial.print("\", \"display_status\": \"");
        Serial.print(display_status);
        Serial.print("\", \"light_status\": \"");
        Serial.print(light_status);
        Serial.println("\" }");
        delay(100);
        Serial.flush();


        if (marquee_status == "on") {
          if (mils-timer>=marquee_max) {
            timer=mils;
            lcd.scrollDisplayLeft();
          }
        }
  
  // print the string when a newline arrives:
  if (stringComplete) {


            temPString = inputString;
            temPString.remove(5);

            
                //lcd.setCursor(0, 0);
                //lcd.print(temPString);

            if (temPString == "wgtmm") {          
              
                lcd.display();
            
                inputString.remove(inputString.length()-1);
                inputString = inputString.substring(5);
                
                inputString2.remove(inputString2.length()-2);
                
                
                while (inputString.length() < 17) inputString = inputString +  " ";
                while (inputString2.length() < 17) inputString2 = inputString2 + " ";

                inputStringOK = inputString;
                inputStringOK2 = inputString2;
              
                lcd.setCursor(0, 0);
                lcd.print(inputString);
                lcd.setCursor(0, 1);
                lcd.print(inputString2);

            }

            if (temPString == "wgtcm") {    
              
                inputString = inputString.substring(5);            
                inputString.remove(inputString.length()-2);


              inputStringMar = inputString;
              inputStringMar.remove(2);

              if (inputString == "Init") {
                lcd.display();
                display_status = "on";
                for (int i=0;i<255;i++) {
                  analogWrite(9, i);
                  delay(2);
                }
                light_status = "on";
              }  

              if (inputString == "dCl") {
                  lcd.display();
                  lcd.setCursor(0, 0);
                  lcd.print("                                                                                ");
                  lcd.setCursor(0, 1);
                  lcd.print("                                                                                ");
              }

              if (inputString == "dOn") {
                if (display_status == "off") {
                  lcd.display();
                  display_status = "on";
                }
              }    

              if (inputString == "dOff") {
                if (display_status == "on") {
                  lcd.noDisplay();
                  display_status = "off";
                }
              }     

              if (inputString == "dTog") {
                if (display_status == "on") {
                  lcd.noDisplay();
                  display_status = "off";
                } else {
                  lcd.display();
                  display_status = "on";
                }
              }  

              if (inputString == "qOn") {
                if (marquee_status == "off") {
                  marquee_status = "on";
                }
              }    

              if (inputString == "qOff") {
                if (marquee_status == "on") {
                  marquee_status = "off";
                  lcd.setCursor(0, 0);
                  lcd.print(inputStringOK);
                  lcd.setCursor(0, 1);
                  lcd.print(inputStringOK2);
                }
              } 

              if (inputStringMar == "mv") {
                temPStringVal = inputString.substring(2);
                marquee_max = temPStringVal.toInt();
              }  

              if (inputString == "lOn") {
                if (light_status == "off") {
                  for (int i=0;i<255;i++) {
                    analogWrite(9, i);
                    delay(2);
                  }
                  light_status = "on";
                }
              }    

              if (inputString == "lOff") {
                if (light_status == "on") {
                  for (int i=255;i>0;i--) {
                    analogWrite(9, i);
                    delay(2);
                  }
                  light_status = "off";
                }
              } 

              if (inputString == "lTog") {
                if (light_status == "on") {
                  for (int i=255;i>0;i--) {
                    analogWrite(9, i);
                    delay(2);
                  }
                  light_status = "off";
                } else {
                  for (int i=0;i<255;i++) {
                    analogWrite(9, i);
                    delay(2);
                  }
                  light_status = "on";
                }
              }

  
            }
            

                inputString = "";
                inputString2 = "";
                stringComplete = false;
                currlin = 0;
                Serial.flush();

            
          }
    
  
  
}



void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:

    if (currlin == 0)
    inputString += inChar;
    
    if (currlin == 1)
    inputString2 += inChar;
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == '*') {
      //stringComplete = true;
      currlin = 1;
    }
    if (inChar == '\n') {
      stringComplete = true;
    }
    
    
  }
}
Onion AppHTML
To be extracted at /www/console/apps
No preview (download only).
lcd-16x2BatchFile
To be at /usr/sbin with chmod +x (execute permission)
#!/bin/ash
case "$1" in
        clean)
echo "wgtmm*" > /dev/ttyS1
            ;;
         
        lightOn)
echo "wgtcmlOn" > /dev/ttyS1                                  
            ;;

        lightOff)     
echo "wgtcmlOff" > /dev/ttyS1                                 
            ;;    

        lightToggle)    
echo "wgtcmlToggle" > /dev/ttyS1                                 
            ;;    

        textToggle)
echo "wgtcmdToggle" > /dev/ttyS1                                  
            ;;    
 
        textOn)
echo "wgtcmdOn" > /dev/ttyS1
            ;;

        textOff)
echo "wgtcmdOff" > /dev/ttyS1
            ;;

        write)
echo "wgtmm$2                *$3                " > /dev/ttyS1
            ;;
         
        *)
            echo $"Usage: $0 {clean|write}"
            exit 1
 
esac
nasdaqBatchFile
To be at /usr/sbin with chmod +x (execute permission)
Executed by the cron periodically.
#!/bin/ash
echo wgtcmqOn > /dev/ttyS1
sleep 1
curl -k 'https://query.yahooapis.com/v1/public/yql?q=select%20symbol,%20Change,%20LastTradePriceOnly%20from%20yahoo.finance.quote%20where%20symbol%20in%20(%22INTC%22,%22AAPL%22,%22GOOG%22,%22MSFT%22,%22ADBE%22)&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=' -H 'Accept-Encoding: gzip, deflate, sdch, br' -H 'Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.6,en;q=0.4,es;q=0.2,ru;q=0.2' -H 'Upgrade-Insecure-Requests: 1' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Cache-Control: max-age=0' -H 'Connection: keep-alive' -o /www/data/nasdaq.json
X=$(sed "s/[,{}]/&\n/g" /www/data/nasdaq.json | awk "/symbol/,/}/ { print }" | grep ":" | grep -v "}" | awk '{$1=$1}1')
count=0
#echo $X
total=""
total2=""
for item in $X
do
  count=$((count+1))
  
  if [ $count -eq 1 ] || [ $count -eq 3 ] || [ $count -eq 5 ] || [ $count -eq 7 ] || [ $count -eq 9 ]
  then
  arr=$(echo $item | tr "\"" "\n")
  #  echo "$arr"
tempTotal=$(echo $item | awk -F'"' '{print $4}')
#echo "$tempTotal"
total="$total$tempTotal    "
#echo $item
  fi
  
  if [ $count -eq 2 ] || [ $count -eq 4 ] || [ $count -eq 6 ] || [ $count -eq 8 ] || [ $count -eq 10 ]
  then
  arr=$(echo $item | tr "\"" "\n")
  #  echo "$arr"
tempTotal=$(echo $item | awk -F'"' '{print $4}')
tempTotal=$(echo $tempTotal | awk '{print substr($0,0,5)}')
#echo "$tempTotal"
total2="$total2$tempTotal   "
#echo $item
  fi

  #echo $count $item
done
#echo "FN"
#echo "$total"
#echo "$total2"
lcd-16x2 write "$total*$total2"

Custom parts and enclosures

Backpack Circuit
Backpack Circuit Cover
Bottom Enclosure
Top Enclosure
Small Washer

Schematics

Backpack circuit
Screen shot 2017 02 21 at 10 01 32 oimufd2ti0

Comments

Similar projects you might like

Ninja Dollar - LCD game

Project tutorial by anime

  • 2,352 views
  • 2 comments
  • 4 respects

IoT-Enabled LCD Display

by Team Nitro

  • 5,163 views
  • 4 comments
  • 7 respects

ATmega Alien Themed Slot Machine

Project tutorial by Dan Murphy

  • 1,081 views
  • 5 comments
  • 14 respects

Using 16x2 LCD with Arduino

by Techmirtz

  • 19,426 views
  • 3 comments
  • 34 respects
Add projectSign up / Login