Further research led me to https://stackoverflow.com/a/70304099 which solved my problem.
I hope a full description may help others.
How to use infra-red to shut down Pi
It is quite easy to enable an infra-red remote control to issue commands to a Raspberry Pi, even headless. There follows a stepwise procedure to equip a Pi to be shut down with a remote control. The system can easily be extended to execute other commands.
The process below should also work on other Linux machines, if an infra-red receiver is present.
Skill level required
Basic familiarity with a Pi:
• setting-up the SD card, • editting files, with your preferred editor, • access to root, via `sudo` • attaching a device to the GPIO.
There is plenty of help online.
Acknowledgements
Significant portions come from:
Hardware and ir-keytable:
https://blog.gordonturner.com/2020/05/31/raspberry-pi-ir-receiver/
Python and evdev:
https://stackoverflow.com/a/70304099
https://pypi.org/project/evdev/
Requirements
The following hardware is required:
• A Raspberry Pi with an SD card, Raspberry Pi OS and wifi or an ethernet connection. The network is only required to install software. Other operating systems probably work, but Linux is assumed here. • A TSOP38238 infra-red receiver. These are very cheap to buy in bulk, but small orders often attract a hefty handling and package charge. • An infra-red remote control. You may be able to find a working device from a discarded television or similar. I used a Philips handset from a broken DVD player. There are many for sale through online suppliers – you may want a cheap, simple device, or something more complex if you envisage programming lots of commands. • Breadboard and jumper wires, for prototyping.
Hardware assembly
Orientate the IR receiver with the legs pointing downwards and the bulge on the head facing forwards. The connectors are:
• Left-most: Signal, connect to pin 8 of the Pi, named GPIO14. • Centre: Ground, connect to one of the ground pins of the Pi, e.g. pin 6. • Right-most: Power, connect to pin 1 of the Pi, 3.3 volts.

