Сергей Мелехин
Published © MIT

Twitter Pager

LoFi hardware twitter news reader every nerd needs!

EasyFull instructions provided3 hours270

Things used in this project

Hardware components

Omega2 Plus
Onion Corporation Omega2 Plus
×1
Onion Corporation Onion Arduino Dock R2
×1
DFRobot LCD Keypad Shield
×1

Story

Read more

Code

get_tweets.py

Python
Gets tweets stream from Twitter API, cleans text, splits for 2 line 16 symbols pages and sends to Arduino via i2c.
#!/usr/bin/env python
import os
import re
import threading
import time
import logging

from twitter import Api
from ConfigParser import ConfigParser
from OmegaExpansion import onionI2C

curr_tweet = ["Waiting for tweets"]
curr_page = 0
paging_period = 4
data_lock = threading.Lock()

def load_config(filename):
    '''Load secrets from configfile'''
    config = ConfigParser()
    config.read(filename)
    user_ids = config.get("twitter", "user_ids", "783214").split(",")
    config.set("twitter", "user_ids", user_ids)
    return config


def split_the_tweet(tweet):
    '''split tweet to 32 symbol pages'''
    curr_tweet = []
    tweet = chr(2) + " " + tweet # add start tweet symbol
    try:
        while len(tweet) > 32:
            page = tweet[:32]
            sp = page.rfind(" ")
            if sp > 0:
                page = page[:sp]
            tweet = tweet[sp:]
            curr_tweet.append(page.strip())
        curr_tweet.append(tweet.strip())
    except:
        logging.exception("Error in split_the_tweet")
    return(curr_tweet)

def send(tweet):
    '''send via i2c to arduino dock'''
    for page in tweet:
        data = [ord(c) for c in page[:32]]
        i2c.writeBytes(8, 2, data)
        time.sleep(paging_period)


if __name__ == '__main__':

        logging.basicConfig(format='%(asctime)s %(message)s',
                            level=logging.INFO)

        i2c     = onionI2C.OnionI2C()

        k = load_config("config.ini")
        api = Api(k.get("twitter","consumer_key"),
                  k.get("twitter","consumer_secret"),
                  k.get("twitter","access_token"),
                  k.get("twitter","access_token_secret"))

        while True:
            try:
                for tweet in api.GetStreamFilter(follow=k.get("twitter", "user_ids")):
                        text = tweet.get("text")
                        if text is None:
                            continue
                        text = text.lower()
                        text = re.sub('http(s)?:[^\s]+', '', text) # remove urls
                        text = re.sub('#', '', text) # remove hashtags
                        text = re.sub('[\s]{2}', ' ', text).strip() # trim extra spaces
                        # ignore replies and retweets
                        if tweet.get("in_reply_to_screen_name") is not None or \
                           tweet.get("in_reply_to_status_id") is not None or \
                           tweet.get("retweeted_status") is not None or \
                           len(text) < 5:
                            continue

                        logging.info(text)

                        send(split_the_tweet(text))
            except KeyboardInterrupt:
                print("Bye!")
                exit()
            except:
                logging.exception("Main loop")
                logging.warn("Waiting 60 seconds to avoid blocking twitter app")
                time.sleep(60)

lcd_sketch.ino

C/C++
Arduino sketch that prints tweets, scrolls through them and processes keypresses to change brightness and flip pages.
#include <LiquidCrystal.h>
#include <LCDKeypad.h>
#include <Wire.h>
#include <avr/wdt.h>
#include <string.h>

#define ledPin 13 // Onboard LED
#define LINE_SIZE 16
#define PAGE_SIZE 32
#define NUM_PAGES 30
#define PAGE_FLIP_TIME 2500

char pages[NUM_PAGES][PAGE_SIZE+1];
int curr_page = -1;
int max_page = -1;
int scrolled_page = 0;
int scroll_return_deadline;
int page_flip_deadline;
bool need_redraw = false;

byte c_ellipsis[8] = {
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B10101,
  B00000,
};

byte c_start[8] = {
  B11100,
  B10010,
  B10001,
  B10001,
  B10001,
  B10001,
  B10001,
  B11111,
};

LCDKeypad lcd;

// Restarts program from beginning but does not reset the peripherals and registers
void _SoftwareReset() {
  wdt_enable(WDTO_15MS);
}

//Set LCD Keypad Shield backlight brightness
void setLCDBrightness(byte brightness) {
  analogWrite(10, brightness);
}

void print_page(int n) {
  char str[2][17];

  memset(&str[0],0,17);
  memset(&str[0],0,17);

  for(int j=0; j<32; j++)
  {
    str[j/16][j%16] = pages[n][j];
  }

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(str[0]);
  lcd.setCursor(0,1);
  lcd.print(str[1]);
}

void setup() {

 lcd.createChar(1,c_ellipsis);
 lcd.createChar(2,c_start);
 lcd.begin(16, 2);
 lcd.clear();
 lcd.noAutoscroll();
 lcd.print("Arduino started\0x01");
 setLCDBrightness(100);
 pinMode(ledPin, OUTPUT);
 digitalWrite(ledPin, LOW);

 Wire.begin(0x08); // 0x08 is the arduino dock 2 i2c port
 Wire.onReceive(i2c_on_receive_handler);
 //Wire.onRequest(i2c_on_request_handler);
}


// called when a transmission is received via the i2c port
void i2c_on_receive_handler(int bytes_received) {
  char cmd = Wire.read();

  switch (cmd) {
    case 0xde:
      char next;
      next = Wire.read();
      if (next == 0xad) {
        _SoftwareReset();
      }
      break;
     case 1:
      setLCDBrightness(Wire.read());
      break;
     default:
      curr_page++;
      if(curr_page == NUM_PAGES) curr_page = 0;
      memset(&pages[curr_page], 0, PAGE_SIZE+1);
      int i = 0;
      while (Wire.available() > 0) {
        pages[curr_page][i++] = char(Wire.read());
      }
      need_redraw = true;
      if(max_page<NUM_PAGES-1)
      {
        max_page = curr_page;
      }
  }
}

int key;
int b = 100;
#define DELAY_MS 60

void loop() {
  while(true) {
    key = analogRead (0);
    if (key < 760) {
      if(key < 30) {
          scrolled_page++;
          if(scrolled_page>max_page) scrolled_page = 0;
          need_redraw = true;
      } else if(key < 150 && b < 240) {
        b += 20;
      }
      else if(key < 360 && b > 20) {
        b -= 20;
      } else if (key < 535) {
          scrolled_page--;
          if (scrolled_page < 0) scrolled_page = max_page;
          need_redraw = true;
      }
      setLCDBrightness(b);
    }
    if(need_redraw && (max_page >= 0)) {
      print_page(scrolled_page);
      need_redraw = false;
      page_flip_deadline = PAGE_FLIP_TIME;
    }
    if(page_flip_deadline>0) {
      page_flip_deadline-=DELAY_MS;
    } else {
      scrolled_page++;
      if(scrolled_page>max_page) scrolled_page = 0;
      need_redraw = true;
    }
    delay(DELAY_MS);
  }
}

Twitter pager github repository

Credits

Сергей Мелехин

Сергей Мелехин

1 project • 1 follower

Comments