Showing posts with label nook. Show all posts
Showing posts with label nook. Show all posts

Sunday, 3 February 2013

Nook - e-reader / Pi Display - Attempt 2.

OK - so I've finally got something close to what I was looking for here. The Nook can be sited standalone from the Pi and wirelessly grabs the image of the weather. - A script runs on the RPi (every hour from cron). - It generates a file (test.png) into an output directory - this graphic is generated using the script for the Kobo from here with minor modifications:-

http://www.mobileread.com/forums/showthread.php?t=194376

Then, on the Nook, I created a directory for a custom screensaver - /screensavers/weather.  The nook (rooted as previously with nookmanager) runs a program 'FolderSync' which periodically (every 6 hours) syncs the output directory on the RPi with the screensavers/weather directory on the Nook.

Finally, the Nook is configured so that the screensaver kicks in after 10 seconds by modifying the settings.db from http://forum.xda-developers.com/showthread.php?t=1721665.
Code:
adb pull /data/data/com.android.providers.settings/databases/settings.db settings.db

sqlite3 settings.db
update system set value=10000 where name='screen_off_timeout';
.q

adb push settings.db /data/data/com.android.providers.settings/databases/settings.db

The Kobo script is modified (actually much simplified) to create the output test.png as below:-
Code:
import urllib2
import pygame, os

from xml.dom.minidom import parseString
from datetime import date, datetime, timedelta
from subprocess import call

os.environ['SDL_NOMOUSE'] = '1'
print("Kobo Wifi weather forecast started.")

def index_error(error):
    print(error)
    print("Failed to fetch weather data.")
    print("Double check your location settings by running:")
    print(" cat location")
    print("If the information is incorrect, re-set your location with:")
    print(" set_location.sh")
    
def to_hex(color):
    hex_chars = "0123456789ABCDEF"
    return hex_chars[color / 16] + hex_chars[color % 16]
    
def convert_to_raw(surface):
    print("Converting image . . .")
    raw_img = ""
    for row in range(surface.get_height()):
        for col in range(surface.get_width()):
            color = surface.get_at((col, row))[0]
            raw_img += ('\\x' + to_hex(color)).decode('string_escape')
    f = open("/tmp/img.raw", "wb")
    f.write(raw_img)
    f.close()
    print("Image converted.")
    
    
def get_weather_data():
    
    print("Getting weather information . . .")

    try:
        location = open("location", "r")
        lat = location.readline().strip()
        lon = location.readline().strip()
        location.close()
    except IOError:
        print("\nCouldn't open location file.")
        print("Run the 'set_location.sh' script to set your location for the weather script.")
        return 1
    #print(lat, lon)
    #weather_link = 'http://graphical.weather.gov/xml/SOAP_server/ndfdSOAPclientByDay.php?whichClient=NDFDgenByDay&lat={0}&lon={1}&format=24+hourly&numDays=5&Unit=e'.format(lat, lon)
    weather_link='http://free.worldweatheronline.com/feed/weather.ashx?q={0},{1}&format=xml&num_of_days=5&key=525804183f140652120211'.format(lat, lon)
    #print(weather_link)
    weather_xml = urllib2.urlopen(weather_link)
    weather_data = weather_xml.read()
    weather_xml.close()

    dom = parseString(weather_data)
    
    unit_file = open("unit.txt", "r")
    unit = unit_file.read()
    unit_file.close()
    unit = unit.strip().upper()

    h_temps = dom.getElementsByTagName('tempMax%s' % unit)
    l_temps = dom.getElementsByTagName('tempMin%s' % unit)
    highs = []
    lows = []
    for i in h_temps:
        try:
            highs.append(str(i.firstChild.nodeValue))
        except AttributeError as error:
            print("Error getting temperature highs: " + str(error))
                    
    for i in l_temps:
        try:
            lows.append(str(i.firstChild.nodeValue))
        except AttributeError as error:
            print("Error getting temperature lows: " + str(error))

              
    conditions = []
    for con in dom.getElementsByTagName('weatherDesc')[1:]:
        conditions.append(str(con.firstChild.nodeValue))
        
    now = datetime.now()
    day3 = now + timedelta(days=2)
    day4 = now + timedelta(days=3)
    day5 = now + timedelta(days=4)
    days = ["Today", "Tomorrow", day3.strftime("%A"), day4.strftime("%A"), day5.strftime("%A")]

    # images
    # The first image link is for the current weather, which we don't want.
    icons = dom.getElementsByTagName('weatherIconUrl')[1:]
    img_links = []
    for i in icons:
        try:
            link = "icons/" + str(i.firstChild.nodeValue)[72:]
        except AttributeError as error:
            print("Error getting icon links: " + str(error))
        img_links.append(link)
        
        
    #print(img_links)
    #print(highs, lows)
    #print(conditions)
    #print(days)
    
    display(days, highs, lows, conditions, img_links, unit)


