Headless Raspberry Pi – Circa 2019

With the advent of the Raspberry Pi 3 and Zero W, newer Pi-s come with wireless baked-in, which is (IMHO) a welcome addition to help make setting up a Pi without Ethernet much more straightforward.

In fact, given my employer’s aggressively antisocial wireless network 1, it has become the norm for me (and my students) to set up a fresh Raspbian install using either a mobile hotspot or by tethering their phones. In neither case is Ethernet a useful option2.

“Headless” installs are setups which do not require a keyboard, mouse and monitor – given the ubiquity of networking and the low-power of Pi-like devices, it makes sense to be able to use an SSH session to do all your setup and get your device running without the hassle of directly using I/O in front of it. Plus, all the reference sites you’re using are probably open in the hundred or so tabs on your main computer3.

Without further rambling, here is the current easiest way to set up a Raspbian Buster install to be headless, using MacOS as the host machine:

  • Write your image to a micro SD card. I am lazy and use Balena Etcher rather than DD, although at the time of writing, it’s a little broken when used with MacOS Catalina.
  • Remove your SD card and pop it back in. Do not boot your Pi with it at this stage. You need to make these changes for the first boot or Raspbian will ignore them.
  • It should appear mounted as “boot”. This is the only section of the new filesystem you can read and write on the host machine.
  • Open a terminal, because we’re all adults here and GUIs are only for circumventing the DD command using Balena Etcher.
  • Change directory to the boot partition on the card and create a file called “ssh”:
cd /Volumes/boot
touch ssh
  • edit a new file called “wpa_supplicant.conf”4
nano wpa_supplicant.conf

Put this content in it, replacing the placeholders in quotes (but keep the quotes) with bits relevant to you:

update_config=1
country=AU
ctrl_interface=/var/run/wpa_supplicant

network={
 scan_ssid=1
 ssid="Your Network Name"
 psk="Your Network Password"
}

That’s it – you can eject your card safely5, pop it in your Pi and power up.

Some additional notes, for fun and profit:

Q. How do I find the IP of my Pi after it boots, so that I can SSH in?
A. If you’re using an Android phone to hotspot – you can find a list of connected devices in the settings along with each of their IPs.
If you’re using a mobile hotspot or home router, log in to its web interface to view connected devices or get your phone to connect to the network use a network scanning tool such as Fing.
If you’re using an iPhone to hotspot – umm. I don’t know. Last I checked, they tell you how many devices are connected, but not any details about them (thanks Apple! I hate it!) and Fing doesn’t return details when it’s run on the hotspot itself. Arp has decidedly mixed results. There is apparently an app that can be downloaded to show you details of devices connected to your iPhone.

Q. Isn’t there other info I should include in my wpa_supplicant config? Like the country code?
A. Probably. It works fine for me without country code and I’m all for minimising the content that has to be customised in a config. Perhaps AU and UK wireless devices just interconnect fine, or perhaps some other WiFi voodoo has done away with the need for CCs. If you’re in the US, does it not work without a country code? I do know that in a previous version of Raspbian (Jessie, perhaps?), the Pi would refuse to connect if CC wasn’t set, so do with that what you will.
UPDATE IN 2020:
You absolutely do need to set the country code, especially if you’re using the 5GHz bands. Recent RPi OS builds seem to enforce this again. I’ve included the AU code in the example above (since I’m in AU), but you’ll need to set yours as per this list.

Q. I have to put my password in a config in plain text. What gives?
A. You don’t have to. There are ways to hash it and store it in the config.
Here’s the thing though – I’m betting this WiFi password is either a home network or a hotspot – and in either case, it’s a shared key in the literal sense of the term – lots of people know it, and it’s trivially easy to change it (at least on the router).
If you’re setting this up on a corporate network, my little config above won’t get you connected anyway. I’ve made it work in the past, but mobile devices I’ve connected to our corporate network have been… idiosyncratic. They lose Internet access or randomly change IP or need to be power cycled with a 15 minute delay every day. In short, I haven’t found Raspbian, or even many Linux distros that are cooperative with (what is probably a poorly configured) corporate WiFi, so in this day and age, it’s easier just to work around it rather than try to join it. :-/

Python: The value of “with”

I never learned to code with Python; my first forays into development were with batch files (I kid you not) and then Visual Basic (which taught me many things I spent years unlearning).

Python is, in many respects, a great language for learners (which I’m not going to discuss today).

There is however, a great deal of… less than intuitive show-off code that can be, nay is encouraged to be, written using the language. Solutions are deemed to be “Pythonic”, a term as nebulous as “elegant” and often resulting in code just as unreadable to the casual observer or Python learner.

In some respects, this is about reducing the number of lines written – something fraught with peril for someone new to coding.

But there is a seductive element to Pythonic solutions – they don’t require you to twist yourself up in lines of boilerplate just to overcome a (often commonly encountered) problem.

The “with” keyword is not especially unique to Python, but is actively encouraged, and with good reason. This is one case where fewer lines is definitely better. Continue Reading…

