Fridge Gizmo recap

Behold the mighty FridgeGizmo! Er, not on the fridge. Yet.

Here’s a quick recap on the main steps I took in making a self-contained gizmo which displays London weather, global random tweets and Twitter trends on an LCD display. No soldering was involved. It’s really rather hypnotic watching utterly random tweets scroll by on a cool blue LCD display…

Ingredients:

  • RaspberryPi with normal, default bog-standard Raspbian OS – I used a model B with ethernet, but an A would do as I was also using…
  • Edimax USB wifi dongle.
  • Arduino Uno microcontroller.
  • LCD keypad shield for Arduino – though I’ve not used the buttons yet, and any Arduino-friendly display would do.
  • Kindle power supply for Raspberry Pi.
  • Some random old power supply for the Arduino.
  • A USB lead. A really, really short A-B lead or adapter would be better than the one I have.

Method:

  1. My basis was this project: http://www.midnightcheese.com/2011/10/displaying-twitter-and-weather-on-your-arduino-lcd-screen/
    This uses a Mac to send weather and tweets to an Arduino with a different LCD display.
  2. I tweaked the Arduino code for my display etc.
  3. I got my Raspberry Pi connected to the internet over wifi.
  4. I installed the Apache web server and PHP on the Raspberry Pi.
  5. I tweaked the PHP script to show weather in London in centigrade, rather than Nashville in Fahrenheit.
  6. I added a horrible kludge to the bash script that calls the PHP script in order to keep open the serial communication between the Pi and the Arduino.
  7. I got the RaspberryPi to run the script automatically when I turned it on. This was harder than I expected but I got there.

To do list:

  • get the display to scroll twitter trends or split over two lines – at the moment trends are truncated
  • display UK twitter trends rather than global trends
  • weather forecast, not current weather
  • my display can’t cope with accented characters – strip out, replace with equivalent normal ASCII ones or work out how to get display to do it.
  • display the time of my next train into town – this is going to be difficult as our local train data isn’t freely syndicated – well, why would you want to encourage people to use public transport when you can charge people to breathe the air around them? (Little bit of politics, there).
  • get the buttons to do something – switch between tweets, weather, train info?
  • build it into a box and stick it to the fridge or put it on a bookcase, bedside table
  • add a clock?
  • possible heresy: remove the Arduino and get the Raspberry Pi to address the LCD display directly. This must be eminently do-able, but I like my Arduino and the way the LCD shield just plugs into it. I’m not good at soldering.

Raspberry Pi displaying random tweets on LCD display via an Arduino

Source Code

Here’s the code I uploaded to the Arduino, very slightly tweaked from Midnight Cheese: http://www.midnightcheese.com/2011/10/displaying-twitter-and-weather-on-your-arduino-lcd-screen/

#include <LiquidCrystal.h>
#include <WString.h>

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// these figures copied from sample sketch that came with my LCD shield

void setup() {
//  analogWrite(5, 100);    // Set LCD contrast level (0-255) - removed for my LCD shield
  lcd.begin(16, 2);       // Set the LCD's number of rows and columns
  Serial.begin(9600);     // Initialize communication with serial(USB) port.
  lcd.print("FridgeGizmo v1.1");    // Print welcome message to LCD.
  lcd.setCursor(0, 1);              // move cursor to start of 2nd line of display
  lcd.print(">>>fetching data");    // Print 'please wait' message to LCD.
}

int bufferArray[250];     // Our array to store characters arriving from serial port.
int output = 0;
int i = 0;

void loop() {
  int count = Serial.available();

  if (Serial.available() > -1) {
    delay(1000);
    for (i=0; i<count ; i++) {
     bufferArray[i] = Serial.read();          // Put into array
     output = 1;                              // Show new data has been recieved
    }
  }

  if (output != 0) {                          // If new bytes have been recieved
    int position = 0;
    if (bufferArray[0] == '!') {              // Print on first line if message begins with '!'
      lcd.clear();
      lcd.setCursor(0,0);
      position = 1;
    } else if (bufferArray[0] == '@') {       // Print on second line if message begins with '@'
      lcd.setCursor(0,1);
      position = 1;
    } else if (bufferArray[0] == '^') {       // Clear screen if message begins with '^'
      lcd.clear();
      lcd.setCursor(0,0);
      position = 1;
    } else {
      lcd.clear();
      lcd.setCursor(0,0);
    }
    int j;
    for (j = position; j < count; j++) {
      lcd.write(bufferArray[j]);
    }
    output = 0;                               // Don't print on next iteration
    memset(bufferArray, 0, count);
    count = 0;
  }
}

This is the tweetwx.sh bash script on the RaspberryPi that runs the tweetwx.php script with the ‘screen’ command kludge at startup:

#!/bin/bash

screen -d -m /dev/ttyACM0 9600

sudo php /var/www/tweetwx.php

This is the PHP code tweetwx.php that fetches weather & twitter data from the internet and formats it and sends it to the Arduino and display:

<?php
// Include the PHP Serial class.
include "php_serial.class.php";
//Define the serial port to use
define('SERIALPORT','/dev/ttyACM0');

// Weather
$zipcode = "UKXX0085";
$title = "London UK WX.";
// $unit = "c"; - will add unit switch later

// Setup the serial connection
$serial = new phpSerial;
$serial->deviceSet(SERIALPORT);
$serial->confBaudRate(9600);

// Time
$lastTime = date('D M j H:i:s Y');
$lastTime = strtotime($lastTime);

