Elsewhere I’ve written about moving from Raspberry Pi 4 and legacy 32-bit Bullseye (Pi OS) to Raspberry Pi 5 and 64-bit Bookworm (Pi OS). So I thought, having backed up my RPi4 and 5, I’d take the RPi4 and do a from-scratch installation of Bullseye on the latter.
Armed with my PC and RPi4 (Ethernet connection as usual for me), Balena Etcher on the PC and a handy SD (I typically use 32GB SDs), I selected the LITE version of Pi OS Bookworm 64-bit and flashed that onto the SD. I was asked by Balena Etcher before flashing started if I’d like to customise the install – so I called it RPi4 and put in user pi with my usual password. That’s about it.
On removing the flashed image from the PC, I put it into the RPi4 and applied power. Advanced IP Scanner (PC) told me the address of the board on my network, so using Mobaxterm on the PC, I selected a Mobatek SSH session for device 192.168.1.232 (that’s the address that dhcp gave it), remembering to select in Mobaxterm terminal setup, the 256 colour terminal option for later.
In the SSH session as user pi, I enabled root access – and while still user pi, I fixed the IP address (IPV4 configuration) in the RPi4 as I did here on RPi5. – NOT using the mouse – remember that. i.e.
# enter a password for root user sudo passwd root # change these 2 lines in /etc/ssh/sshd_config to allow root login via ssh sudo nano /etc/ssh/sshd_config PermitRootLogin yes PasswordAuthentication yes sudo nmtui
After setting the fixed IP address I wanted (192.168.1.19) and default gateway and DNS (my router at 192.168.1.1) and finally disabling IPV6, I hit OK and rebooted the RPi4 which no longer appeared at the original address, so I created a new Mobaxterm session at 192.168.1.19
I stuck with user pi at this point – as that’s what I’ve always used on the RPi4 and previous (RPi3, RPi2). I found a new script on a blog Ultimate Python Script – and selected Python 3.8 specifically as last time I installed Amazon AWS Polly (days ago) it seemed to want Python 3.8
wget -qO - https://raw.githubusercontent.com/tvdsluijs/sh-python-installer/main/python.sh | sudo bash -s 3.8.0
But no – it said “you are trying to install an older version than your current version – exiting this script” – ok, I’ve documented it now, so, in for a penny…
Next, for the RPi4, a variation of my RPi5 blog entry , remembering I’m still pi
## jq will be needed for Antonio's Docker stuff, mc is for the mcedit editor sudo apt install jq sudo apt install mc
No interaction above but plenty of waiting.
As before, I went into mc – options – appearance and selected julia256 theme – just because I hate the default theme – I don’t find it easy to read. I’ve explained elsewhere that I find mcedit to be way easier to use than nano which comes with the pi – and I’m starting to use mc for copying files, folders etc. It’s almost like being civilised. See this Midnight Commander reference.
As I’m using Bookworm I went for the revised rpi-clone (not BillW’s original github respository which is no longer supported)- for me an utterly essential tool which I’ve discussed in the RPi5 entry.
curl https://raw.githubusercontent.com/geerlingguy/rpi-clone/master/install | sudo bash
Seconds later – done. rpi-clone available but then I was going to have to remember the commands – so immediately I went to install my usual aliases in /etc/bash.bashrc – this time using sudo mcedit – so:
sudo mcedit /etc/bash.bashrc ##once in the editor I add this lot after commenting out the original PS1 section in the file ## ## # set a fancy prompt # original commented out along with the conditional code # PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' PS1="\[\033[38;5;39m\]\u\[$(tput sgr0)\]\[\033[38;5;15m\]@\[$(tput sgr0)\]\[\033[38;5;222m\]\h\[$(tput sgr0)\]\[\033[38;5;15m\]:\[$(tput sgr0)\]\[\033[38;5;83m\]\W\[$(tput sgr0)\]\[\033[38;5;15m\]:\[$(tput sgr0)\]\[\033[38;5;69m\]\A\[$(tput sgr0)\]\[\033[38;5;15m\][\[$(tput sgr0)\]\[\033[38;5;174m\]\$?\[$(tput sgr0)\]\[\033[38;5;15m\]]> \[$(tput sgr0)\]" BLACK='\033[0;30m' RED='\033[0;31m' GREEN='\033[0;32m' BROWN='\033[0;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' LIGHTGRAY='\033[0;37m' DARKGRAY='\033[1;30m' LIGHTRED='\033[1;31m' LIGHTGREEN='\033[1;32m' YELLOW='\033[1;33m' LIGHTBLUE='\033[1;34m' LIGHTPURPLE='\033[1;35m' LIGHTCYAN='\033[1;36m' WHITE='\033[1;37m' NC='\033[0m' alias space='df -h|grep -v udev|grep -v tmpfs|grep -v run' alias stop='sudo shutdown now' alias boot='sudo reboot' alias partitions='cat /proc/partitions' alias parts='sudo fdisk -l /dev/mmc* /dev/sd*' alias cloned="sudo printf 'Last cloned on ' && sudo tune2fs -l /dev/sda2|grep -i write|grep -iv life|cut -d: -f 2-|xargs" #alias cls='python /home/pi/cls.py' # rpi-clone aliases to make life easy #optional hostnames in clone functions below # clone assumes running the RPi on SD and clones to an already used SSD clone () { printf "${LIGHTBLUE}Creating a quick clone on SDA${NC}\n" touch /home/pi/clone-date bashCmd=(sudo rpi-clone -U sda) if [ -n "$1" ]; then bashCmd+=(-s "$1") fi "${bashCmd[@]}" } # Same as clone but assumes a brand new clean (or used for other purposes) SSD - it means clean clone cclone () { printf "${LIGHTRED}Creating a full clone on SDA${NC}\n" touch /home/pi/clone-date bashCmd=(sudo rpi-clone -f -U sda) if [ -n "$1" ]; then bashCmd+=(-s "$1") fi "${bashCmd[@]}" } # Same as clone but assuming a ssecond SSD in SDB - I used to have an adaptor for 2 USB-mounted SSDs on the RPi cloneb () { printf "${LIGHTBLUE}Creating a quick clone on SDB${NC}\n" touch /home/pi/clone-date bashCmd=(sudo rpi-clone -U sdb) if [ -n "$1" ]; then bashCmd+=(-s "$1") fi "${bashCmd[@]}" } # clonem is used assuming you are running on SSD and will create a clone on SD clonem () { printf "${LIGHTBLUE}Creating a quick clone on MMCBLK0${NC}\n" touch /home/pi/clone-date bashCmd=(sudo rpi-clone -U mmcblk0) if [ -n "$1" ]; then bashCmd+=(-s "$1") fi "${bashCmd[@]}" } ccloneb () { printf "${LIGHTRED}Creating a full clone on SDB${NC}\n" touch /home/pi/clone-date bashCmd=(sudo rpi-clone -f -U sdb) if [ -n "$1" ]; then bashCmd+=(-s "$1") fi "${bashCmd[@]}" } cclonem () { printf "${LIGHTRED}Creating a full clone on MMCBLK0${NC}\n" touch /home/pi/clone-date bashCmd=(sudo rpi-clone -f -U mmcblk0) if [ -n "$1" ]; then bashCmd+=(-s "$1") fi "${bashCmd[@]}" } cclonec () { printf "${LIGHTRED}Creating a full clone on SDC${NC}\n" touch /home/pi/clone-date bashCmd=(sudo rpi-clone -f -U sdc) if [ -n "$1" ]; then bashCmd+=(-s "$1") fi "${bashCmd[@]}" } clonec () { printf "${LIGHTBLUE}Creating a quick clone on SDC${NC}\n" touch /home/pi/clone-date bashCmd=(sudo rpi-clone -U sdc) if [ -n "$1" ]; then bashCmd+=(-s "$1") fi "${bashCmd[@]}" } update () { printf "${LIGHTGREEN}Getting upgrades...${NC}" sudo apt update sudo apt upgrade } created () { printf "${LIGHTGREEN}This setup was created at ${YELLOW}" bashCmd=(date -r /home/pi/clone-date +"%H:%M on %-d/%m/%Y") "${bashCmd[@]}" printf "${NC}" }
After pasting that into the end of the existing /etc/bash.bashrc file, I hit F2 to save – then F10 to exit the editor – it doesn’t get any easier. I’m sure someone will tell me the command to reset bash.bashrc without a reboot but I find it as easy to use sudo reboot (after this it’ll just be boot thanks to my aliases).
Time for a update and upgrade – bang goes another 141MB of storage.
sudo apt update && sudo apt upgrade
And now I made a clone to the used SSD I just happen to have plugged into one of the RPi4 USB3 connectors. Always great being able to know that if the next step messes up,, I can get back to this place in no time at all (there’s a reason I’m installing in the order you see here – editor – rpi-clone, latest updates all in place before trying anything major). If I’d only had a brand new SSD handy I’d have gone for the much slower of my alias commands for rpi-clone – cclone for clean clone. Instead, I used clone
clone
As the SSD had none of this installation – it was previously used for my full RPI backup using the previous operating system – hence….. total time for the clone above… around 6 minutes. The next clone will take much less than that – and in both cases – no interaction – a great time for a bathroom break or coffee.
Now I was ready to install my cls file (cls.py but the .py suffix is not needed here) in /usr/local/bin folder – I also need to give all users full permissions for that file including execute permission…
Here’s the content of the file /usr/local/bin/cls which I put into that /usr/local/bin folder with mcedit… and then give everyone full permissions… to the file…
#!/usr/bin/python3 import time import os import psutil import platform import socket from datetime import datetime import subprocess byteunits = ('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB') def filesizeformat(value): exponent = int(log(value, 1024)) return "%.1f %s" % (float(value) / pow(1024, exponent), byteunits[exponent]) def bytes2human(n): """ >>> bytes2human(10000) '9K' >>> bytes2human(100001221) '95M' """ symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y') prefix = {} for i, s in enumerate(symbols): prefix[s] = 1 << (i + 1) * 10 for s in reversed(symbols): if n >= prefix[s]: value = int(float(n) / prefix[s]) return '%s%s' % (value, s) return "%sB" % n def cpu_usage(): # load average, uptime av1, av2, av3 = os.getloadavg() return "%.1f %.1f %.1f" \ % (av1, av2, av3) def cpu_temperature(): tempC = ((int(open('/sys/class/thermal/thermal_zone0/temp').read()) / 1000)) return "%sc" \ % (str(round(tempC,1))) def disk_usage(dir): usage = psutil.disk_usage(dir) return " %s/%s" \ % (bytes2human(usage.total-usage.used), bytes2human(usage.total)) def network(iface): stat = psutil.net_io_counters(pernic=True)[iface] return "%s: Tx%s, Rx%s" % \ (iface, bytes2human(stat.bytes_sent), bytes2human(stat.bytes_recv)) bold = '\033[1m' normal = '\033[0m' red='\033[91m' green='\033[92m' blue='\033[94m' default = '\033[39m' magenta = '\033[38;5;200m' lime = '\033[38;5;156m' cyan = '\033[38;5;39m' yellow = '\033[38;5;229m' uptime = datetime.now() - datetime.fromtimestamp(psutil.boot_time()) os.system('cls' if os.name == 'nt' else 'clear') host_name = socket.gethostname() #host_ip = socket.gethostbyname(host_name+".local") def get_ip_address(): ip_address = ''; s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("8.8.8.8",80)) ip_address = s.getsockname()[0] s.close() return ip_address host_ip = get_ip_address() def ram_usage(): mem = psutil.virtual_memory() s=str(round((mem.available/1000000000.0),2)) + "G/" + str(round((mem.total/1000000000),2)) + "G" return s sb=subprocess.Popen(['vcgencmd', 'get_throttled'],stdout=subprocess.PIPE) cmd_out=sb.communicate() power_value=cmd_out[0].decode().split("=")[1] print (blue + "____________________________________________________________________________\n" + normal) print (" Platform: " + cyan + "%s %s" % (platform.system(),platform.release()) + normal + "\tStart: " + yellow + str(datetime.now().strftime('%a %b %d at %H:%M:%S')) + normal) print (" IP Address: " + red + host_ip + normal + "\t\tUptime: " + green + "%s" % str(uptime).split('.')[0] + normal) print (" CPU Temperature: " + red + cpu_temperature() + normal + "\t\t\tHostname: " + red + host_name + normal) print (" Memory Free: " + magenta + ram_usage() + normal + "\t\tDisk Free: " + lime + disk_usage('/') + normal) bum=psutil.cpu_freq(0) print (" Current CPU speed: " + red + "%d" % int(bum.current) + "Mhz" + normal + "\t\tmin: " + red + "%d" % int(bum.min) + "Mhz" + normal + " max: " + red + "%d" % int(bum.max) + "Mhz" + normal) print (" Power Status: " + power_value) print (blue + "____________________________________________________________________________\n" + normal)
Now I had a working basic RPi4 setup with Bookworm Pi OS, rpi-clone, the editor and my cls command. Next – start work on Docker and hence all my usual stuff like Node-Red – just like my RPI5, using Antonio’s instructions on Github. As yet, on the RPi5 we have my full home control setup but I can’t progress audio (aws Polly) until my audio dongle arrives – we DO have AWS working entirely in a container on the RPi5 but as yet not neen able to rest MPG123 until I have the dongle – so I’m backtracking to the RPi4 here to narrow down any issues – Bookworm or change of board…
To clarify: mpg123 needed installing – as root user I just used apt install mpg123 – meanwhile amixer as used to control volume – is already installed by default in Bookworm just as before – no changes – it’s a weird setup…
At the command line:
amixer cset numid=1 -- 80% amixer cset numid=1 -- 90% amixer cset numid=1 -- 100%
In the above, I get VERY quiet at 80%, listenable at 90%, maximum at 100%
It seems that from a value range of +400 to -10239, 100% produces 400, 90% produces -664, 80% produces -1728 etc. Weird. Then I decided to re-think my volume control in which I input from 1 to 100…. below 75 was at this point silent on my speaker.
See the updated Polly article for that – I improved the audio level control and made the whole lot work with Node-Red installed in a Docker Container – all explained between the updated Polly blog entry and the RPi5 – Docker blog entry – any missing details – check Antonio Fragola’s DockerIOT Git repository.
Enjoy.