Take note that there are different conventions for identifying the GPIO pins. The pin numbers above are physical numbers, obtained by counting the actual pins – pin 1 is the bottom left in the diagram, with pin 2 above it. There is also a naming scheme, which is known as GPIO numbering or Broadcom numbering.
Operating system configuration
Starting with a bootable Raspberry Pi OS, add this line at the end of the file /boot/config.txt :
dtoverlay=gpio-ir,gpio_pin=14
If you want to use a different pin for the receiver signal, you need to adjust the value of gpio_pin in this statement, using the Broadcom number. There is plenty of information online, which may vary according to your Pi model.
Reboot the Pi after changing boot parameters.
Initial testing
This section tests the hardware installation, but is not a required part of the final solution.
Install ir-keytable with
sudo apt install -y ir-keytable
and test it with:
sudo ir-keytable
which should display output similar to:
Found /sys/class/rc/rc1/ with: Name: vc4-hdmi Driver: cec Default keymap: rc-cec Input device: /dev/input/event1 Supported kernel protocols: cec Enabled kernel protocols: cec bus: 30, vendor/product: 0000:0000, version: 0x0001 Repeat delay = 0 ms, repeat period = 125 ms Found /sys/class/rc/rc0/ with: Name: gpio_ir_recv Driver: gpio_ir_recv Default keymap: rc-rc6-mce Input device: /dev/input/event0 LIRC device: /dev/lirc0 Attached BPF protocols: Operation not permitted Supported kernel protocols: lirc rc-5 rc-5-sz jvc sony nec sanyo mce_kbd rc-6 sharp xmp imon Enabled kernel protocols: lirc rc-6 bus: 25, vendor/product: 0001:0001, version: 0x0100 Repeat delay = 500 ms, repeat period = 125 ms
In this case, we can ignore the first entry (/sys/class/rc/rc1/) and focus on the second (/sys/class/rc/rc0/) because it has the name gpio_ir_recv. We will use the class (rc0) and the device (/dev/input/event0) in later steps.
Test the remote with:
sudo ir-keytable -t -s rc0
(or a different value of the class if identified).
Then press buttons on the remote. Each key-press should produce lines like:
211.610167: event type EV_MSC(0x04): scancode = 0x4601 211.610167: event type EV_SYN(0x00).
The lines may be repeated, if you held the button down. Don’t worry about that. Also, we don’t need the data, just the fact that we got some.
If the remote button presses are received, you have a working IR system. The next stage is to make it do something useful. If there is no response to the remote, check all the work above. Don’t forget to check the battery in the remote.
Required Software
There are plenty of guides online, but many are old and out-of-date. You do not need LIRC or udev. A short Python script (shown below) is all that is necessary. It is assumed you already have Python3 available. Some of the commands need adjusting if not, but I not a Python user and cannot really help.
Install pip (a standard package-management system for Python) and use it to install evdev (which provides bindings to the generic input event interface in Linux). It is important to install evdev into a system directory, to be accessible to root.
sudo apt install -y python3-pip sudo pip install -y evdev --target /usr/lib/python3/dist-packages
or
sudo pip3 install evdev --target /usr/lib/python3/dist-packages
You may need to adjust the path if you have a different version of Python.
Create a Python script called say, ir-test.py containing these lines.
from evdev import InputDevice dev = InputDevice('/dev/input/event0') for event in dev.read_loop(): print(event)
Check, and if necessary correct, the device pathname according to what was obtained from ir-keytable. If you bypassed the ir-keytable stage, look at what devices are in /dev/input/ and test each.
Run this script and press buttons on the remote.
python ir-test.py
It should print lines like:
event at 1691579255.159091, code 04, type 04, val 17921 event at 1691579255.159091, code 00, type 00, val 00
The first number is the time, the last (‘val’ or ‘value’) is what we want. If the numbers are zero (as in the second line), it simply indicates the button was held down – these lines can be ignored.
Make a note of the ‘val’ value that corresponds to the button you want to action.
You now have enough information for the final stage. You may want to keep the above Python script, for possible trouble-shooting, or in case you ever want to expand your system.
I suggest you create another Python script, called maybe ir-read.py. It contains:
# Production program to process IR input import subprocess from evdev import InputDevice dev = InputDevice('/dev/input/event0') for event in dev.read_loop(): print(event.value) # Debug only if event.value == 18119: subprocess.run(["/usr/sbin/shutdown", "now"])
Again, adjust the device pathname for your system. The print line is only to show what is happening, you can remove it after testing. Adjust the number in the if line to the value of the button you want. The ‘now’ in the last line says to shut down immediately, you can substitute a number if you want a delay – it is a number of minutes to wait.
Test ir-read.py and press buttons on the remote.
python ir-read.py
Don’t expect the shutdown command to work here; as it requires root privilege. An error message will show the script got to this point.
You can add more if blocks, following the same pattern, if you want to listen for, and react to, more remote buttons.
Finally, add your script to root’s crontab, so it runs when the Pi starts.
sudo crontab -e
Add this line at the end of the file:
@reboot /usr/bin/python /home/pi/ir-read.py
Make sure the paths and names are correct for your system.
Trouble-shooting
It often happens that the script works as user ‘pi’ (or whatever you are logged on as), but not as root. This is because root has a different environment. For this reason, full paths are included everywhere.
You can debug the script by changing the crontab line to:
@reboot /usr/bin/python /home/pi/ir-read.py >>/home/pi/irdebug.log
and can add more prints in the script to see what is happening. Remember to reboot each time crontab is changed. Alternately try the Python script, as root, from the command line:
sudo /usr/bin/python /home/pi/ir-read.py
Further thoughts
It is difficult to press a remote button briefly enough for a single event to be received. For shut down, this does not matter, but for other commands, it may be a problem.
There are options on the ir-keytable command to adjust the delay and period of repeats, see the man page for details. It should also be possible to extend the Python code to ignore duplicate events.