Customising The E-ink Weather Display

With all the pieces in place to allow me to draw to the e-ink screen, I made some 8-bit RAW images and wrote values to the display. It worked, but it looked a bit crusty, not least because the Framebuffer.text method for putting text onto the screen is a fixed size, and a fixed font. Remember that I’m aiming for something like this, which uses a few different font sizes:

As with so many things, this has been solved before, with a piece of work that I think is absolute genius going by the catchy title of “font_to_py“. Basically, it’s a Python command line tool that inputs a font file (like a ttf) and some parameters, such as pixel size, and outputs a Python file containing all the data necessary to render the font as byte data. The files are very small too, with a 20 pixel font “compiling” down to 17kb.

Then you just import the Python files, which in my case were three different sizes of Calibri, and the functions to draw the font to a Framebuffer:

import calibri_36, calibri_15, calibri_12
from writer import Writer

And to draw to the display something like:

wri = Writer(display_buffer, calibri_36)
Writer.set_textpos(display_buffer, text_top, text_left)
wri.printstring(max_daily, True)

To print the value of the maximum daily temperature to the screen (via the Framebuffer). Somewhat strangely, the coordinates are passed in as (top, left) rather than (x, y). I also tweaked writer.py slightly to make sure it handled transparency (i.e. 0 pixels), by changing:

self.device.blit(fbc, s.text_col, s.text_row)

to

self.device.blit(fbc, s.text_col, s.text_row, 1 if invert else 0)

in the _printchar method.

The fonts still looked a little weedy, though, and rather than make a bold version of Calibri my own slightly hacky method was just to print the same characters four times over, offset by 1 pixel each time:

Writer.set_textpos(display_buffer, text_top, text_left)
wri.printstring(max_daily, True)
Writer.set_textpos(display_buffer, text_top, text_left - 1)
wri.printstring(max_daily, True)
Writer.set_textpos(display_buffer, text_top + 1, text_left)
wri.printstring(max_daily, True)
Writer.set_textpos(display_buffer, text_top + 1, text_left - 1)
wri.printstring(max_daily, True)

The results were good enough.

For degree symbols I used Framebuffer.ellipse, and to calculate the position to draw the symbol in writer.py even provides a very useful “how wide is this piece of text?” function:

text_width = get_string_display_width(wri, max_daily)
display_buffer.ellipse(text_left + text_width + 4, text_top + 5, 4, 4, 0)
display_buffer.ellipse(text_left + text_width + 4, text_top + 5, 3, 3, 0)
display_buffer.ellipse(text_left + text_width + 4, text_top + 5, 2, 2, 0)

Note that the ellipse (circle) is also drawn three times to create a faux bold effect.

The last part was some trigonometry as I wanted to display wind direction as an arrow in a circle.

Putting it all together resulted in something usable, albeit with some pixel tweaking required to sharpen some of the smaller images:

An epaper display showing temperature, weather summary, wind direction and rainfall duration

The last thing was to schedule it to update every hour. I experimented with lightsleep and deepsleep, which are supposedly low power modes, but the Pico just never seemed to wake up (and from Googling that appears to be a known issue), so I just took to a sleep function:

HOURS_SLEEP = 1
sleep_time = 60 * 60 * HOURS_SLEEP

Having made something functional, I now had a list of things I wanted to improve:

  1. The size. It’s a little bit too small. I decided to order a 2.9inch e-paper display, and this time get one with the right HAT
  2. The four hour summary is useful, but the weather at 7am is irrelevant once that time of day is passed. I wanted to change it to a rolling twenty-hour period
  3. What happens if I hit an error? I might think the weather’s the same every day and not notice the program has crashed. I needed to show the date/time of last update, and the “feels like” temperature is probably the least useful metric to replace it with
  4. The sleep function updated after an hour, but every update took maybe twenty seconds. If I was going to show update time, I wanted it to be on the hour, not to drift by a couple of minutes per day

I placed an order for another Pico (W, with headers, of course) and the larger e-ink display and waited.

Show Me The Weather

After connecting the e-ink display to the Pico and managing to get it to display in landscape mode I felt I’d solved the unknowns in making this e-ink weather display. Now it was time to decide what I was going to show, and how I was going to show it.

One Python example I’d found used a weather API called OpenWeather, so I went and signed up. Yet no matter what I seemed to do in terms of requesting API keys, and even waiting a day for activation, I was never able to make a valid request. In the meantime, with a little more Googling I found Meteo’s API. It turned out to be very easy to work with and had everything I’d need.