def display(days, highs, lows, conditions, img_links, unit):
    
    print("Creating image . . .")
   
    pygame.font.init()
    #pygame.mouse.set_visible(False)

    white = (255, 255, 255)
    black = (0, 0, 0)
    gray = (125, 125, 125)

    # AJR - try init display - output to PC screen for testing.
    # pygame.display.init()
    ### screen = pygame.display.set_mode((600, 800))
    screen = pygame.Surface((600, 800))
    screen.fill(white)

    tiny_font = pygame.font.Font("Cabin-Regular.ttf", 18)
    small_font = pygame.font.Font("Fabrica.otf", 22)
    font = pygame.font.Font("Forum-Regular.ttf", 40)
    comfortaa = pygame.font.Font("Comfortaa-Regular.ttf", 60)
    comfortaa_small = pygame.font.Font("Comfortaa-Regular.ttf", 35)

    # Dividing lines
    pygame.draw.line(screen, gray, (10, 200), (590, 200))
    pygame.draw.line(screen, gray, (10, 400), (590, 400))
    pygame.draw.line(screen, gray, (200, 410), (200, 790))
    pygame.draw.line(screen, gray, (400, 410), (400, 790))

    # Today
    date = small_font.render(days[0], True, black, white)
    date_rect = date.get_rect()
    date_rect.topleft = 10, 15

    high = small_font.render('high: ', True, black, white)
    high_rect = high.get_rect()
    high_temp = comfortaa.render(highs[0], True, black, white)
    htemp_rect = high_temp.get_rect()
    high_rect.topleft = (50, 100)
    htemp_rect.topleft = high_rect.topright

    low = small_font.render("low: ", True, black, white)
    low_rect = low.get_rect()
    low_rect.topleft = (400, 100)
    low_temp = comfortaa.render(lows[0], True, black, white)
    ltemp_rect = low_temp.get_rect()
    ltemp_rect.topleft = low_rect.topright


    condition = font.render(conditions[0], True, black, white)
    con_rect = condition.get_rect()
    con_rect.centerx = 300
    con_rect.top = 5
    # Make sure words don't overlap
    if con_rect.left < date_rect.right:
        con_rect.left = date_rect.right

    image = pygame.image.load(img_links[0])
    image.set_colorkey((255, 255, 255))
    img_rect = image.get_rect()
    img_rect.center = (300, 125)
    degrees = pygame.image.load("icons/%s.png" % unit)

    screen.blit(condition, con_rect)
    screen.blit(high, high_rect)
    screen.blit(degrees, htemp_rect.topright)
    screen.blit(degrees, ltemp_rect.topright)
    screen.blit(high_temp, htemp_rect)
    screen.blit(low, low_rect)
    screen.blit(low_temp, ltemp_rect)
    screen.blit(image, img_rect)
    screen.blit(date, date_rect)


    # Tomorrow
    date = small_font.render(days[1], True, black, white)
    date_rect = date.get_rect()
    date_rect.topleft = 10, 210

    high = small_font.render('high: ', True, black, white)
    high_rect = high.get_rect()
    high_temp = comfortaa.render(highs[1], True, black, white)
    htemp_rect = high_temp.get_rect()
    high_rect.topleft = (50, 300)
    htemp_rect.topleft = high_rect.topright

    low = small_font.render("low: ", True, black, white)
    low_rect = low.get_rect()
    low_rect.topleft = (400, 300)
    low_temp = comfortaa.render(lows[1], True, black, white)
    ltemp_rect = low_temp.get_rect()
    ltemp_rect.topleft = low_rect.topright


    condition = font.render(conditions[1], True, black, white)
    con_rect = condition.get_rect()
    con_rect.centerx = 300
    con_rect.top = 210
    if con_rect.left < date_rect.right:
        con_rect.left = date_rect.right

    image = pygame.image.load(img_links[1])
    image.set_colorkey((255, 255, 255))
    img_rect = image.get_rect()
    img_rect.center = (300, 325)

    screen.blit(condition, con_rect)
    screen.blit(high, high_rect)
    screen.blit(degrees, htemp_rect.topright)
    screen.blit(degrees, ltemp_rect.topright)
    screen.blit(high_temp, htemp_rect)
    screen.blit(low, low_rect)
    screen.blit(low_temp, ltemp_rect)
    screen.blit(image, img_rect)
    screen.blit(date, date_rect)



    # Day 3
    date = small_font.render(days[2], True, black, white)
    date_rect = date.get_rect()
    date_rect.centerx = 100
    date_rect.top = 410

    high = small_font.render('high: ', True, black, white)
    high_rect = high.get_rect()
    high_temp = comfortaa_small.render(highs[2], True, black, white)
    htemp_rect = high_temp.get_rect()
    high_rect.topright = (100, 630)
    htemp_rect.midleft = high_rect.midright

    low = small_font.render("low:  ", True, black, white)
    low_rect = low.get_rect()
    low_rect.topright = (100, 710)
    low_temp = comfortaa_small.render(lows[2], True, black, white)
    ltemp_rect = low_temp.get_rect()
    ltemp_rect.midleft = low_rect.midright


    condition = tiny_font.render(conditions[2], True, black, white)
    con_rect = condition.get_rect()
    con_rect.centerx = 100
    con_rect.top = 450

    image = pygame.image.load(img_links[2])
    image.set_colorkey((255, 255, 255))
    img_rect = image.get_rect()
    img_rect.center = (100, 540)

    screen.blit(condition, con_rect)
    screen.blit(high, high_rect)
    screen.blit(degrees, htemp_rect.topright)
    screen.blit(degrees, ltemp_rect.topright)
    screen.blit(high_temp, htemp_rect)
    screen.blit(low, low_rect)
    screen.blit(low_temp, ltemp_rect)
    screen.blit(image, img_rect)
    screen.blit(date, date_rect)



    # Day 4
    date = small_font.render(days[3], True, black, white)
    date_rect = date.get_rect()
    date_rect.centerx = 300
    date_rect.top = 410

    high = small_font.render('high: ', True, black, white)
    high_rect = high.get_rect()
    high_temp = comfortaa_small.render(highs[3], True, black, white)
    htemp_rect = high_temp.get_rect()
    high_rect.topright = (300, 630)
    htemp_rect.midleft = high_rect.midright

    low = small_font.render("low:  ", True, black, white)
    low_rect = low.get_rect()
    low_rect.topright = (300, 710)
    low_temp = comfortaa_small.render(lows[3], True, black, white)
    ltemp_rect = low_temp.get_rect()
    ltemp_rect.midleft = low_rect.midright


    condition = tiny_font.render(conditions[3], True, black, white)
    con_rect = condition.get_rect()
    con_rect.centerx = 300
    con_rect.top = 450

    image = pygame.image.load(img_links[3])
    image.set_colorkey((255, 255, 255))
    img_rect = image.get_rect()
    img_rect.center = (300, 540)

    screen.blit(condition, con_rect)
    screen.blit(high, high_rect)
    screen.blit(degrees, htemp_rect.topright)
    screen.blit(degrees, ltemp_rect.topright)
    screen.blit(high_temp, htemp_rect)
    screen.blit(low, low_rect)
    screen.blit(low_temp, ltemp_rect)
    screen.blit(image, img_rect)
    screen.blit(date, date_rect)

    # Day 5
    date = small_font.render(days[4], True, black, white)
    date_rect = date.get_rect()
    date_rect.centerx = 500
    date_rect.top = 410

    high = small_font.render('high: ', True, black, white)
    high_rect = high.get_rect()
    high_temp = comfortaa_small.render(highs[4], True, black, white)
    htemp_rect = high_temp.get_rect()
    high_rect.topright = (500, 630)
    htemp_rect.midleft = high_rect.midright

    low = small_font.render("low:  ", True, black, white)
    low_rect = low.get_rect()
    low_rect.topright = (500, 710)
    low_temp = comfortaa_small.render(lows[4], True, black, white)
    ltemp_rect = low_temp.get_rect()
    ltemp_rect.midleft = low_rect.midright


    condition = tiny_font.render(conditions[4], True, black, white)
    con_rect = condition.get_rect()
    con_rect.centerx = 500
    con_rect.top = 450

    image = pygame.image.load(img_links[4])
    image.set_colorkey((255, 255, 255))
    img_rect = image.get_rect()
    img_rect.center = (500, 540)

    screen.blit(condition, con_rect)
    screen.blit(high, high_rect)
    screen.blit(degrees, htemp_rect.topright)
    screen.blit(degrees, ltemp_rect.topright)
    screen.blit(high_temp, htemp_rect)
    screen.blit(low, low_rect)
    screen.blit(low_temp, ltemp_rect)
    screen.blit(image, img_rect)
    screen.blit(date, date_rect)

    update_time = "Last updated at " + datetime.now().strftime("%l:%M%P")
    last_update = tiny_font.render(update_time, True, gray, white)
    screen.blit(last_update, (5, 770))
   
    # AJR - try to output display instead of converting to raw.
    ### pygame.display.update()
    # AJR - and now save the image we've generated on the surface 'screen'
    pygame.image.save(screen, "output/test.png")
    #call(["/mnt/onboard/.python/eink_update.sh"])
    ###convert_to_raw(screen)
    ###call(["/mnt/onboard/.python/display_raw.sh"])
    
    
