Changes for new version of Fenrir and extended speech customization options.
This commit is contained in:
1 parent
d41a531b9d
commit
c7f21c9234
10 files changed
+149
-59
No files matched your search
+16
-3
@@ -70,9 +70,11 @@ Rebuild after pulling so your custom image inherits any upstream fixes (new pack
|
||||
```bash
|
||||
xzcat stormux-rpi4-5-aarch64-*.img.xz | sudo dd of=/dev/sdX bs=4M status=progress conv=fsync
|
||||
```
|
||||
3. Insert the card into your Raspberry Pi and power it on. You should hear Fenrir start speaking once the user session loads.
|
||||
4. Log in using the default credentials (username `stormux`, password `stormux`). Root uses `root`/`root` until you change it.
|
||||
5. Run `sudo configure-stormux` (or follow the automatic prompt) to finish the guided setup: configure networking via `nmtui`, update the clock, optionally resize the SD card with `growpartfs`, and toggle Fenrir’s layout.
|
||||
3. Insert the card into your Raspberry Pi and power it on. The first boot automatically logs in on tty1 and starts guided setup.
|
||||
4. Setup calibrates volume, offers the default speech-engine selector, and speaks the laptop-layout question using the selected engine. Enter or N selects desktop layout; Y selects laptop layout. Fenrir stays stopped until these choices are complete.
|
||||
5. Setup updates `[keyboard] layout` in `/etc/fenrirscreenreader/settings/settings.toml`, preserving comments, and validates the edited settings with `fenrir --check-config` before replacing the original. It then starts Fenrir and presents the welcome prompt.
|
||||
6. Continue with the Pi-specific setup: display and I38 startup choices, optional SD-card resizing, networking via `nmtui`, and the clock/timezone. Fenrir is enabled for later boots unless you choose to disable console speech when I38 starts at boot.
|
||||
7. After first-boot setup, log in using the default credentials (username `stormux`, password `stormux`). Root uses `root`/`root` until you change it. If setup is interrupted, run `sudo configure-stormux` to continue.
|
||||
|
||||
## Testing Without Hardware
|
||||
You can boot the image in a container to verify services before flashing:
|
||||
@@ -82,6 +84,17 @@ sudo systemd-nspawn -i stormux-rpi4-5-aarch64-*.img --boot
|
||||
```
|
||||
Use `machinectl` to connect to the console and ensure critical services start. For unit files you edit, run `systemd-analyze verify path/to/unit` inside the container or the Pi.
|
||||
|
||||
### Focused Setup Checks
|
||||
|
||||
From the repository root, run:
|
||||
```bash
|
||||
python3 pi4/tests/test-first-boot-fenrir-setup.py
|
||||
bash tests/test-select-speech-module.sh
|
||||
shellcheck pi4/build/build-stormux.sh pi4/files/etc/profile.d/stormux_first_boot.sh pi4/files/usr/local/bin/configure-stormux
|
||||
```
|
||||
|
||||
For acceptance, boot a rebuilt image on a Pi. Confirm that volume calibration comes first, voice previews work with Up/Down, Enter accepts the engine, Escape keeps the previous engine, and the laptop question uses the selected voice. Test desktop (Enter or N) and laptop (Y) bindings and confirm Fenrir starts once after the choice. Exercise both connected and headless display setup, I38 boot with console Fenrir enabled and disabled, SD-card resize accepted and declined, and setup with and without networking. Reboot after completing setup to check voice/layout persistence, the selected console/I38 startup behavior, and removal of temporary autologin/passwordless sudo. Automated checks and container boots do not establish audible speech, physical keyboard behavior, or real Pi boot acceptance.
|
||||
|
||||
## Troubleshooting Tips
|
||||
- **Locale or package errors**: Ensure your host’s pacman keyring is up to date (`sudo pacman -Sy archlinux-keyring`).
|
||||
- **Loop device cleanup**: After failures run `sudo losetup -a` to find stray devices, then `sudo losetup -d /dev/loopX`.
|
||||
|
||||
@@ -570,6 +570,8 @@ echo '%wheel ALL=(ALL) ALL' > /etc/sudoers.d/wheel
|
||||
echo stormux > /etc/hostname
|
||||
# Configure services
|
||||
systemctl disable systemd-networkd.service systemd-networkd.socket
|
||||
# First-login setup starts Fenrir after volume, voice, and layout selection.
|
||||
systemctl disable fenrirscreenreader.service
|
||||
# Enable services
|
||||
services=(
|
||||
brltty.path
|
||||
|
||||
@@ -62,16 +62,4 @@ fi
|
||||
|
||||
/usr/local/lib/stormux/select-speech-module
|
||||
|
||||
echo
|
||||
echo "Starting Fenrir..."
|
||||
spd-say "Starting Fenrir."
|
||||
sudo "${sudoFlags[@]}" systemctl --quiet enable --now fenrirscreenreader.service
|
||||
|
||||
clear
|
||||
cat << "EOF"
|
||||
Hello, and welcome to Stormux!
|
||||
|
||||
Please press enter to continue.
|
||||
EOF
|
||||
read -r
|
||||
sudo "${sudoFlags[@]}" configure-stormux
|
||||
@@ -104,13 +104,54 @@ EndSection
|
||||
EOF
|
||||
}
|
||||
|
||||
restart_fenrir_speech() {
|
||||
configure_fenrir() {
|
||||
local keyboardLayout="desktop" answer configPath tempPath serviceAction="start"
|
||||
configPath="/etc/fenrirscreenreader/settings/settings.toml"
|
||||
# A manual rerun must also apply the newly selected launch-time layout.
|
||||
if systemctl is-active --quiet fenrirscreenreader.service; then
|
||||
killall speech-dispatcher 2>/dev/null || true
|
||||
systemctl restart fenrirscreenreader.service
|
||||
serviceAction="restart"
|
||||
fi
|
||||
|
||||
# Reload the default engine selected before this script was started.
|
||||
killall speech-dispatcher 2>/dev/null || true
|
||||
while true; do
|
||||
echo "Would you like to switch Fenrir to laptop layout? [y/N]"
|
||||
spd-say -w "Would you like to switch Fenrir to laptop layout? Press y for yes or n for no, followed by Enter. Press Enter for desktop layout."
|
||||
read -r answer || return 1
|
||||
case "${answer,,}" in
|
||||
y|yes) keyboardLayout="laptop"; break ;;
|
||||
n|no|"") break ;;
|
||||
esac
|
||||
done
|
||||
|
||||
tempPath="$(mktemp "${configPath}.stormux.XXXXXX")" || return 1
|
||||
if ! cp --preserve=mode,ownership "$configPath" "$tempPath" || ! awk -v layout="$keyboardLayout" '
|
||||
/^[[:space:]]*\[/ { inKeyboard = ($0 ~ /^[[:space:]]*\[keyboard\][[:space:]]*(#.*)?$/) }
|
||||
inKeyboard && /^[[:space:]]*layout[[:space:]]*=/ {
|
||||
if (sub(/=[[:space:]]*("[^"]*"|\047[^\047]*\047)/, "= \"" layout "\"")) {
|
||||
changed++
|
||||
}
|
||||
}
|
||||
{ print }
|
||||
END { if (changed != 1) exit 1 }
|
||||
' "$configPath" > "$tempPath" || ! fenrir --config "$tempPath" --check-config; then
|
||||
rm -f "$tempPath"
|
||||
echo "Could not configure Fenrir. The original settings were preserved."
|
||||
spd-say -w "Could not configure Fenrir. The original settings were preserved."
|
||||
return 1
|
||||
fi
|
||||
if ! mv -f "$tempPath" "$configPath"; then
|
||||
rm -f "$tempPath"
|
||||
return 1
|
||||
fi
|
||||
if ! systemctl "$serviceAction" fenrirscreenreader.service; then
|
||||
echo "Fenrir could not start. Check journalctl -u fenrirscreenreader.service."
|
||||
spd-say -w "Fenrir could not start. Check the screen reader service log."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
set_timezone() {
|
||||
# Get the list of timezones
|
||||
mapfile -t regions < <(timedatectl --no-pager list-timezones | cut -d '/' -f1 | sort -u)
|
||||
@@ -139,12 +180,14 @@ set_timezone() {
|
||||
ln -sf /usr/share/zoneinfo/"${region}"/"${city}" /etc/localtime
|
||||
timedatectl set-ntp true
|
||||
}
|
||||
# Offer to switch fenrir layout.
|
||||
if read_yes_no "Would you like to switch Fenrir to laptop layout?"; then
|
||||
sed -i 's/=desktop/=laptop/' /etc/fenrirscreenreader/settings/settings.conf
|
||||
clear
|
||||
fi
|
||||
restart_fenrir_speech
|
||||
configure_fenrir || exit 1
|
||||
# Keep console speech available on later boots unless the I38 choice disables it.
|
||||
systemctl --quiet enable fenrirscreenreader.service || exit 1
|
||||
|
||||
clear
|
||||
echo "Hello, and welcome to Stormux!"
|
||||
echo "Let's get you set up. Please press enter to continue."
|
||||
read -r
|
||||
|
||||
if command -v i3 > /dev/null 2>&1 && systemctl list-unit-files nodm.service > /dev/null 2>&1; then
|
||||
if read_yes_no "Will this Pi be connected to a physical screen?"; then
|
||||
|
||||
+20
-7
@@ -89,7 +89,7 @@ The Stormux repository key is also embedded in the ISO at `/usr/share/stormux/st
|
||||
- The UEFI systemd-boot menu enables its audible beep
|
||||
- Boot menu defaults to accessible entry
|
||||
- Service startup order ensures audio is ready before screen reader
|
||||
- First-login live-environment setup calibrates volume, checks networking and time, then offers to run the installer
|
||||
- First-login setup calibrates volume, selects the default speech engine and Fenrir keyboard layout, starts Fenrir, then checks networking and time before offering the installer
|
||||
|
||||
### Package Management
|
||||
|
||||
@@ -113,19 +113,23 @@ The live environment uses a carefully orchestrated startup sequence to ensure Fe
|
||||
- Starts pipewire user services
|
||||
- Unmutes audio and sets volume to 70%
|
||||
|
||||
2. **stormux-speech.service** - Runs after audio setup
|
||||
- Waits 2 seconds for pipewire to fully initialize
|
||||
- Starts fenrirscreenreader.service
|
||||
2. **First-login setup on tty1**
|
||||
- Calibrates volume using Speech Dispatcher
|
||||
- Offers the default speech-engine selector
|
||||
- Speaks the laptop-layout question using the selected engine
|
||||
- Sets `[keyboard] layout` in `/etc/fenrirscreenreader/settings/settings.toml`, preserving comments, and validates the configuration
|
||||
- Starts `fenrirscreenreader.service` with the selected settings
|
||||
|
||||
3. **fenrirscreenreader.service** - Screen reader with dependencies
|
||||
- Configured to wait for pipewire, speech-dispatcher, and sound.target
|
||||
- Configured to wait for user audio initialization and sound.target
|
||||
- Uses speech-dispatcher for TTS output
|
||||
- Disabled at boot in the live ISO; started by first-login setup
|
||||
|
||||
This ensures Fenrir never starts without working audio, preventing system freezes or silent boot.
|
||||
The old `stormux-speech.service` boot launcher is also disabled in the live ISO. The installed system still enables Fenrir at boot.
|
||||
|
||||
## Live Setup and Installer Flow
|
||||
|
||||
On first login to tty1, the live environment runs a short setup script. It calibrates speech volume, checks for network access, updates the live environment clock, copies the detected timezone into the installer defaults, and then asks whether to run `install-stormux`.
|
||||
On first login to tty1, setup calibrates volume, selects the default speech engine, and asks whether to use Fenrir's laptop layout. These prompts use Speech Dispatcher directly while Fenrir is stopped. Enter at the layout prompt selects desktop layout. Setup then starts Fenrir, presents the welcome prompt, checks for network access, updates the live environment clock, and asks whether to run `install-stormux`.
|
||||
|
||||
The installer gives one last chance to accept or change the timezone before installation. The live setup changes are for the temporary live environment only; the installed system is configured by `install-stormux`.
|
||||
|
||||
@@ -146,6 +150,15 @@ After building, test the ISO with:
|
||||
- VirtualBox
|
||||
- Physical hardware (USB/CD)
|
||||
|
||||
Before building, run the focused checks from this directory:
|
||||
|
||||
```bash
|
||||
python3 tests/test-live-fenrir-setup.py
|
||||
bash ../tests/test-select-speech-module.sh
|
||||
```
|
||||
|
||||
For boot acceptance, confirm that Fenrir stays silent during volume calibration and voice selection, the laptop prompt uses the selected voice, and Fenrir starts once afterward. Test both desktop (Enter or N) and laptop (Y) bindings, voice selection with Enter and Escape, network setup with and without a connection, and declining the installer. After a test installation, confirm that the selected voice persists and Fenrir starts at boot. Automated checks do not establish audible speech, physical keyboard behavior, or installed-system acceptance.
|
||||
|
||||
For VM testing with audio:
|
||||
```bash
|
||||
./qemu-boot.sh
|
||||
|
||||
@@ -50,13 +50,4 @@ fi
|
||||
/usr/local/lib/stormux/select-speech-module \
|
||||
--selection-file /run/stormux/selected-speech-module
|
||||
|
||||
clear
|
||||
cat << "EOF"
|
||||
Hello, and welcome to Stormux!
|
||||
|
||||
Let's get you set up.
|
||||
|
||||
Please press enter to continue.
|
||||
EOF
|
||||
read -r
|
||||
sudo "${sudoFlags[@]}" configure-stormux
|
||||
@@ -1,5 +1,5 @@
|
||||
[Unit]
|
||||
# Ensure audio and speech-dispatcher are available before starting Fenrir
|
||||
# Ensure audio is available before starting Fenrir.
|
||||
# Wait for user audio initialization to complete
|
||||
After=sound.target stormux-audio-setup.service speech-dispatcherd.service user@1000.service
|
||||
Wants=stormux-audio-setup.service speech-dispatcherd.service user@1000.service
|
||||
After=sound.target stormux-audio-setup.service user@1000.service
|
||||
Wants=stormux-audio-setup.service user@1000.service
|
||||
@@ -110,7 +110,8 @@ fi
|
||||
|
||||
# Enable system services
|
||||
systemctl enable NetworkManager.service
|
||||
systemctl enable fenrirscreenreader.service
|
||||
# The first-login setup starts Fenrir after volume, voice, and layout selection.
|
||||
systemctl disable fenrirscreenreader.service stormux-speech.service
|
||||
systemctl enable brltty.path
|
||||
|
||||
# Enable user services globally for all users
|
||||
|
||||
@@ -38,27 +38,63 @@ set_timezone() {
|
||||
timedatectl set-ntp true
|
||||
}
|
||||
|
||||
restart_fenrir_speech() {
|
||||
configure_fenrir() {
|
||||
local keyboardLayout="desktop" answer configPath tempPath serviceAction="start"
|
||||
configPath="/etc/fenrirscreenreader/settings/settings.toml"
|
||||
# A manual rerun must also apply the newly selected launch-time layout.
|
||||
if systemctl is-active --quiet fenrirscreenreader.service; then
|
||||
killall speech-dispatcher 2>/dev/null || true
|
||||
systemctl restart fenrirscreenreader.service
|
||||
serviceAction="restart"
|
||||
fi
|
||||
|
||||
# Reload the default engine selected before this script was started.
|
||||
killall speech-dispatcher 2>/dev/null || true
|
||||
while true; do
|
||||
echo "Would you like to switch Fenrir to laptop layout? [y/N]"
|
||||
spd-say -w "Would you like to switch Fenrir to laptop layout? Press y for yes or n for no, followed by Enter. Press Enter for desktop layout."
|
||||
read -r answer || return 1
|
||||
case "${answer,,}" in
|
||||
y|yes) keyboardLayout="laptop"; break ;;
|
||||
n|no|"") break ;;
|
||||
esac
|
||||
done
|
||||
|
||||
tempPath="$(mktemp "${configPath}.stormux.XXXXXX")" || return 1
|
||||
if ! cp --preserve=mode,ownership "$configPath" "$tempPath" || ! awk -v layout="$keyboardLayout" '
|
||||
/^[[:space:]]*\[/ { inKeyboard = ($0 ~ /^[[:space:]]*\[keyboard\][[:space:]]*(#.*)?$/) }
|
||||
inKeyboard && /^[[:space:]]*layout[[:space:]]*=/ {
|
||||
if (sub(/=[[:space:]]*("[^"]*"|\047[^\047]*\047)/, "= \"" layout "\"")) {
|
||||
changed++
|
||||
}
|
||||
}
|
||||
{ print }
|
||||
END { if (changed != 1) exit 1 }
|
||||
' "$configPath" > "$tempPath" || ! fenrir --config "$tempPath" --check-config; then
|
||||
rm -f "$tempPath"
|
||||
echo "Could not configure Fenrir. The original settings were preserved."
|
||||
spd-say -w "Could not configure Fenrir. The original settings were preserved."
|
||||
return 1
|
||||
fi
|
||||
if ! mv -f "$tempPath" "$configPath"; then
|
||||
rm -f "$tempPath"
|
||||
return 1
|
||||
fi
|
||||
if ! systemctl "$serviceAction" fenrirscreenreader.service; then
|
||||
echo "Fenrir could not start. Check journalctl -u fenrirscreenreader.service."
|
||||
spd-say -w "Fenrir could not start. Check the screen reader service log."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Offer to switch fenrir layout.
|
||||
echo "Would you like to switch Fenrir to laptop layout?"
|
||||
echo "Press y for yes or n for no followed by enter."
|
||||
read -r continue
|
||||
continue="${continue::1}"
|
||||
if [[ "${continue,}" == "y" ]];then
|
||||
sed -i 's/=desktop/=laptop/' /etc/fenrirscreenreader/settings/settings.conf
|
||||
clear
|
||||
fi
|
||||
restart_fenrir_speech
|
||||
configure_fenrir || exit 1
|
||||
|
||||
clear
|
||||
echo "Hello, and welcome to Stormux!"
|
||||
echo "Let's get you set up. Please press enter to continue."
|
||||
read -r
|
||||
|
||||
if ! ping -c1 stormux.org &> /dev/null ; then
|
||||
echo "No internet connection detected. Press enter to open NetworkManager."
|
||||
read -r continue
|
||||
read -r
|
||||
echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
|
||||
nmtui-connect
|
||||
echo "setting set focus#highlight=False" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
|
||||
|
||||
@@ -13,6 +13,8 @@ if [ -d /etc/skel.custom ]; then
|
||||
fi
|
||||
|
||||
# Set the distribution name
|
||||
# /etc/issue interprets these escapes when getty displays it.
|
||||
# shellcheck disable=SC2028
|
||||
echo 'Stormux \r (\l)' > /etc/issue
|
||||
echo >> /etc/issue
|
||||
|
||||
@@ -54,9 +56,10 @@ echo stormux > /etc/hostname
|
||||
systemctl disable systemd-networkd.service systemd-networkd.socket 2>/dev/null || true
|
||||
|
||||
# Enable services
|
||||
# The first-login setup starts Fenrir after volume, voice, and layout selection.
|
||||
systemctl disable fenrirscreenreader.service stormux-speech.service
|
||||
services=(
|
||||
brltty.path
|
||||
fenrirscreenreader.service
|
||||
NetworkManager.service
|
||||
stormux-audio-setup.service
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user