I chose some data fields I wanted to display and opened Photoshop to start a basic layout.

Design for an e-ink weather display showing maximum and minimum daily temperature, overall weather, wind gusts, and a summary for every 4 hours

I wanted minimum and maximum temperatures during the day, a nice summary icon, average wind speed, and then a bit more info about how it would feel which is where the 9 degrees (“feels like” temperature), 20mph (wind gusts), and 2hrs (duration of rainfall during the day) came from. Below that is a little summary of what the weather looks like at four hour intervals..

The API call is just a request to a URL, such as this:

https://api.open-meteo.com/v1/forecast?latitude=XXXXX&longitude=XXXXX&hourly=temperature_2m,windspeed_10m,winddirection_10m,windgusts_10m,weathercode&daily=temperature_2m_min,temperature_2m_max,sunrise,sunset,windspeed_10m_max,windgusts_10m_max,winddirection_10m_dominant,precipitation_hours,apparent_temperature_max,weathercode&timezone=GMT&windspeed_unit=mph

You can request more fields in either the hourly or daily summary, and the documentation was pretty clear too.

The return is JSON and easily parsed with Micropython. I wrote a small module to do it all:

import network, rp2, time
import urequests
import json
import sys
from io import BytesIO

LATITUDE = 'XXXXX'
LONGITUDE = 'XXXXX'

BASE_URL = 'https://api.open-meteo.com/v1/forecast?' 
URL = BASE_URL + 'latitude=' + LATITUDE + '&longitude=' + LONGITUDE + '&hourly=temperature_2m,weathercode&daily=temperature_2m_min,temperature_2m_max,sunrise,sunset,windspeed_10m_max,windgusts_10m_max,winddirection_10m_dominant,precipitation_hours,weathercode&timezone=GMT&windspeed_unit=mph'

# API documentation at https://open-meteo.com/en/docs
class Meteo:
    def __init__(self):
        self.json = None
        return
    
    def get_data(self):
        # Make GET request
        response = urequests.get(URL)
        if response.status_code != 200:
            print("Error")
            print(response.status_code)
            print(response.content);
            response.close();
            raise Exception("Error getting weather data " + response.status_code)
        else:
            self.json = response.json();
            response.close();
            return self.json;

I’d call it from a function, just so it was easier to test:

def getWeatherData():
    weather = meteo.Meteo();
    weather.get_data();
    return weather;

And accessing the data is just like accessing any Python object e.g. to get the maximum daily temperature:

max_daily = str(round(weather.json["daily"]["temperature_2m_max"][0]))

So far so simple, and I was quickly on to drawing all of this to the display, which is the subject of the next post.

Micropython E-ink Display Rotation

By default, sending pixels from a Raspberry Pico to a Waveshare e-ink display will result in a portrait image. In the case of the 2.13inch display I started with, this means a screen of 122 pixels wide by 250 pixels high.

But what if you want to display in portrait mode? As someone who’s used to the simple world of CSS it was actually fun to get back into the world of bits and pixels again.

Just like the ZX Spectrum, where I started programming, the display is stored as a list of bytes where each byte is eight consecutive pixels, either set to 1 to display a dark pixel or 0 for white (or clear).

In Micropython, this is stored as a byte array. So the code that sets up the display looks like this:

self.buffer_black = bytearray(self.height * self.width // 8)

Thankfully, there’s a helper module in the shape of Framebuffer which makes changing the value of these pixels much easier. It contains methods to write text, lines, rectangles and circles and, most usefully, to draw images at arbitrary coordinates using the blit command.

Not only does blit make it easier to draw, say, a 50×50 image onto the 122×250 display, but it also makes it much easier to draw an 8-bit image onto the 1-bit display. You start by setting a Framebuffer object with its data source as the byte array, such as:

self.imageblack = framebuf.FrameBuffer(self.buffer_black, self.width, self.height, framebuf.MONO_HLSB)

Where the first argument is the byte array, with and height are self explanatory, and framebuf.MONO_HLSB means that this framebuffer is a mono (1-bit) image, with horizontal bits stored as a byte.

To draw an image on top, assuming you have the pixel data in a variable called image_buffer, you can do something like:

self.imageblack.blit(framebuf.FrameBuffer(image_buffer, width, height, framebuf.GS8), x, y, key)

Where width and height are the width and height of the image, framebuf.GS8 signifies an 8-bit grayscale image, x and y are the coordinates to draw to, and key tells the blit method which pixels in the image it should treat as transparent. This allows you to draw just the black pixels onto the screen without the “white” pixels (or 0 bits) overwriting anything that’s already on the screen. Because the frame buffer takes the image_buffer bytearray as a parameter but changes the pixels in it by reference, any changes to self.imageblack (which is a Framebuffer object) are applied to the bytearay in self.buffer_black – which represents the actual pixel data.

So far so simple as far as drawing an image to the screen goes, assuming you’re still working in portrait mode. I made myself a helper function to load raw files from the on-board memory:

def drawImage(display_buffer, name, x, y, width, height, background=0xFF):
    image_data = get_image_data(name)
    if image_data:
        display_buffer.blit(image_data, x, y, background)
    else:
        image_buffer = bytearray(width * height)
        filename = 'pic/' + name + '.raw'
        with open (filename, "rb") as file:
            position = 0
            while position < (width * height):
                current_byte = file.read(1)
                # if eof
                if len(current_byte) == 0:
                    break
                # copy to buffer
                image_buffer[position] = ord(current_byte)
                position += 1
        file.close()
        display_buffer.blit(framebuf.FrameBuffer(image_buffer, width, height, framebuf.GS8), x, y, background)

Drawing a landscape image instead of portrait should be as simple as:

  1. Set up a Framebuffer with a width equal to the e-ink display height, and a width equal to the e-ink display width
  2. Draw to the Framebuffer
  3. Transpose columns of pixels into rows in a new bytearray
  4. Send to the e-ink display

It seemed like exactly the sort of thing that someone would already have tackled, and so it proved. So with some Googling and adjustment of width/height variables to suit the display I was working with I came to this:

def rotateDisplay(display):
    epaper_display = bytearray(epd.height * epd.width // 8)
    x=0; y=-1; n=0; R=0
    for i in range(0, epd.width//8):
        for j in range(0, epd.height):
            R = (n-x)+(n-y)*((epd.width//8)-1)
            pixel = display[n]
            epaper_display[R] = pixel
            n +=1
        x = n+i+1
        y = n-1
    epaper_buffer = framebuf.FrameBuffer(epaper_display, epd.width, epd.height, framebuf.MONO_HLSB)
    return epaper_display;

And I have to confess I didn’t worry too much about the details. Not until I ran it and the output was complete garbage.

It took a while to work out what I was doing wrong, but once I found the problem the solution made complete sense: I was inputting a Framebuffer stored as MONO_HLSB but the function above transposed the position of bytes, not individual bits. In other words, chunks of 8 pixels were being moved to the right place on the screen, but forming a column rather than a row. No wonder it looked bad.

The solution was simple: start with a Framebuffer of the type MONO_VLSB, where the bytes represent a column of 8 pixels, not a row. Then the transposition naturally mapped to MONO_HLSB.

I ended up with something like this:

display = bytearray(epd.height * epd.width // 8)
    display_buffer = Screen(display, epd.height, epd.width, framebuf.MONO_VLSB)
    display_buffer.fill(0xff)
    --- 
      Draw somethings here
    ---
    epaper_display = rotateDisplay(display)

where Screen was an extension of the Framebuffer class, necessary because the width and height parameters weren’t accessible in a native Framebuffer object. It just felt nicer to store them “in place” rather than pass another parameter around.

class Screen(framebuf.FrameBuffer):
    def __init__(self, display, width, height, encoding):
        self.display = display
        self.width = width
        self.height = height
        self.encoding = encoding
        return

The final wrinkles was that the e-ink display was 122 pixels “wide” (or now 122 pixels high, as I was trying to work in landscape mode), and therefore not a number that formed a whole number of bytes. Because of the way I was treating the screen, it meant my top left origin was at the coordinates (0, 6), which felt a bit nasty but was something I could live with. The alternative would have been to transpose the whole thing down 6 pixels using another Framebuffer, but frankly I couldn’t be bothered.

Getting Started With The Raspberry Pi Pico

Raspberry Pi Pico

The whole Raspberry Pi craze has passed me by before. Mainly because I have no competency whatsoever in electronics, and when it comes to using it just as a small computer I’ve had no need for one.

I don’t really know what drew me to the Raspberry Pi Pico, but it just looked like such a fun little thing to experiment with. I think it’s partly that it’s not just a small computer, because there’s no keyboard or mouse input, no monitor, and the only way to program it (that I know of so far) is through an attached computer. And with a very low power consumption it comes across more as a component to be used in something else than a mini-computer. Plus it can be programmed in Micropython, which is more-or-less a subset of the Python language with which I’m familiar (although no expert, but it looks pretty much the same as every other language to be honest).

But given my previously mentioned lack of electronics competency that alone wouldn’t be enough to lure me in, but the more I started to look at it the more it appeared that competency in electronics really wasn’t al that important. So many components, whether e-ink or LCD displays, cameras or motion sensors seem to be almost plug-and-play. Even I couldn’t mess that up.

Finally, I’d recently installed Hive Smart Radiators, and although the app is okay for controlling them, I’d been thinking how nice it would be to have small, unobtrusive controls for them in key rooms so it’s harder to forget to turn heating off in rooms that aren’t going to be used for most of the day, or turning them back on again if someone comes home early. I’d looked at cheap Android tablets that I could then build an app for, but for a kind of “at a glance” display I’d either have to have the screens always on, or look at something more expensive like OLED. Android, or cheap old model Apple tablets, just seemed like overkill, but also lacking in flexibility.

So a Pico looked fun and an avenue to explore, but where to start?

Starting Small: An E-ink Weather Display

The thing that piqued my interest was tiny e-ink displays, like the ones from Waveshare. I knew they’d be low power and ideal for infrequently updated displays, and although maybe not quite what I wanted for smart radiator controls (but then maybe they will be), I couldn’t get the idea of building something with one out of my head.

Waveshare 2.13 inch e-ink display

I decided I’d start with something smaller than a heating controller and settled on a weather display. My partner is always asking me if she’s going to need an umbrella that day, despite having a smartphone sitting in front of her, so I could kid myself it would be useful to install by the front door. Plus, some of the first search results I’d pulled up when looking at how hard it might be to program an e-ink were weather displays. (Albeit for a Raspberry Pi, not the Pico, and with a larger screen than I was planning. But it was some working code to give me direction.)

I had my project, and it looked achievable, so I just needed to buy some kit and start playing.

Buying The Right Equipment

In trying to buy just a Pico and an e-ink display my lack of knowledge almost set me back. Just in time, I realised that I needed a Pico W, which is a Pico with an onboard wifi controller, otherwise my weather display wouldn’t be able to retrieve weather information. (Although it’s possible to add an external controller, it’s much easier just to have it there at the start.)

Secondly, I needed a Pico with soldered headers to make the connection to the display much easier. In fact, as I don’t (yet) own a soldering iron, it was the only way to make the connection possible. The Pico with soldered headers costs a few pounds more, but easily worth the extra convenience. As shown in the image below, the headers are the “spikes” that make it easy to attach cables or other devices.

Raspberry Pi Pico with soldered headers

I knew then that if I bought an e-ink display with a HAT connection (which apparently stands for “hardware attached on top” and is easy to remember because it really does look lik you’re putting a hat on it) all I’d have to do is drop it on top.

The first confusion came when I tried to attach the two. The Pico had two rows of pins, but the display only had a single connection row. It had me stumped for a while, but then I worked out that I’d bought the wrong type of HAT. Apparently the e-ink display I’d bought hat a HAT configuration for a standard Raspberry Pi, not for a Pico.

This is what not to buy for a Pico:

Waveshare e-ink display with Raspberry Pi HAT connection

Whereas what I wanted would attach like this:

Waveshare e-ink display attached via HAT to Raspberry Pi PIco

It wasn’t a disaster, though as it also came with a cable connection. It just came down to working out how on earth to join the two things together.

A cable for a Waveshare e-ink display

Googling for the connections wasn’t too hard, as it’s all on the Waveshare site, but connecting them was made harder than it should be due to failing close-up eyesight which meant that matching microscopic pin numbers on the Pico to coloured cables from the display wasn’t as easy as it could have been.

Cable connections from a Raspberry Pi Pico to Waveshare e-ink display

Installing the Micropython firmware and connecting to the Pico with the Thonny IDE was straightforward and I was able to run an example piece of code to turn the onboard LED on and off within a few minutes. But I had a feeling that getting the e-ink display to show anything was going to be a little harder. For various reasons, so it proved, but that’s going to be covered in the next post.

An American Kindle Fire in London

I brought a Kindle Fire back to the UK, mainly because I wanted a cheap and small tablet, and preferably Android rather than iPad. I wasn’t sure what would and wouldn’t work back in London but since most of what I wanted in a tablet was a web browser I didn’t think it could go too badly wrong.

What Works

As expected, just using the tablet as a web browser and email device worked just fine. Other reviews cover the merits of the device in this respect compared to other tablets so I wont go into any details. But as far as I’m concerned it does what I wanted of it.

Particularly relevant to me was the ability to run Flash. Although Flash is much maligned (and often rightly) on tablets, playing videos from the BBC News website is virtually an essential in my opinion. Embedded clips seem to be screened out and only display as static images, which is probably the website itself auto-detecting that I’m on a mobile device, but longer clips and live news both play perfectly.

What doesn’t work (or needs some help)

Charging

The most basic of things: the Fire comes with a US plug and it didn’t appear to charge very quickly from the PC. – after about 8 hours it was at 76%. The mains-to-mini-USB cable from my phone seems to work, though.

Streaming Movies and Music from Amazon

Somewhat surprisingly, while I was still in the US the streaming videosxworked fine. As the Fire comes with an Amazon Prime trial I managed to get some content for free – despite having UK payment and address details. Unsurprisingly this stopped working beck in the UK, meaning the checks must be based on IP address. I know there are services by which I could send neteork traffic so that it appears that I’m still stateside, but given that it’s streaming content I’m not sure the performance will be good enough. And frankly, there are easier ways to get videos or music.

Installing Apps

More surprising was that the Amazon app store wouldn’t work for installing apps, even whilst in the US. I think the requirements here are both an American credit card and address. This was true even when I tried to download free apps – my details were still checked. Any attempt to install an app from the Google Market saw the Amazon App Store intercept the request, andcthen tell me the store isn’t available.

There are two workarounds. One is to root the device and you can install what you like. The other, which is what I’ve done, is to backup apps from my Android phone, copy them onto the PC, and then copy onto the Kindle and install. I had to install a file browser from a slightly dodgy source, but from there on in it was simple enough. A few apps didn’t work (Google docs), but for the most part this workaround does the trick.

Amongst the apps I had success with were: YouTube, BBC iPlayer, WordPress, eBay, Angry Birds. The iPlayer appeared to work well.

What do I think?

This is my first tablet. Not the first I’ve used, but the first I’ve owned. It’s pretty much fulfilling the role I had in mind for it i.e as an instant-on web browser that’s bigger than my phone. However, I don’t think I’d recommend that others import one and “make do” with it’s half-walled-garden Android system unless a) you’re a cheapskate like me and b) you’re happy to tinker at a tech level to get more apps on.

Just to add to the “how does it fare for what it’s supposed to do”, which is to stream movies and music, I’m not sure I’d want it for that anyway as a) the speakers are weirdly placed if you watch anything in landscape mode, and also aren’t that good, and b) it’s heavier than I thought it would be. Oh, and c) I just don’t think the screen is big enough for anything long-form such as a movie, especially not if you want to watch it with someone else.

But to add a more general opinion, I’m very happy with it for my unique cheapskate-android-freak-techie needs, but for anything more mainstream I don’t think it does anything quite well enough. If anyone else is thinking of buying one in the US and then bringing it over I would think as to whether you’d be better served just splashing out on a more expensive and full-featured tablet.

Create wallpaper on the K750i

It’s fairly easy to make your own wallpaper for the Sony Ericsson K750i:

  1. Find an image on your PC
  2. Resize it to 176 pixels wide by 220 pixels high
  3. Save it somewhere
  4. Copy it into the Phone Memory/Phone memory/Pictures folder on the phone
  5. On the phone itself, go into Menu -> Settings -> Display and select ‘Wallpaper’
  6. Select ‘Picture’
  7. Browse through the list of images to the one you’ve just copied over

You can also make the image 176 pixels by 176 pixels to just cover the centre of the screen.

My new Sony Ericsson K750i

I’ve just upgraded to the new Sony Ericsson K750i phone and am well pleased with it. It works well as a phone and is much more responsive and easier to use than my old Nokia 6600, but it’s all the extra features that make it really great. The camera takes pretty good pictures for a camera, let alone a phone, and the way it comes straight on when you open the back cover without having to unlock the phone makes it very useable. There’s also a pretty good LED for giving some light at night which gives pretty good results. I also found the bluetooth connection to both my PC and my Clie quite easy to set up and plugging the usb cable in just mounts the memory stick as a drive on the PC which makes copying files from one to the other very easy and fast.

After using the 6600 I found the interface much better and I can’t imagine I’ll go near another Symbian phone again in a hurry. On the K750i I press a button and it responds; there’s none of the delay the 6600 had. The text messaging is also much easier as you get a dropdown with predictive matches as you type, and can manually choose any letter you like at any time without having to go into a separate ‘spell’ mode.

It’s saved me having to buy a separate digital camera and mp3 player, and has an FM radio included too. Brilliant!!!

Sony Clie and Nokia 6600 infra red GPRS internet settings

Instructions for connecting the Sony Clie UX50 to the internet via GPRS through a Nokia 6600’s infra red port. I’m on the Orange phone network so some of the settings may be specific to this. I also assume your phone already works with internet/GPRS by itself and has a connection called ‘orangeinternet’ set up (which it is by default).

  1. Go to Preferences.
  2. Select ‘Connections’ and ‘New..’.
  3. Call it something like ‘IR Internet’.
  4. Set:
    • Connect to: Modem
    • Via: Infrared
    • Dialing: TouchTone
    • Volume: Low
  5. Click on ‘Details’ and set speed: 115,200, flow ctl: Automatic, Init string: leave empty.
  6. Click ‘OK’ then ‘OK’ from the ‘Edit Connection’ screen.
  7. Select ‘Network’ from within Preferences.
  8. Open up the top menu and select ‘New’.
  9. Call the service something memorable (e.g ‘Working IR Internet’).
  10. Some of the following settings are specific to the Orange phone network so you may have to play around:
    • Username: a
    • Password: a
    • Connection: select the IR connection you just made (‘IR Internet’)
    • Phone: *99#
  11. Click on ‘details’.
  12. Set:
    • Connection type: PPP
    • Idle timeout: Never
    • Query DNS: ticked
    • IP Address: tick automatic

Now the hard bit… Click on ‘Script’ and enter through the menus:

Send: AT&FO;&D2&EO [both capital “o”, not zeros]
Send CR:
Send: ATV1W1S95=47
Send CR:
Send: AT&K3
Send CR:
Send: AT+CGDCONT=1,”IP”,”orangeinternet”
Send CR:
Send: ATDT*99#
Send CR:
End:

Click on ‘OK’.

Now to try and connect the phone to the Clie. Go to ‘Modem’ option in the Nokia 6600’s menu (probably inside the ‘Connect’ folder if you haven’t moved it).
Click on the ‘Modem’ icon and select ‘Connect via infrared’. The phone should start looking for something to connect to.
Now go to the network setting you’ve just made in the Clie, point the infra red port at the phone’s IR port and click ‘Connect’.
Then hope for the best….

This obviously isn’t as good as bluetooth would be because a) you have to point the devices at each other and b) you have to navigate through a few menus just to enable the modem on the 6600, but it’s the best we seem to have for a while.