#try:
get_weather_data()
#except IndexError as error:
    #index_error(error)
The only irksome part I've not managed to work around is that the screensaver does not automatically update when the new copy of the image is sync'd. - I have to push the 'n' button on the nook to wake it, and then the new weather is displayed when it goes to sleep again (after 10 seconds).

Still - I'm happy :)


Sunday, 27 January 2013

Nook - e-reader / Pi Display - Attempt 1.

OK - This isn't strictly related to the Raspberry Pi as such - at least not yet, but it was because of running the weather station software on the Pi that I bought the Nook. - I want to be able to use the Nook as a remote display, pulling data from the weather station's Raspberry Pi, and displaying it remotely - e.g. at my office for example, or stuck on the wall. - I've seen similar things with the Kobo etc.

So, this is step 1. - So far, I've got the Nook, I've rooted it, go the market working, installed Kindle application and then got sidetracked into reading 'Life Of Pi'.

 - The Nook (Nook simple touch) seems easier to hold / read on than my kindle keyboard - It seems lighter, and easy to turn the pages with just a touch rather than using the side buttons as on the kindle, but that's maybe just personal preference.  I can't see me buying much from the B&N Nook store as I've really committed to Kindle previously, although by using Calibre with a decoder, I could install my purchased items onto the Nook. - I didn't want to be tied into one platform in the long term......  Anyway. - This post is just for notes on the install so far.