ECU Assignment Stapler

A working copy of the stapler can be found here.

Why does this thing exist?

When you submit assignments, you should submit them in PDF, not Word format.

There are a few reasons why, but the main two are as follows:

  1. You can be more sure that your tutor or lecturer will see the same thing you submitted
    Word documents can display differently depending on the version or device used.
    This is far less of an issue with PDF.
  2. You can’t accidentally munge your keyboard and change the final document.
    Probably not normally a consideration, but after 9 hours staring at papers on the significance of First Name Consonant Frequency in Childhood Misbehaviour*, you can easily make silly mistakes and be completely unaware that you just moved a crucial paragraph and are now submitting the antithesis of your intended argument.
(*Not a paper, but totally should be)

Continue Reading…

Python, oursql and executemany

I’ve never had cause to use executemany before, so perhaps it is unfortunate that my first encounter be in the context of oursql’s somewhat anaemic documentation.

I’ve just spent well over an hour trying to get a simple executemany statement to work – in retrospect, the solution was obvious. But the presence of an example (just one!) would have made things immediately clear.

To that end:

reportDB = oursql.connect(host = "localhost",
                          user = "LapsedPacifist",
                          passwd = "ContentsMayDiffer",
                          db = "AnythingLegalConsidered")

with reportDB as query:
  query.execute("BEGIN")
  query.execute("""
                INSERT INTO assets(clientid, assettype, model, deployed, name)
                VALUES(?, ?, ?, ?, ?)
                """, (clientID, ASSET_TYPE_UNKNOWN, model, deployed, name))

  assetID = query.lastrowid
  addresses = []

  for ip in ips:
    addresses.append([assetID, ip])

  query.executemany("""
                    INSERT INTO asset_ips(assetid, ipv4address)
                    VALUES (?, ?)
                    """, (addresses))

That’s it – just as oursql’s parameterisation is looking for a list of parameters, executemany is looking for a list of parameter lists – not just a list of strings.

Hence the for loop creating a list with the two parameters and then appending it to the executemany parameter list.

I’m sure there’s a better, more pythonic way of doing that – please let me know if I’m missing something obvious.

And behold, the grand total of what oursql’s documentation has to say about executemany:

Additionally, executemany() is lazy; if passed a generator or any other iterator which does produces values lazily, values will only be taken from the iterator immediately before they are sent to the database.

executemany(query, parambatch)
Execute the same query with different sets of parameters. This is more efficient than calling execute many times with the same query.

I don’t want it to sound like I’m down on oursql – I feel it’s the superior library for MySQL in Python, and it’s still quite young – but this particular gap in the documentation had me pulling out my hair.

I’ve read some complaints regarding scalability of executemany in oursql – fortunately my code won’t ever have to handle huge numbers of queries at one time.

Promiscuous Plink

Sometimes it’s necessary to do things the wrong way.

Plinkmiscuous is the world’s tiniest, laziest modification to the very excellent Plink, part of the PuTTY suite of software.

Plink is a command line only connection tool – it has much of the core functionality of PuTTY without all the fruit of a window and GUI. It’s often necessary to connect  through to *nix servers from Windows programmatically, and Plink is generally the tool for the job.

Unless you have a scenario where you can’t know the SSH fingerprint of the server to which you are connecting, or can’t store it (PuTTY puts things in the registry – I’m assuming a hangover from the bad old days of XP) for the account you need to run as.

In these circumstances, the otherwise fully automated Plink demands user interaction to confirm the fingerprint as OK.

Obviously, this is by design – the whole point of SSH is that you can be sure the server you’re connecting to is indeed the one you want before you start sending over authentication details.

But sometimes, security be damned, you need to do something dirty. Please don’t ever do it in a serious or production system.

To that end – the traditional way to “break” Plink and make it work regardless of a stored fingerprint is to pipe or otherwise send a “keypress” for confirmation.

That method sucks.

Plink is open source, so that means we can modify it when it fails to do what we want.

So that’s what I’ve done – it was a change of exactly 1 byte (and some Visual Studio fru fru).

You can find Plinkmiscuous on the software page. It’s based on the current version of Plink at the time of writing. I can update it in the future, but make no promises (and the code change is so simple, you should do it yourself).

And it’s probably worth rethinking whatever it is you’re planning to do with Plinkmiscuous so you don’t have to use it. :-P

Logitech Restarter

This will be of interest only to those who: have a Logitech keyboard with a fancy display, put their PC to sleep from time to time.

The Logitech Restarter is a little program designed to do nothing more than kill and restart Logitech’s Gaming Software.

Hardware manufacturers are notoriously bad at making stable, usable software (barring, one hopes, drivers). LGS isn’t as awful as some offerings in the past – but one area in which it does fall down is maintaining its connection to the keyboard’s display after waking from sleep.

This little application seeks to work around that problem by automating the user’s only recourse: killing the application and starting it again.

Code, binaries and more info at my software page.