Public transport directions on a Nokia dumbphone

Posted on Jun 16, 2024

I probably should ditch my smartphone, but I kinda rely a lot on public transport routing apps.

Nokia still makes these little dumbphones, and nowadays they come with LTE connectivity…
Can I make a nugget like that give me directions?

Some time ago I impulse-bought a Nokia 110 4G (the 2019 edition):

The nugget

It can call, send SMS/MMS, play music (SD cards, mp3 support and a 3.5mm jack!). The screen is absolutely tiny: 128x160, 1.8" (~4.6 cm).

The main difference from old phones is that it supports LTE and VoLTE - ensuring it will still work after 3G gets shut down. Good!

While I bought it to try and limit my smartphone usage by simply leaving the smartphone at home when going out, I quickly noticed something:

I am completely lost without a public transport routing app.

But okay, I could make a simple Java app the public transport routes… right?

Well, turns out, the new dumbphones are much dumber than the actual “dumb” phones of the past - no J2ME!

Opera Mini to the rescue

Opera Mini 4 on the Nokia 110 4G 2019

One inkling of “smartness” in the nugget is the pre-installed Opera Mini web browser.

Opera Mini v4.4, to be exact. Quoting Wikipedia:

On 7 November 2007, Opera Mini 4 was released.

2007.

Unfortunately, I can’t really run jakdojade.pl in a 2007-era browser, so I started looking into alternatives.

Originally I wanted to reverse engineer jakdojade’s API, but it seems they did a non-zero amount of work to protect against that, so I went looking for an alternative that’s I can use without having to use my brain too much.

I found gdir.telae.net, which provides a text-based interface for Google Maps directions, including public transport. Perfect!

An excerpt from gdir.telae.net: Text-Based Google Directions, A minimalistic
directions service aimed at users of feature phones/dumb phones, terminal-based
browsers, low-bandwidth connections, screen readers etc. Best suited for public
transport directions. No JavaScript requirements.

However, having to type in the address of the office I work at, every day, on the T9 keyboard is a HUGE pain in the ass, so I wanted something more personalized.

couldn’t you just learn the routes you frequently use?

yeah probably, but I am already in too deep
let me have this

gdir wrapper

To make this less of a PITA, I decided to make what is basically a wrapper for gdir which would allow me to pick places I often want to look up from a list, and then redirect me to gdir with the correct parameters already set.

I implemented it in a pretty crude way to test the concept, each step is simply a separate Flask route with a form, which then saves values in the session object, and redirects to the next step.

Eventually, once all the values are gathered, gdir’s html is fetched using requests and returned to the browser:

import requests
from dataclasses import dataclass
from flask import Blueprint, redirect, render_template, session, url_for, request
from .auth import auth_required

maps = Blueprint("maps", __name__, url_prefix=("/maps"))


@maps.route("/")
@auth_required
def index():
    session["maps"] = {}

    return redirect(url_for("maps.from_"))


@dataclass
class Option:
    key: str
    name: str


def place_picker(key: str, next: str):
    option = request.args.get("option")
    state = session.get("maps", {})
    if not option:
        return render_template(
            "maps/from.html",
            title=key,
            options=[
                Option("Politechnika Wrocławska", "university"),
                Option("Wrocław Główny", "main station"),
                Option("SkyTower", "work"),
            ],
            state=state,
        )

    session["maps"] = state | {key: option}
    return redirect(url_for(next))


@maps.route("/from")
@auth_required
def from_():
    return place_picker("from", "maps.to")


@maps.route("/to")
@auth_required
def to():
    return place_picker("to", "maps.route")


@maps.route("/route", methods=["GET", "POST"])
def route():
    state = session["maps"]
    if request.method == "GET":
        return render_template("maps/route.html", state=session["maps"])

    country = request.form.get("country", "pl")

    url = f"https://gdir.telae.net/gdir/?country={country}&origin={state['from']}&destination={state['to']}&mode_of_travel=transit&walking_substeps=on"

    res = requests.get(url)
    return render_template("maps/route.html", directions=res.text)

Opera Mini supports cookies, so I put it behind password auth not to leak the addresses I frequent, and, lo and behold, our nugget can give me directions!

What’s next?

Well, I do like how the prototype came out. There’s a few issues… Opera doesn’t allow me to make the font or the text boxes smaller to fit more stuff onto the screen. Also I want to make more simple “applets” like this one…

So, maybe there’s a silly way to work around these limitations, and why not make it a framework while at it?

Well, actually I started some time ago… but that’s a topic for another blogpost or two.

Here’s a sneak peek though:

That’s still all in Opera Mini 4!