1. - Register the Nook with B&N having turned it on for the first time and setup connection to Wi-Fi etc.
2. - Download and follow instructions to create an SD card with NookManager on. - See this post - http://forum.xda-developers.com/showthread.php?t=2040351
3. - Reboot the Nook with the NookManager and BACKUP the Nook before proceeding.
4. - Transfer the backup from the SD card somewhere safe.
5. - Repeat steps 3 and 4 so we know we have a backup from which we can hopefully recover the Nook should the root fail but nothing guaranteed.
6. - Reboot with Nook Manager and 'root' the device.
7. - Reboot and verify it's all working OK.
8. - Reboot with Nook Manager - make a backup at this stage.
9. - Install NTGAppsAttack as per - http://forum.xda-developers.com/showthread.php?t=2086582
10. - Assuming this has worked OK we now have market etc installed.
11. - Reboot and install Kindle app from the market. - I've now got that installed and working fine with my Kindle books.

... to be continued.

(28/1/13) Much googling, and playing with the screensaver on the Nook shows that what may be possible is to create a directory on the Nook 'screensavers' directory e.g. /screensavers/weather.  Then, mount the Nook (in this case on the RPi), copy an image file into the 'screensavers/weather' directory on the Nook, then remove the nook. - The Nook will timeout and if you have it to display files from the 'weather' screensaver - Brilliant - it doesn't even need rooting to do that.

Then, I found this from the Kindle. - http://www.mpetroff.net/archives/2012/09/14/kindle-weather-display/
Currently trying to get the script running on the Pi to create the image which can then be transferred to the Nook.  Problem I've hit so far is that I can't 'rescan' the USB bus to remount the Nook periodically.  - When it's 'removed' from the Pi, the device files are removed. - I can't find a way to get udev to think it's been replugged ..... yet.


I can force 'removal' of the Nook on the USB with :-

echo 1 > /sys/bus/usb/devices/1-1.2/remove

But can't find a way to remount. - The device files are gone, and I don't know how to rescan the bus to force recognition as if it has been replugged.


I didn't originally want to do it this way because it involves a dedicated Pi for the purpose. - Originally I'd wanted a script running on the Nook which would pull the image from the Pi. - However, I'm a simple guy and I like simple solutions, so this is good enough if it works. - The upside is that I only need one power supply - the Nook charges OK from the Pi. albeit slowly. - I'll just have to get another Pi to use as my general purpose Pi if this project works :)

TBC....

OK - now looking for the essentials for the Kindle scripts. - namely pngcrush and rsvg_convert. - pngcrush was easy:-

apt-get install pngcrush

rsvg_convert took a little more finding, but I think is provided by librsvg2-bin

apt-get install librsvg2-bin

Run the scripts from the above link and put the resultant image into the screensaver directory on the Nook, et voila:-


OK - It's not entirely what I want, but as a proof of concept it pretty much works OK.  Now I just need to know how to rescan the USB to remount the Nook at intervals....

(Update 3/2/13.) - I could find no way of re-establishing / rescanning the USB devices once one had been removed. - I don't mean just re-mounting a filesystem here, I mean once the device files are removed, I could find no way of getting them recreated / re-establishing as if the device had been replugged. - Anyway, see next post, I'm now getting the file via ftp periodically which is a better solution anyway.