diff --git a/.github/workflows/build-all.yml b/.github/workflows/build-all.yml
index 42b33ea..501c967 100644
--- a/.github/workflows/build-all.yml
+++ b/.github/workflows/build-all.yml
@@ -41,6 +41,25 @@ jobs:
compression-level: 6
custom-hostname: picompose
+ # 2MICHAT-v2
+ build-2michat-v2:
+ uses: ./.github/workflows/build-image-template.yml
+ with:
+ image-name: PiCompose-2MicHat-v2
+ stage-list: stage0 stage1 stage2 ./01-stage-picompose ./02-stage-audiodriver-2michat-v2 ./04-stage-finish
+ compression: xz
+ compression-level: 6
+ custom-hostname: picompose
+
+ build-2michat-v2-lva:
+ uses: ./.github/workflows/build-image-template.yml
+ with:
+ image-name: PiCompose_2MicHat-v2_Linux-Voice-Assistant
+ stage-list: stage0 stage1 stage2 ./01-stage-picompose ./02-stage-audiodriver-2michat-v2 ./03-stage-linux-voice-assistant ./04-stage-finish
+ compression: xz
+ compression-level: 6
+ custom-hostname: picompose
+
# RESPEAKER-LITE
build-respeaker_lite:
uses: ./.github/workflows/build-image-template.yml
@@ -62,5 +81,5 @@ jobs:
# RPI IMAGER JSON
generate-rpi-imager-json:
- needs: [build, build-2michat, build-respeaker_lite, build-2michat-lva, build-respeaker_lite-lva]
+ needs: [build, build-2michat, build-2michat-v2, build-respeaker_lite, build-2michat-lva, build-2michat-v2-lva, build-respeaker_lite-lva]
uses: ./.github/workflows/create-rpi-image-json.yml
diff --git a/02-stage-audiodriver-2michat-v2/01-driver/01-packages b/02-stage-audiodriver-2michat-v2/01-driver/01-packages
new file mode 100644
index 0000000..775d501
--- /dev/null
+++ b/02-stage-audiodriver-2michat-v2/01-driver/01-packages
@@ -0,0 +1,4 @@
+git
+build-essential
+device-tree-compiler
+alsa-utils
diff --git a/02-stage-audiodriver-2michat-v2/01-driver/03-run-chroot.sh b/02-stage-audiodriver-2michat-v2/01-driver/03-run-chroot.sh
new file mode 100755
index 0000000..a9160c6
--- /dev/null
+++ b/02-stage-audiodriver-2michat-v2/01-driver/03-run-chroot.sh
@@ -0,0 +1,44 @@
+#!/bin/bash -e
+
+# ReSpeaker 2-Mics Pi HAT **V2.0** uses a TLV320AIC3104 codec on I2C 0x18 —
+# NOT the WM8960 codec (0x1a) used on V1. No out-of-tree DKMS module is
+# needed: the mainline `snd-soc-tlv320aic3x` driver already ships in the
+# kernel. We just need the device-tree overlay that wires it up to the Pi's
+# I2S pins. The overlay source is maintained by Seeed in their
+# seeed-linux-dtoverlays repo.
+
+echo "Building ReSpeaker 2-Mic HAT V2.0 device-tree overlay..."
+
+SRC=/tmp/seeed-linux-dtoverlays
+rm -rf "$SRC"
+git clone --depth 1 https://github.com/Seeed-Studio/seeed-linux-dtoverlays.git "$SRC"
+
+cd "$SRC"
+make overlays/rpi/respeaker-2mic-v2_0-overlay.dtbo
+
+# detect boot config + overlays location
+OVERLAYS_DIR=/boot/overlays
+CONFIG=/boot/config.txt
+if [ -d /boot/firmware/overlays ]; then
+ OVERLAYS_DIR=/boot/firmware/overlays
+fi
+if [ -f /boot/firmware/config.txt ]; then
+ CONFIG=/boot/firmware/config.txt
+fi
+if [ -f /boot/firmware/usercfg.txt ]; then
+ CONFIG=/boot/firmware/usercfg.txt
+fi
+
+install -v -m 644 overlays/rpi/respeaker-2mic-v2_0-overlay.dtbo \
+ "${OVERLAYS_DIR}/respeaker-2mic-v2_0.dtbo"
+
+# set boot params: enable I2C and load the v2 overlay
+sed -i -e 's:#dtparam=i2c_arm=on:dtparam=i2c_arm=on:g' "$CONFIG" || true
+grep -q "^dtparam=i2c_arm=on$" "$CONFIG" || echo "dtparam=i2c_arm=on" >> "$CONFIG"
+grep -q "^dtoverlay=respeaker-2mic-v2_0$" "$CONFIG" || \
+ echo "dtoverlay=respeaker-2mic-v2_0" >> "$CONFIG"
+
+cd /
+rm -rf "$SRC"
+
+echo "Done. After boot the card appears as 'seeed2micvoicec' (bcm2835-i2s-tlv320aic3x-hifi)."
diff --git a/02-stage-audiodriver-2michat-v2/02-set-audio-volume/01-run.sh b/02-stage-audiodriver-2michat-v2/02-set-audio-volume/01-run.sh
new file mode 100755
index 0000000..fc50a65
--- /dev/null
+++ b/02-stage-audiodriver-2michat-v2/02-set-audio-volume/01-run.sh
@@ -0,0 +1,10 @@
+#!/bin/bash -e
+
+install -v -m 755 files/configure_audio.sh "${ROOTFS_DIR}/usr/bin/configure_audio.sh"
+install -v -m 644 files/configure_audio.service "${ROOTFS_DIR}/etc/systemd/system/configure_audio.service"
+
+on_chroot << EOF
+echo "Enable audio services"
+systemctl daemon-reload
+systemctl enable configure_audio.service
+EOF
diff --git a/02-stage-audiodriver-2michat-v2/02-set-audio-volume/files/configure_audio.service b/02-stage-audiodriver-2michat-v2/02-set-audio-volume/files/configure_audio.service
new file mode 100644
index 0000000..945f217
--- /dev/null
+++ b/02-stage-audiodriver-2michat-v2/02-set-audio-volume/files/configure_audio.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=PiCompose - Configure Audio volume setting (ReSpeaker 2-Mic HAT V2.0)
+After=user@1000.service sound.target alsa-restore.service
+Wants=user@1000.service sound.target alsa-restore.service
+
+[Service]
+Type=oneshot
+Environment=XDG_RUNTIME_DIR=/run/user/1000
+ExecStart=/usr/bin/configure_audio.sh
+RemainAfterExit=yes
+Restart=on-failure
+RestartSec=30s
+
+[Install]
+WantedBy=multi-user.target
diff --git a/02-stage-audiodriver-2michat-v2/02-set-audio-volume/files/configure_audio.sh b/02-stage-audiodriver-2michat-v2/02-set-audio-volume/files/configure_audio.sh
new file mode 100755
index 0000000..2880059
--- /dev/null
+++ b/02-stage-audiodriver-2michat-v2/02-set-audio-volume/files/configure_audio.sh
@@ -0,0 +1,80 @@
+#!/bin/bash
+set -u
+
+# TLV320AIC3104 on V2.0 ships quiet on both ends: HP DAC at -23.5 dB,
+# HP/Line amps at ~89% and muted on some units, and the capture PGA at 27%
+# (16 dB) — too low for microWakeWord detection. PCM is driven by wpctl as
+# hardware-volume passthrough, so only the downstream stages need tuning.
+# Runs every boot because WirePlumber can reset ALSA state between sessions.
+
+wait_for_card_and_control() {
+ local card="$1"
+ local control="$2"
+ local max_tries=30
+ local count=0
+
+ while [ "$count" -lt "$max_tries" ]; do
+ count=$((count + 1))
+
+ if amixer -c "$card" info >/dev/null 2>&1; then
+ if amixer -c "$card" scontrols | grep -Fq "'$control'"; then
+ echo "Card $card with control '$control' is ready ($count/$max_tries)"
+ return 0
+ fi
+ echo "Card $card found, but control '$control' not ready yet ($count/$max_tries)"
+ else
+ echo "Card $card not ready yet ($count/$max_tries)"
+ fi
+
+ sleep 1
+ done
+
+ echo "Card $card with control '$control' did not become ready"
+ return 1
+}
+
+# Returns 0 on set-success or missing control; 1 on set-failure.
+# Non-zero exit triggers the systemd retry.
+set_control_if_exists() {
+ local card="$1"
+ local control="$2"
+ shift 2
+
+ if amixer -c "$card" scontrols | grep -Fq "'$control'"; then
+ echo "Setting $control on $card to $*"
+ if amixer -c "$card" set "$control" "$@"; then
+ return 0
+ fi
+ echo "amixer set failed for '$control' on $card" >&2
+ return 1
+ fi
+
+ echo "Control '$control' not found on $card, skipping"
+ return 0
+}
+
+# Same kernel alias as V1 (`seeed2micvoicec`); the PCM control distinguishes
+# V2's tlv320aic3x from V1's wm8960.
+if ! wait_for_card_and_control seeed2micvoicec PCM; then
+ echo "No TLV320AIC3104-based card became ready; is the V2.0 overlay loaded?"
+ exit 1
+fi
+CARD="seeed2micvoicec"
+
+FAIL=0
+set_control_if_exists "$CARD" "HP DAC" 100% || FAIL=1
+set_control_if_exists "$CARD" "Line DAC" 100% || FAIL=1
+set_control_if_exists "$CARD" "HP" 100% unmute || FAIL=1
+set_control_if_exists "$CARD" "Line" 100% unmute || FAIL=1
+set_control_if_exists "$CARD" "PGA" 80% cap || FAIL=1
+
+if [ "$FAIL" -ne 0 ]; then
+ echo "One or more amixer set calls failed; not storing state." >&2
+ exit 1
+fi
+
+# Keep PipeWire sink at unity so HA/LVA volume reaches the ALSA stages
+# above. Matches the 2michat-v1 pattern from #42.
+wpctl set-volume @DEFAULT_AUDIO_SINK@ 1.0
+
+alsactl store
diff --git a/02-stage-audiodriver-2michat-v2/prerun.sh b/02-stage-audiodriver-2michat-v2/prerun.sh
new file mode 100755
index 0000000..9acd13c
--- /dev/null
+++ b/02-stage-audiodriver-2michat-v2/prerun.sh
@@ -0,0 +1,5 @@
+#!/bin/bash -e
+
+if [ ! -d "${ROOTFS_DIR}" ]; then
+ copy_previous
+fi
diff --git a/README.md b/README.md
index 58935f9..9016706 100644
--- a/README.md
+++ b/README.md
@@ -52,6 +52,8 @@ Here is a Overview for the specific images of each hardware:
| **[Sattelite1](docs/hardware_sattelite1.md)**
**+Linux-Voice-Assistant**
**+Snapcast** |
| • Satellite1 Hat Image
• Linux-Voice-Assistant (OpenHomeFoundation)
• Snapcast MultiRoom Audio Client
• Pre-configured for Home Assistant
Image is currently work in progress! |
| **[ReSpeaker 2-Mic HAT v1](docs/hardware_2mic_v1.md)** |
| • Base Image
• Seeed Voicecard Driver |
| **[ReSpeaker 2-Mic HAT v1](docs/hardware_2mic_v1.md)**
**+Linux-Voice-Assistant**
**+Snapcast** |
| • 2-Mic HAT Image
• Linux-Voice-Assistant (OpenHomeFoundation)
• 2-Mic HAT GPIO LED Control
• Snapcast MultiRoom Audio Client
• Pre-configured for Home Assistant |
+| **[ReSpeaker 2-Mic HAT v2.0](docs/hardware_2mic_v2.md)** |
| • Base Image
• TLV320AIC3104 device-tree overlay
• Per-boot codec mixer tuning for the V2.0 |
+| **[ReSpeaker 2-Mic HAT v2.0](docs/hardware_2mic_v2.md)**
**+Linux-Voice-Assistant**
**+Snapcast** |
| • 2-Mic HAT v2.0 Image
• Linux-Voice-Assistant (OpenHomeFoundation)
• Snapcast MultiRoom Audio Client
• Pre-configured for Home Assistant |
| **[ReSpeaker Lite](docs/hardware_respeaker_lite.md)** |
| • Base Image
• Audio keep-alive service
• Workaround for connectivity issues in combination with the Pi Zero 2W.
There is a USB connectivity issue with the Pi Zero 2W. I cannot recommend this board if you want to use it with that. Use Pi3 or higher. |
| **[ReSpeaker Lite](docs/hardware_respeaker_lite.md)**
**+Linux-Voice-Assistant**
**+Snapcast** |
| • ReSpeaker Lite Image
• Linux-Voice-Assistant (OpenHomeFoundation)
• Snapcast MultiRoom Audio Client
• Pre-configured for Home Assistant
• Workaround for connectivity issues in combination with the Pi Zero 2W.
There is a USB connectivity issue with the Pi Zero 2W. If you want to use it with that, you need to use Pi3 or higher. |
diff --git a/docs/hardware_2mic_v2.md b/docs/hardware_2mic_v2.md
new file mode 100644
index 0000000..dbc6c0b
--- /dev/null
+++ b/docs/hardware_2mic_v2.md
@@ -0,0 +1,41 @@
+# Hardware - ReSpeaker 2-Mics Pi HAT v2.0
+
+
+
+The V2.0 is a silent hardware revision of the 2-Mics Pi HAT. Visually identical, electrically different: the WM8960 codec used on v1 (I2C `0x1a`) is replaced with a **TLV320AIC3104** codec (I2C `0x18`). This matters because the v1 driver stage does not produce a working sound card on v2 hardware, and because the mixer defaults differ.
+
+Features (same as v1):
+- Support the Raspberry Pi 3B / 4B / Zero 2 W
+- Two microphones (Mic L and Mic R)
+- Two Grove connectors
+- One User-defined button
+- 3.5 mm audio interface
+- XH2.54-2P audio output interface
+
+## Order
+
+### Base:
+
+- [Raspberry Pi Zero 2 W](https://amzn.to/3M0G4hC)
+- [SD-Card](https://amzn.to/4qfx06l)
+- [US MicroUSB Power Supply](https://amzn.to/4c52mt3)
+- [Cable for Speaker](https://amzn.to/3ZvU0Dz)
+
+### ReSpeaker 2-Mics Pi HAT v2.0
+
+- [Seeed Studio ReSpeaker 2-Mics Pi HAT V2.0](https://wiki.seeedstudio.com/respeaker_2_mics_pi_hat_v2/)
+
+## Technical notes
+
+Unlike v1 — which needs an out-of-tree DKMS kernel module — v2 uses the mainline `snd-soc-tlv320aic3x` driver that already ships with the Raspberry Pi OS kernel. The image only needs:
+
+1. The device-tree overlay `respeaker-2mic-v2_0.dtbo` (built from [Seeed-Studio/seeed-linux-dtoverlays](https://github.com/Seeed-Studio/seeed-linux-dtoverlays)), enabled via `dtoverlay=respeaker-2mic-v2_0` in `/boot/firmware/config.txt`.
+2. `dtparam=i2c_arm=on` in `/boot/firmware/config.txt`.
+3. Per-boot mixer tuning — the TLV320 ships with several attenuators well below 100 % (`HP DAC` at -23.5 dB in particular), producing a card that appears to work but is inaudible at typical application volumes.
+
+The PiCompose `02-stage-audiodriver-2michat-v2` stage performs all three steps automatically. The mixer tuning is applied by `configure_audio.service` on every boot, the same pattern other audiodriver stages follow after #42: amixer on the codec-specific controls, then `wpctl set-volume @DEFAULT_AUDIO_SINK@ 1.0` to keep the PipeWire sink at unity. PipeWire / WirePlumber manage ALSA state per session and can reset the mixer between reboots, so a first-boot-only guard would let users end up stuck at 0%. Customization via `amixer` is still possible at runtime — it just won't survive a reboot.
+
+## Additional information
+
+- [Seeed Studio Wiki — ReSpeaker 2-Mics Pi HAT v2.0](https://wiki.seeedstudio.com/respeaker_2_mics_pi_hat_v2/)
+- [seeed-linux-dtoverlays (overlay source)](https://github.com/Seeed-Studio/seeed-linux-dtoverlays)