// Scroll text up LCD screen
function scrollChunks($message) {
  global $serial;
  $serial->deviceOpen();
  for ($i=0; $i<count ($message); $i++) {
    if ($i==0) {
      $serial->sendMessage($message[$i]);
    } else if ($i&1 && $i!=0) { // If $i is odd and not zero
      $serial->sendMessage($message[$i]);
      sleep(1);
      $message[$i] = substr_replace($message[$i], "!", 0, 1); // Print on top line !
      $serial->sendMessage($message[$i]);
    } else if (!($i&1) && $i!=0) { // If $i is even and not zero
      $message[$i] = substr_replace($message[$i], "@", 0, 1); // Print on top line @
      $serial->sendMessage($message[$i]);
      sleep(1);
      $message[$i] = substr_replace($message[$i], "!", 0, 1); // Print on top line !
      $serial->sendMessage($message[$i]);
    }
    echo $message[$i]."\n";
    sleep(1);
  }
  sleep(1);
  $serial->sendMessage(" ");
  $serial->deviceClose();
}

// Wordwrap our text to lines no more than 15 characters long.
// The LCD displays 16 characters at a time, minus a space for our
// placement character.
function segmentString($t) {
  $chunks = wordwrap($t, 15, "\n", true);
  $chunks = explode("\n", $chunks);
  // Alternate each line with '!' and '@'
  for ($i=0; $i<count ($chunks); $i++) {
    if ($i&1) {
      $chunks[$i] = "@".$chunks[$i];
    } else {
      $chunks[$i] = "!".$chunks[$i];
    }
  }
  scrollChunks($chunks);
}

function displayRSS() {
  global $serial;
  global $title;
  echo "Display only: ".$title."\n";
  sleep(3);
  $serial->deviceOpen();
  $serial->sendMessage($title);
  sleep(240);
  $serial->sendMessage("^");
  sleep(3);
  $serial->deviceClose();
}

function pullWXRSS() {
  global $zipcode;
    $yql = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20location%3D\"".$zipcode."\"%20and%20u%3D\"c\"&format=json";

  $session = curl_init($yql);
  curl_setopt($session, CURLOPT_RETURNTRANSFER,true);
  $json = curl_exec($session);
  $json_output =  json_decode($json,true);
  global $serial;
  global $title;
  $title = $json_output['query']['results']['channel']['item']['condition']['temp']."c ".$json_output['query']['results']['channel']['item']['condition']['text'];
  echo "Pull and Display: ".$title."\n";
  echo "Waiting a few seconds to display on Arduino...\n\n";
  sleep(5);
  $serial->deviceOpen();
  $serial->sendMessage($title);
  sleep(240);
  $serial->deviceClose();
  sleep(3);
}

// Display current weather from Yahoo! YQL
function displayWX() {
  global $lastTime;
  global $title;

  $currentTime = date('D M j H:i:s Y');
  $currentTime = strtotime($currentTime);

  echo "\n\n\n\nCurrent Time: ".$currentTime."\n";
  echo "Last Time: ".$lastTime."\n";

  $timeDiff = $currentTime - $lastTime;
  echo "Time Difference: ".$timeDiff."\n";

  // 1 hour = 3600
  if ($timeDiff>=3605 || $title == "London UK WX.") {
    echo "It's been an hour. Pulling WX.\n";
    $lastTime = $currentTime;
    pullWXRSS();
  } else {
    echo "An hour has not passed. Displaying old WX.\n";
    displayRSS();
  }
  displayPubTimeline();
}

function displayPubTimeline() {
  $jsonurl = "http://api.twitter.com/1/statuses/public_timeline.json";
  $json = file_get_contents($jsonurl,0,null,null);
  $json_output = json_decode($json,true);
  foreach ($json_output as $tweet) {
    $name = $tweet['user']['screen_name'];
    $text = $tweet['text'];
    echo "\n\n\n".$name."\n";
    echo $text."\n\n";
    global $serial;
    $serial->deviceOpen();
    $serial->sendMessage("Twitter User:");
    sleep(1.5);
    $serial->sendMessage("@".$name);
    echo "@".$name."\n";
    sleep(2);
    $serial->deviceClose();
    if (strlen($text) > 16) {
      segmentString($text);
    } else {
      $serial->deviceOpen();
      $serial->sendMessage($text);
      $serial->deviceClose();
    }
    sleep(5);
  }
  sleep(5);
  displayTopTrends();
}

function displayTopTrends () {
  $jsonurl = "http://api.twitter.com/1/trends/daily.json";

  $json = file_get_contents($jsonurl,0,null,null);
  $json_output = json_decode($json,true);
  $json_output = current($json_output['trends']);

  global $serial;

  $serial->deviceOpen();
  $serial->sendMessage("The top 20");
  sleep(1);
  $serial->sendMessage("@Twitter trends:");
  $serial->deviceClose();
  sleep(3);
  echo "\n\nTwitter Trends\n\n";

  foreach ($json_output as $trend) {
    $trendname = $trend['name'];
    echo $trendname."\n";
    $serial->deviceOpen();
    $serial->sendMessage("^".$trendname);
    $serial->deviceClose();
    sleep(15);
  }
  $serial->deviceOpen();
  $serial->sendMessage("^");
  sleep(1);
  $serial->deviceClose();
  sleep(3);
  displayWX();
}

displayWX();
?>
This entry was posted in Arduino, computers, hardware, Raspberry Pi, Raspbian and tagged , , , , . Bookmark the permalink.

One Response to Fridge Gizmo recap

  1. Cale says:

    Ah, very cool. The Raspberry Pi integration is a great idea. Give that thing a solar panel and the only thing holding it back is Wi-fi range.

Leave a Reply to Cale Cancel reply