Sony Clie and Nokia 6600 bluetooth gprs internet access

I’ve been spending quite a lot of time trying to get internet access from my Sony Clie through a Nokia 6600 mobile phone’s bluetooth connection and have had some minor success but still not been able to get it to work completely. A major break through came with getting infra-red access (taking a step back seemed like the best way to start out) but Bluetooth/Nokia 6600/Sony Clie just don’t seem to like each other very much.

There are rumours about an upgrade to the 6600’s firmware which may improve things, but it doesn’t seem particularly easy to get hold of at the moment: either send your phone away for god knows how many weeks, or try and grab a dodgy copy and do it yourself invalidating the warranty. I think i’ll wait until there’s positive news on it actually fixing the problem first.

The stage I’ve now gotten to is:

  1. Can connect to the internet, e-mail and ssh fine via infra-red.
  2. The Nokia 6600 and Clie are paired via Bluetooth.
  3. Sending files back anf forth between the 6600 and the Clie works fine.
  4. Sending SMS messages from the Clie via Bluetooth works fine.
  5. Can make a connection to the internet via Bluetooth but unable to sustain it for any download. The strangest thing is that I can send e-mails.

A great source for the Palm dial-up script and settings for connecting to Orange can be found here:
Orange/Palm GPRS script

A Palm OS Nokia 6600 phone driver can be downloaded here: http://www.clieuk.co.uk/upload/Nokia6600.prc

There’s an interesting thread on the matter here: Clie/Nokia 6600 GPRS internet discussion.