Repository navigation
athena: Echo Show 8 2nd gen (Android 9, MT8183) [stacked on #33] - #34
Merged
Merged
Conversation
baudneo
force-pushed
the
athena
branch
7 times, most recently
from
October 17, 2026 06:48
18cad15 to
e97e24d
Compare
baudneo
marked this pull request as ready for review
October 17, 2026 18:01
A different platform from crown: Android 9 with Treble and enforcing SELinux, rooted in place by saiyaku-athena's zip (INSTALL=running: install-system.sh writes /system/hassmic and patches the vendor policy), the front end inside the audio HAL (OpenSL ES, as crown), a TAS5805m amplifier, a TCS3400 light sensor. devices/athena, docs/re-athena.md. What the platform needed: - the libc's accept/accept4/connect fail with EBADF (netd's fwmarkd denied on su sockets: sepolicy rule; net_accept, net_connect_fd and libcurl's already-connected socket stay as workarounds) - Wi-Fi through Android 9's IWifiManager (package name argument, ParceledListSlice) in wifictl.dex, run as uid system - ringbar.dex builds the SurfaceControl through its Builder on SDK >= 26 - IAudioService's transaction numbers differ on Android 9: setStreamVolume 7, getStreamMaxVolume 14 (the volume keys and Music Assistant's volume did nothing before) - the light sensor's lux from the raw channels as stock's virtual_als does (lux.h) - speaker gain on the TAS5805m's digital volume, up to +9 dB (listened to: a rap track's bass clips above) - Sendspin: unpaired sessions are closed when "Music Assistant without pairing" changes - Drop In: a quiet room's noise no longer counts as the far end talking (NEAR_MIN_DB, far_voice) - "Download from Amazon" through the fireosdhaservice binder service Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…r's second Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…s its reboot Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…d-to-reset Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The driver is named gen2 (wlan_mt76x3_sdio) but its receive path is gen4m's, so hassmic_rcpi4m.c runs with its 32-bit defaults. The kernel has no patch_text and read-only module text: the module falls back to set_memory_rw (kallsyms) and a write under stop_machine. CONFIG_MODVERSIONS is on: devices/athena/Module.symvers carries the kernel's CRCs (read out of boot.img's Image), which the Makefile copies into the kernel tree. Tested on a Show 8 2nd gen: RCPI 120 for unicast (0x14009), 129 for broadcasts, the motion sensor switched on when someone walked past. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…r Wi-Fi motion Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…r in the matrix) The build job left out hassmic_rcpi4m.ko for lack of toolchain/linux-4.4.146 and the check that a bundle must not lose its module failed. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Taken out of this PR, to come back on their own (as issue 45 did for crown's): the system-call bypass of the libc's accept()/connect() (netio.h net_accept/net_connect_fd, net.c net_open_connected, libcurl's already-connected socket in davs.c and update.c: under __ANDROID__ it changed every model, and athena's cause, netd denied on su sockets, is fixed by its sepolicy.rules), the 200 ms cold-output lead-in and state/lead_ms (checkers and crown share audio_android.c: back to 350), the Drop In gate (NEAR_MIN_DB, far_voice, dropin_far_level and its log line), closing idle unpaired Sendspin sessions, the blueprint's "drop into"/"drop it in" sentences, the GUIDE's factory-reset note for every Show, and docs/known-issues.md (its athena facts are in docs/re-athena.md now). Their docs with them, and the CHANGELOG entry for restart_hassmic, which is not in this tree. Kept, because athena needs them: INSTALL=running and SEPOLICY_FILE, wifictl.dex and ringbar.dex for Android 9, the IAudioService numbers, fireosdhaservice, the TCS3400 lux, speaker_gain_limit, the early mute press, Wi-Fi motion, and the blueprint's model slug. Fixed on the way: - sysinstall.sh: conf_get's fallback to the installed device.conf never ran (mksh ends the subshell when "." is given a missing file: checked with athena's own sh under qemu), and /vendor is remounted only when the policy is written, not for every promoted update - Makefile: Module.symvers is copied at each build of the module, so a changed list reaches it - ring_band.c: the SDK is read before the fork (a property lookup in the child of a threaded process can deadlock) - athena's setup.sh: boot-root.zip is needed whenever the root step flashes it, the policy tool is unpacked again before the install, locals in step_network; device.conf: WPA_SOCKETS is the firmware's /data/vendor/wifi/wpa/sockets, ambienthome, paladin and whad disabled as on crown - tests/unit/buttons_privacy_test.c for the early mute press; the CI step name back to what fake_wifi_join.py covers - docs: one status everywhere (README, devices/README, the model's page, re-athena.md, PLAN, CHANGELOG), unlock.md in our words, the firmware's FTVDB link, the GUIDE's wake sound and speaker gain lines name the two Show 8s Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 of 17 tasks
Gamer92000
added a commit
that referenced
this pull request
Oct 26, 2026
* athena: Echo Show 8 2nd gen (Android 9, MT8183) A different platform from crown: Android 9 with Treble and enforcing SELinux, rooted in place by saiyaku-athena's zip (INSTALL=running: install-system.sh writes /system/hassmic and patches the vendor policy), the front end inside the audio HAL (OpenSL ES, as crown), a TAS5805m amplifier, a TCS3400 light sensor. devices/athena, docs/re-athena.md. What the platform needed: - the libc's accept/accept4/connect fail with EBADF (netd's fwmarkd denied on su sockets: sepolicy rule; net_accept, net_connect_fd and libcurl's already-connected socket stay as workarounds) - Wi-Fi through Android 9's IWifiManager (package name argument, ParceledListSlice) in wifictl.dex, run as uid system - ringbar.dex builds the SurfaceControl through its Builder on SDK >= 26 - IAudioService's transaction numbers differ on Android 9: setStreamVolume 7, getStreamMaxVolume 14 (the volume keys and Music Assistant's volume did nothing before) - the light sensor's lux from the raw channels as stock's virtual_als does (lux.h) - speaker gain on the TAS5805m's digital volume, up to +9 dB (listened to: a rap track's bass clips above) - Sendspin: unpaired sessions are closed when "Music Assistant without pairing" changes - Drop In: a quiet room's noise no longer counts as the far end talking (NEAR_MIN_DB, far_voice) - "Download from Amazon" through the fireosdhaservice binder service Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * athena: the mute button is answered at the press, not after the driver's second Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * athena: --uninstall restores the SELinux policy in /vendor and reaches its reboot Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * athena: the guided setup unlocks (saiyaku) and roots (boot-root in TWRP) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * docs: the Show 8's action button is a tap of both volume keys, no hold-to-reset Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * athena: Wi-Fi motion (hassmic_rcpi4m on the 4.4.146 kernel) The driver is named gen2 (wlan_mt76x3_sdio) but its receive path is gen4m's, so hassmic_rcpi4m.c runs with its 32-bit defaults. The kernel has no patch_text and read-only module text: the module falls back to set_memory_rw (kallsyms) and a write under stop_machine. CONFIG_MODVERSIONS is on: devices/athena/Module.symvers carries the kernel's CRCs (read out of boot.img's Image), which the Makefile copies into the kernel tree. Tested on a Show 8 2nd gen: RCPI 120 for unicast (0x14009), 129 for broadcasts, the motion sensor switched on when someone walked past. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * athena: the guided setup downloads the kernel sources and compiler for Wi-Fi motion Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * CI: athena builds its Wi-Fi motion module (kernel sources and compiler in the matrix) The build job left out hassmic_rcpi4m.ko for lack of toolchain/linux-4.4.146 and the check that a bundle must not lose its module failed. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * athena: only the port; the changes for every model go to their own PRs Taken out of this PR, to come back on their own (as issue 45 did for crown's): the system-call bypass of the libc's accept()/connect() (netio.h net_accept/net_connect_fd, net.c net_open_connected, libcurl's already-connected socket in davs.c and update.c: under __ANDROID__ it changed every model, and athena's cause, netd denied on su sockets, is fixed by its sepolicy.rules), the 200 ms cold-output lead-in and state/lead_ms (checkers and crown share audio_android.c: back to 350), the Drop In gate (NEAR_MIN_DB, far_voice, dropin_far_level and its log line), closing idle unpaired Sendspin sessions, the blueprint's "drop into"/"drop it in" sentences, the GUIDE's factory-reset note for every Show, and docs/known-issues.md (its athena facts are in docs/re-athena.md now). Their docs with them, and the CHANGELOG entry for restart_hassmic, which is not in this tree. Kept, because athena needs them: INSTALL=running and SEPOLICY_FILE, wifictl.dex and ringbar.dex for Android 9, the IAudioService numbers, fireosdhaservice, the TCS3400 lux, speaker_gain_limit, the early mute press, Wi-Fi motion, and the blueprint's model slug. Fixed on the way: - sysinstall.sh: conf_get's fallback to the installed device.conf never ran (mksh ends the subshell when "." is given a missing file: checked with athena's own sh under qemu), and /vendor is remounted only when the policy is written, not for every promoted update - Makefile: Module.symvers is copied at each build of the module, so a changed list reaches it - ring_band.c: the SDK is read before the fork (a property lookup in the child of a threaded process can deadlock) - athena's setup.sh: boot-root.zip is needed whenever the root step flashes it, the policy tool is unpacked again before the install, locals in step_network; device.conf: WPA_SOCKETS is the firmware's /data/vendor/wifi/wpa/sockets, ambienthome, paladin and whad disabled as on crown - tests/unit/buttons_privacy_test.c for the early mute press; the CI step name back to what fake_wifi_join.py covers - docs: one status everywhere (README, devices/README, the model's page, re-athena.md, PLAN, CHANGELOG), unlock.md in our words, the firmware's FTVDB link, the GUIDE's wake sound and speaker gain lines name the two Show 8s Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com> Co-authored-by: Julian Imhof <julianimhof00@gmail.com>
9 tasks
Gamer92000
added a commit
that referenced
this pull request
Oct 27, 2026
* athena: Echo Show 8 2nd gen (Android 9, MT8183) A different platform from crown: Android 9 with Treble and enforcing SELinux, rooted in place by saiyaku-athena's zip (INSTALL=running: install-system.sh writes /system/hassmic and patches the vendor policy), the front end inside the audio HAL (OpenSL ES, as crown), a TAS5805m amplifier, a TCS3400 light sensor. devices/athena, docs/re-athena.md. What the platform needed: - the libc's accept/accept4/connect fail with EBADF (netd's fwmarkd denied on su sockets: sepolicy rule; net_accept, net_connect_fd and libcurl's already-connected socket stay as workarounds) - Wi-Fi through Android 9's IWifiManager (package name argument, ParceledListSlice) in wifictl.dex, run as uid system - ringbar.dex builds the SurfaceControl through its Builder on SDK >= 26 - IAudioService's transaction numbers differ on Android 9: setStreamVolume 7, getStreamMaxVolume 14 (the volume keys and Music Assistant's volume did nothing before) - the light sensor's lux from the raw channels as stock's virtual_als does (lux.h) - speaker gain on the TAS5805m's digital volume, up to +9 dB (listened to: a rap track's bass clips above) - Sendspin: unpaired sessions are closed when "Music Assistant without pairing" changes - Drop In: a quiet room's noise no longer counts as the far end talking (NEAR_MIN_DB, far_voice) - "Download from Amazon" through the fireosdhaservice binder service Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * athena: the mute button is answered at the press, not after the driver's second Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * athena: --uninstall restores the SELinux policy in /vendor and reaches its reboot Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * athena: the guided setup unlocks (saiyaku) and roots (boot-root in TWRP) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * docs: the Show 8's action button is a tap of both volume keys, no hold-to-reset Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * athena: Wi-Fi motion (hassmic_rcpi4m on the 4.4.146 kernel) The driver is named gen2 (wlan_mt76x3_sdio) but its receive path is gen4m's, so hassmic_rcpi4m.c runs with its 32-bit defaults. The kernel has no patch_text and read-only module text: the module falls back to set_memory_rw (kallsyms) and a write under stop_machine. CONFIG_MODVERSIONS is on: devices/athena/Module.symvers carries the kernel's CRCs (read out of boot.img's Image), which the Makefile copies into the kernel tree. Tested on a Show 8 2nd gen: RCPI 120 for unicast (0x14009), 129 for broadcasts, the motion sensor switched on when someone walked past. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * athena: the guided setup downloads the kernel sources and compiler for Wi-Fi motion Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * CI: athena builds its Wi-Fi motion module (kernel sources and compiler in the matrix) The build job left out hassmic_rcpi4m.ko for lack of toolchain/linux-4.4.146 and the check that a bundle must not lose its module failed. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * athena: only the port; the changes for every model go to their own PRs Taken out of this PR, to come back on their own (as issue 45 did for crown's): the system-call bypass of the libc's accept()/connect() (netio.h net_accept/net_connect_fd, net.c net_open_connected, libcurl's already-connected socket in davs.c and update.c: under __ANDROID__ it changed every model, and athena's cause, netd denied on su sockets, is fixed by its sepolicy.rules), the 200 ms cold-output lead-in and state/lead_ms (checkers and crown share audio_android.c: back to 350), the Drop In gate (NEAR_MIN_DB, far_voice, dropin_far_level and its log line), closing idle unpaired Sendspin sessions, the blueprint's "drop into"/"drop it in" sentences, the GUIDE's factory-reset note for every Show, and docs/known-issues.md (its athena facts are in docs/re-athena.md now). Their docs with them, and the CHANGELOG entry for restart_hassmic, which is not in this tree. Kept, because athena needs them: INSTALL=running and SEPOLICY_FILE, wifictl.dex and ringbar.dex for Android 9, the IAudioService numbers, fireosdhaservice, the TCS3400 lux, speaker_gain_limit, the early mute press, Wi-Fi motion, and the blueprint's model slug. Fixed on the way: - sysinstall.sh: conf_get's fallback to the installed device.conf never ran (mksh ends the subshell when "." is given a missing file: checked with athena's own sh under qemu), and /vendor is remounted only when the policy is written, not for every promoted update - Makefile: Module.symvers is copied at each build of the module, so a changed list reaches it - ring_band.c: the SDK is read before the fork (a property lookup in the child of a threaded process can deadlock) - athena's setup.sh: boot-root.zip is needed whenever the root step flashes it, the policy tool is unpacked again before the install, locals in step_network; device.conf: WPA_SOCKETS is the firmware's /data/vendor/wifi/wpa/sockets, ambienthome, paladin and whad disabled as on crown - tests/unit/buttons_privacy_test.c for the early mute press; the CI step name back to what fake_wifi_join.py covers - docs: one status everywhere (README, devices/README, the model's page, re-athena.md, PLAN, CHANGELOG), unlock.md in our words, the firmware's FTVDB link, the GUIDE's wake sound and speaker gain lines name the two Show 8s Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com> Co-authored-by: Julian Imhof <julianimhof00@gmail.com>
Gamer92000
added a commit
that referenced
this pull request
Oct 27, 2026
* Echo Show 5 1st gen (checkers): firmware findings, model directory, OpenSL ES backend
The Echo Show 5 (2019, H23K37) runs the same Fire OS 6574.1 as donut, but
as a full Android device: no mixer daemon or libmixerAPI.so, Amazon's
front end (libasp) inside the audio HAL, Alexa as apps, Wi-Fi, iptables
and Bluetooth owned by Android. Worked out from the firmware only; no
unlock is known, so it is not installable.
- docs/re-checkers.md: unpacking the block OTA, where the ASR pipeline
runs and how the HAL picks it from the AudioRecord source, the
audiosignalprocessor binder service (donut's LASP command numbers),
stock's wake word path, board facts, what a port still needs.
- libpryon.so, libopus.so and libz.so are byte-identical to donut's;
donut's pryon_test under qemu detects ALEXA on checkers' en-US model.
- devices/checkers/: device.mk, board.c, device.conf (INSTALL=none),
kconfig (IKCONFIG, 4.9.77 ARM), probe.md5, stubs. hassmic builds, and
links byte-identically against the stubs (tools/mkstubs.sh).
- audio_android.c: capture with the VOICE_RECOGNITION preset (the HAL
routes it into the ASR pipeline), one player per stream mixed by
AudioFlinger, no Bluetooth speaker stream. Untried on a device.
- Makefile: device.mk SYSLIBS for NDK libraries beside the stock ones
(-lOpenSLES); mkstubs.sh counts libOpenSLES as the NDK's.
- ble.c: a model without a stock Bluetooth init service (bt_service NULL).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: the unlock is public (amonet-checkers v2.0.1)
amonet-checkers unlocks the Echo Show 5 1st gen and leaves TWRP: a
fastboot exploit over micro-USB on a working Echo, or the bootrom through
test point TP30 on 2019 units. devices/checkers/README.md has the steps,
the boot key combinations it sets up, and the partitions that must never
be written (lk, preloader, tee: no way back on most units). What blocks an
install now is an install method of this model's own (no A/B slots,
dm-verity on system, the policy in boot.img), not the unlock.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: pin amonet-checkers and boot-root; boot-root is NS6570's
The XDA thread and the sha256 of amonet-checkers-v2.0.1.zip and
boot-root.zip in devices/checkers/README.md. amonet's lk.bin and tz.img
are byte-identical to the pinned 8149 firmware's, so the unlock fits it.
The thread's boot-root.img (adb root, insecure properties, fosflags cut
down) is built from NS6570/6086: its kernel and ramdisk are 6570's, so it
would run that kernel and policy under 8149's /system. Written down with
the differences; hassmic's install should rather apply the same changes to
8149's own boot.img.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: the root boot.img built from 8149's own
scripts/mkbootroot.py replaces the two files inside the boot ramdisk's
cpio stream (default.prop's five properties, init.fosflags.sh byte for
byte the XDA file) and re-splices the image: the header page, kernel
and every other ramdisk entry keep their exact stock bytes, and Amazon's
kernel-signing certificate page trailing the stock image is carried
over. The header ID is AOSP mkbootimg's v0 formula: lk does not check
it (the XDA image boots with a foreign one too). --check proves the
rebuild - the stock image reassembles byte for byte but for the ID; the
built boot-root-8149.img (firmware/, sha256 afca0a33..., 8140800 bytes)
is not tried on a device. Corrected the README: 8149's ramdisk is a
bare gzip stream, only the kernel carries MTK's 512-byte header.
Co-Authored-By: ZCode <noreply@z.ai>
* checkers: installer (root boot image with patched policy, then /system)
The 8149 root boot.img from the last commit would leave adb dead: with
ro.secure=0 adbd setcon()s to its --root_seclabel u:r:su:s0 and AOSP 7
adbd dies when that is refused. 8149's policy has su permissive but no
rule letting adbd into it (the XDA 6570 policy makes adbd and every app
permissive instead).
- scripts/mkbootroot.py: --sepolicy FILE replaces the ramdisk's policy,
--no-verity drops "verify" from the fstab, --extract and --cpio read
the ramdisk. Without options the output is unchanged (afca0a33...).
- devices/checkers/sepolicy.rules: donut boot-root's adb rules plus our
init -> su rules; applied by donut's magiskpolicy32 under qemu-arm, the
diff against stock is exactly those rules.
- scripts/install-boot.sh (INSTALL=boot; install-system.sh hands over):
builds the boot image from the firmware's own boot.img (pinned sha256;
reproducible), checks the Echo's system build from TWRP or the OS,
flashes boot only in amonet's hacked fastboot, checks root adb in su,
then installs the files with sysinstall.sh as on donut. --boot-only,
--uninstall. Never touches lk, preloader or tee.
- devices/checkers/hassmic.rc: firewall on boot, satellite at
sys.boot_completed.
- alexa-off.sh disables Alexa's apps with pm where the model lists
packages, notes them; alexa-on.sh (and boot.sh without hassmic.conf)
turn exactly those back on; stock-online keeps the updater off.
- lockdown.sh: FW_KEEP for rules a model's stock lacks (checkers: DHCP
answers, no stock firewall.sh); the updater's uid from packages.list.
- otatool remount clears BLKROSET when the kernel refuses (checkers'
/system is its own block device).
- tools/sdat2img.py for block OTAs; recording rights read from the
firmware (root records; other uids need a package: system).
Untried on a device. PC-checked: the boot image build end to end with
adb stubbed, alexa scripts against a fake pm, all models build, checkers
stubs byte-identical, ota_push_test, otatool_test, fake_ha_update,
fake_web_artifacts, fake_ha_esphome.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* README: Echo Show 5 marked untested, not unsupported
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: every open item in one list (docs/re-checkers.md)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: Wi-Fi through Android's WifiService, from root's shell (wifictl.dex)
The Show's framework owns the networks: no dhcpcd exists (DHCP runs when
WifiService provisions a network it knows), and it re-syncs wpa_supplicant
from its own WifiConfigStore, so driving wpa_supplicant as the Dots do
cannot get an address and cannot survive a radio toggle. The way in is
what stock's own setup apps use (com.amazon.kindle.otter.oobe and
com.amazon.ds2.oobe.efd put an android.net.wifi.WifiConfiguration in):
the IWifiManager binder, called as root.
- tools/mkwifictl.py assembles scripts/device/wifictl.dex from nothing
but itself: a one-class Java program as Dalvik bytecode, reflection
only (no android.* type references, so the verifier has nothing to
resolve but the platform), run as
CLASSPATH=<dir>/wifictl.dex app_process / Wifictl <verb>.
Its output is shaped like wpa_cli's, so scripts/device/wifi.sh can
serve both worlds: status, list_networks, scan_results (the verbs
match wpa_cli's), add <ssid hex> <psk hex|-> (addOrUpdateNetwork,
hiddenSSID, WPA_PSK), select <id> (enableNetwork(id, true) +
reconnect), enable <id> <only|keep>, remove <id>, reassociate,
wifi-on (setWifiEnabled; Fire OS's binder takes the caller's name),
name <hex> for messages. The WifiService signatures are the ones of
this firmware's own framework dex (boot-framework.oat of 8149).
The writer keeps the id tables sorted as the format wants and its
read() parses the result back before anything is written.
- Checked against the firmware's own dexdump under qemu-arm: structural
verification passes and the disassembly is the intended program.
Running it needs ashmem, which qemu-user has not: that stays for the
device. mkwifictl.py --check re-reads and compares the checked-in dex.
* checkers: Drop In and earcons in the OpenSL ES backend (builds again on main)
Main grew Drop In (voip_* in audio.h, opus-encoded) and earcons that keep
playing while a condition holds; the checkers backend predated both, and
the stubs list was missing opus' encoder functions, so nothing linked.
- audio_android.c: a voip pstream on the voice stream type
(SL_ANDROID_STREAM_VOICE, its own volume and routing in Android);
play_earcon_while() feeds the system stream as before and drops what is
left of the queue when go() ends instead of draining it (a ringing
timer stopped leaves nothing ringing out).
- devices/checkers/stubs/libopus.syms: the encoder symbols Drop In calls
(tools/mkstubs.sh again); hassmic byte-identical between the firmware
libraries and the stubs.
* checkers: the network switch through WifiService, both at setup and from the page
scripts/device/wifi.sh keeps its contract with wifi.c and the page in both
worlds: the Dots' wpa_supplicant (W) and, on a model with INSTALL=boot,
Android's framework through wifictl.dex (A; Q picks). The framework saves
every change at once, so the try-out is what remains of the Dots'
transaction: the new network goes in and is switched to, and on any failure
it is removed and the old ones enabled again — a reboot lands on the old
ones either way. Android's DHCP is its own (no dhcpcd): the address on the
interface is the lease, and the gateway for the silent-router tell-apart
comes from /proc/net/route (no awk on the Echo), pinged to fill the ARP
cache as the Dots' online() does.
- scripts/wifi-join.sh (the setup step) joins through wifictl for INSTALL=boot:
SSID and passphrase as hex, so nothing of either passes a shell; the
radio on, add, select, then the address.
- deploy.sh pushes the dex next to wifi.sh (trial runs find it too);
install-boot.sh and sysinstall.sh put it on the system partition (644:
data, not a program).
- tools/qrun.sh falls back to toolchain/qemu-arm (devices/checkers/setup.sh
puts one there); install-boot.sh accepts that too.
- tests: fake_wifi_tools.py answers as WifiService would in the same world
the wpa_cli fake serves (add replaces by name, the store is the world,
the address comes with the network, WifiInfo quotes the name, the route
file follows the connection); fake_web_wifi.py runs its whole scenario
list a second time in that world — wrong password, out of reach, no DHCP,
silent router, open and exotic names, replace-not-add, busy, replay —
through the same build/hassmic-host and browser.
* checkers: the guided setup (devices/checkers/setup.sh), untried on a device
scripts/setup.sh offers the model again: its menu entry says untested, and
the dry run walks every step. amonet's fastbrick at the unlock (run in the
foreground: it wants YES typed, and must not be interrupted once it starts),
the rooted boot image at the root step (install-boot.sh --boot-only: root adb
with stock Fire OS has none), the build, the egress lock and the Wi-Fi join
through wifictl.dex before the Echo ever talks to Amazon, the install.
- the files step downloads a pinned qemu-arm into toolchain/ when the PC has
none (tools/qrun.sh and install-boot.sh take it from there), and takes
magiskpolicy out of donut's boot-root.zip — a copy under firmware/donut/
serves, so a PC that set up a Dot downloads nothing extra.
- no wakeword step, as on the Dots now: the settings page's "Download from
Amazon" brings the models once the satellite runs.
- docs: the checkers README's install section starts with the guided way
and says how Wi-Fi joins; docs/re-checkers.md closes the guided-setup,
Wi-Fi-join and CI items; DEVELOPMENT.md names mkwifictl.py; CHANGELOG.
- CI: checkers back in the build matrix (no kernel step: no Wi-Fi motion
module on it).
* checkers: wifictl.dex that would load, checked on the PC; fixes from the review
The first wifictl.dex passed the firmware's dexdump, which checks structure
only; ART would have refused it: int aget/sget opcodes for objects, lit8
opcodes off by 8, 22b operands swapped, parameters read from the low
registers (Dalvik puts them last), java/lang/List, Iterator, BitSet and
java/lang/io/PrintStream, Class.forName("int"), main passing one argument to
two-argument verbs. What it computed was off too: unhex read 2i as i+3,
scan_results piled every row into one, KeyMgmt bit 0 (NONE, not WPA_PSK), the
page's 64-hex PSK saved as a quoted passphrase, list_networks' flags from the
wrong Status values.
- tools/mkwifictl.py: logical registers mapped to Dalvik's frame, the opcodes
and formats right, cls() for primitive parameter types, setAccessible on
the binder proxy's methods, a keys verb (getPrivilegedConfiguredNetworks).
--check runs a type-flow check over every method; --framework=<rootfs>
resolves every reference and reflected call in 8149's boot*.oat dex files,
KeyMgmt.WPA_PSK's value included.
- tests/unit/wifictl_run.py (make unit): a Dalvik interpreter runs the dex
verb by verb against a fake WifiService. qemu-user cannot run the
firmware's ART, so a device is the rest.
- wifi.sh: WifiService changes a saved network of the same name in place, so
the keys are read first and a failed switch puts the old one back instead
of removing the network the Echo was on (fake_web_wifi.py: a mistyped
password for the current network, both worlds).
- bundle.sh: wifictl.dex rides along for INSTALL=boot models (updates ran
wifi.sh from a folder without it).
- devices/checkers/setup.sh: system.transfer.list; firmware, rootfs and qemu
whatever the build mode or a rooted Echo (the root step makes the boot
image from them); donut's boot-root.zip from firmware/donut/, not the name
of checkers' own.
- wifi-join.sh: the PSK made on the PC, add retried while the radio comes
up, select checked, - for an open network.
- audio_android.c: earcons written a slot at a time with go() in between.
- qrun.sh: the system's qemu-arm first, toolchain/qemu-arm the fallback.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: the setup's Wi-Fi join under test; setWifiEnabled(null) read from the firmware
- tests/fake_wifi_join.py (CI): scripts/wifi-join.sh for INSTALL=boot
against a fake adb whose shell runs here, with fake_wifi_tools.py as
wifictl and ifconfig: the PSK made on the PC, add retried while the radio
comes up (the fake answers -1 for as long as told), a wrong password, an
open network, a passphrase of the wrong length, a radio that never comes
up. wifi-join.sh takes WIFI_CONF, WIFI_JOIN_SECS and WIFI_ADD_SECS for it.
- 8149's WifiServiceImpl.setWifiEnabled (wifi-service.jar, under the
firmware's dexdump): the package name only feeds the permission-review
consent dialog, and review is off (no ro.permission_review_required,
framework-res config_permissionReviewRequired false). wifictl's null is
fine (docs/re-checkers.md).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: stock's sounds read straight out of its apps
No earcon folder on this firmware: the sounds are resources of stock's apps,
every one stored uncompressed (aapt leaves audio alone). sounds.c now falls
back from earcon_dir to board.earcon_zip, a table of stock name -> APK entry,
and reads the entry out of the zip itself (end record, central directory,
local header, every offset checked; stored entries only, 4 MB at most): no
install step, nothing copied, an own file in earcon_dir still wins.
checkers' table: the wake sound from SpeechInteractionManager (res/7E.mp3 =
ful_ui_wakesound_hybrid, its shrunk names mapped back through
resources.arsc), privacy and volume from KnightSystemUI, Bluetooth from
KnightSettings, the five Drop In sounds from the comms app. 12 of 13: no setup
beacon anywhere, Identify keeps the built-in tone.
tests/unit/sounds_test.c (make unit): a synthetic APK (stored WAV, a deflated
one refused, a missing entry, earcon_dir winning), clean under ASan/UBSan;
with the firmware unpacked, every entry of checkers' table decodes from the
real APKs (all 48 kHz, 0.34 to 5.5 s).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Volume behind audio.h; checkers: a gain per player, Android's own at full, the keys grabbed
main.c drove the Dots' mixer directly (audio_manager_*_prop); now it asks the
audio backend: vol_read/vol_write for VOL_MAIN, VOL_TTS and VOL_MUTE. The
mixer backend runs the same tools as before (core_spawn: still without
waiting); the PC keeps them in memory; OpenSL ES (checkers) sets a gain on
each player (SLVolumeItf, 0.4 dB per step, 0 silent; replies on VOL_TTS, the
rest on VOL_MAIN), applied before a player's first sample and kept in
state/volume.
Android's own stream volumes would take level off on top: wifictl.dex gets
a volume-max verb (IAudioService getStreamMaxVolume/setStreamVolume for
voice call, system and music, as package "root", which 8149's AudioService
notes with AppOps for uid 0; Android 7.1's media_cmd has no volume
subcommand), run by main.sh at every satellite start on INSTALL=boot models;
--framework checks the signatures, wifictl_run.py runs it against a fake
AudioService. board.grab_keys (checkers): the keypad EVIOCGRAB'd, else
PhoneWindowManager turns its volume too and shows its panel.
Host tests unchanged in result (ESPHome, web, Drop In, Sendspin); every
model builds without warnings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Front end behind audio.h; checkers reaches it through audiosignalprocessor; input devices by name
main.c's three LIPC calls to the front end (listening mode, the wake word's
energies for arbitration, the end of a command) are afe_listening,
afe_arbitration and afe_stream_stopped in audio.h now: the same LIPC tools in
audio_mixer.c, nothing on the PC.
checkers has no LIPC: its libasp runs in the audio HAL behind the binder
service audiosignalprocessor, transaction 3 = command(cmd, in, out).
afe_parcel.c builds the parcel as "service call ... i32" words for the
firmware's own /system/bin/service and reads the reply back out of Android
7's Parcel/HexDump print (format strings checked in its libbinder; the ASCII
column ignored, a quote in it included). Commands: SET_LISTENING_MODE 146 and
REQUEST_ARBITRATION_JSON 23 (aspclient's constants), NOTIFY_ASR_STREAM_STOPPED
14 and SET_WAKEWORD_METADATA 114 (donut's libgenericaspclient.so pairs the
LIPC names with them; checkers' libasp command switch sends 14 to "Stop AFE
Diag" and 114 to the size check that names SET_WAKEWORD_METADATA).
tests/unit/afe_parcel_test.c in make unit, clean under ASan/UBSan.
buttons.c opens "name:<input name>" by EVIOCGNAME; checkers' keypad is
name:gpio-keys and its privacy input name:amazon-gating (the kernel's DTBs:
no label on gpio-keys, the gating driver's own "mute" device) instead of an
event number that depends on the probe order.
fake_ha_arbitration, make unit pass; every model builds without warnings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Equalizer behind audio.h; checkers: the user EQ through audiosignalprocessor
core_eq/core_set_eq ask afe_eq_get/afe_eq_set (audio.h): LIPC
GET/SET_USER_EQ_INFO on the Dots as before, nothing on the PC, and on checkers
command 29 / 21 of audiosignalprocessor (donut's libgenericaspclient.so pairs
those LIPC names with them, ADJUST 28 and RESET 30 beside). checkers' libasp
has the UserEq code and its JSON, behind a vtable, so its handler was not
traced: the set sends the JSON as LIPC does, the get uses
REQUEST_ARBITRATION_JSON's convention (int32 reply size in, JSON out).
Marked [~] in docs/re-checkers.md until a device answers.
fake_ha_esphome passes (the EQ entities included); every model builds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: both volume keys together stand in for the action button
The Echo Show 5 has no action button, and the settings page's login, adb
over Wi-Fi, Improv's authorization and answering a Drop In all wait for
one. board.action_combo: both volume keys pressed within 400 ms of each
other and let go within a second are its press (buttons.c); held 2 s they
still pair for arbitration, one after the other they are volume steps.
The hello says so ("action":"volume_keys"), and the page words its texts for
the Echo they are about (act() in web/app.js: the login, adb, help texts, a
login on another Echo by that one's hello); the factory reset's "hold the
action button 10 s" is left out there.
tests/unit/buttons_test.c (make unit, ASan/UBSan clean): a chord either way
round, one key after the other, presses 600 ms apart, the 2 s pairing hold
with key repeat, a slow chord. fake_web passes; every model builds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: root boot image that works on a real Echo Show 5
The first device (a tester's) showed what the PC could not:
- 8149's own adbd is a user build: it drops to shell whatever ro.secure,
service.adb.root or `fastboot oem flags 61` say. The XDA image's adbd
(CyanogenMod's, static, ADBD in device.conf) goes by ro.secure; with it
in 8149's ramdisk adb is root in u:r:su:s0 (mkbootroot.py --adbd). The
setup takes it out of checkers' own boot-root.zip, and picks up a
browser's "boot-root (1).zip" (donut's has the same name).
- kaeru 2.0.0 leaves the RTC boot-to-fastboot flag set after
`adb reboot bootloader`: every `fastboot reboot` lands in fastboot again.
install-boot.sh boots with `fastboot continue` and says to replug the
power when it is still in fastboot.
- The stock image's certificate page names its sha256; mkbootroot.py leaves
it out, as the XDA image does.
- setup.sh: the root step and checkers' install run in the foreground, so
install-boot.sh's hints show; a booted Echo with adb as shell gets its
boot image replaced from there instead of waiting for TWRP.
- README: how the firmware .bin gets into TWRP whole; hashes per zlib.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: boot a flashed image from TWRP; continue past a fastboot stop
- install-boot.sh: when the boot partition holds the image already and the
Echo sits in TWRP, boot it through hacked fastboot and `fastboot continue`
(it waited 10 min for a boot that never came). After the install's
reboot, a stop in fastboot (kaeru keeps the RTC flag) is continued too.
- setup.sh: refuse a path with a space in it (make splits there; a tester's
copy "echo-dot-assist-checkers (1)" failed in the build).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* setup: the space check on the physical path, as make sees it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: main's per-model additions (speaker gain, wake sound removal, buttons, light ring)
Rebased on main; what main added per model, brought to the Echo Show 5:
- Speaker gain: the RT5616's line out "OUT Playback Volume" feeds the
speaker amplifier. From checkers' own kernel (soc_mixer_control and
TLV, decompressed from boot.img): reg 0x03, inverted, 0..39 =
-46.5..+12 dB, 1.5 dB a step; the HAL's /system/etc/audio_device.xml
sets 29 (-3 dB) among its initial settings, nothing else names it.
board.speaker_gain_db: steps per that many dB, for steps that are not
a whole dB (2 per 3 here; a whole dB takes the nearest step). Other
models unchanged; spkgain_test gets the Show's shape.
- Wake sound removal: audio_android.c sets audio_earcon_started after
the first Enqueue (the player is PLAYING from s_open on).
- Buttons: the volume-key chord under main's rule (volume steps on
release, a pair is no step and no event); its press is Home
Assistant's "action" event. buttons_test updated.
- Light ring: main.sh leds() skips where /system/etc/led-resources is
missing (no ledcontroller).
- Drop In blueprint: default_name "Echo Show 5", the slug of the
project's model (blueprint_dropin checks it), and echo-show-5 among
the blueprint's known models.
- install-boot.sh no longer writes NAME (the Echo names itself).
make unit, every model with and without STUBS=1 (mkstubs: identical),
and the PC suites pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* main.sh: the firewall start no longer loops on a dead process's cmdline
The previous firewall watcher was found by reading every /proc/*/cmdline
with a read -d '' loop. On the Echo Show it spun at 100 % CPU on a
process that had exited between the open and the read, so ota_watch
never ran: an update passed its self test and was never promoted, and
root's other requests (reboot, Wi-Fi, artifacts) went unanswered. The
Echo 2's tr did the same before (2026-09-30). Now one read of comm
(only shells can be the watcher) and one dd read of their cmdline,
which ends whatever the read returns.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* avahi: runs without D-Bus and without a terminal
On the Echo Show there was no mDNS at all, so Home Assistant could not
find the Echo again after an address change:
- D-Bus runs but its policy keeps org.freedesktop.Avahi from root, and
avahi with D-Bus required exits ("Failed to acquire D-Bus name").
avahi_start writes enable-dbus=warn: the service file is announced
without D-Bus; where D-Bus works (the Dots) it is used as before.
- Started without a controlling terminal (main.sh, run.sh), avahi died
about two seconds in, its parent shell with it; from an adb shell it
lived. --no-proc-title (avahi 0.6.31, the Dots' binary too) leaves
argv and the environment alone, and it stays up.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers boot image: no adb over Wi-Fi, no boot chime
mkbootroot.py comments out two lines of stock's init.checkers.rc (any
init.*.rc that has them, RC_OUT):
- setprop service.adb.tcp.port 5555 (on boot): with the image's root
adb and no authentication, every boot opened a root shell to the
network until lockdown.sh closed it. adb over Wi-Fi is hassmic's to
open (adb_gate).
- start bootsound_anim: Amazon's boot chime, played at the media
stream's volume, which on a satellite is not Amazon's to pick.
New image sha256 03253eed... (README); install-boot.sh flashes it over
an older one, as it compares the partition with what it built.
lockdown.sh closing adb over Wi-Fi restarts adbd, and init kills
adbd's process group with it, the setup's adb shell that runs
lockdown.sh among them ("Service 'adbd' killed by signal 9 ... killing
any children"): the setup's lockdown step failed without a word. For an
Echo still on the older image the step now closes it first and waits
for adb.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers setup: TWRP's read-only screen, and 8149's system partition
- amonet's TWRP asks "Keep System Read only?" at every start; the setup
says to keep it read only (nothing writes /system from TWRP, and a
system TWRP mounted read-write fails the stock boot image's dm-verity,
the way back while /system is untouched). Answering restarts TWRP's
USB: install-boot.sh waits up to 2 min for adb instead of checking
once, and its failure names adb's state and the screen.
- A step "System partition" between the unlock and the root boot image:
the first Echo Show came out of the unlock with build 0013054618500,
and the root boot image is 8149's. Only system is written, from the
image on the PC (tools/sdat2img.py of system.new.dat, reproducible,
SYSTEM_IMG_SHA256, exactly the partition's 3253731328 bytes), never
with twrp install of the .bin, whose updater-script also writes lk,
tee, the preloader and an MBR. It goes in 64 MB pieces: each compared
on the Echo first, pushed into TWRP's /tmp, written with toybox dd
(TWRP's own dd refuses conv= and truncates after a seek), the page
cache dropped and read back. adb exec-in into dd stalled for good at
2.94 of 3.25 GB (TWRP runs it on a pty); a cut-short write goes on
where it stopped.
- The partition counts as 8149's only by its digest, in the step and in
install-boot.sh: build.prop lies in the first pieces, and after the
stalled write it said 8149 while directories further in were not.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers audio: Android's own volume, buffers counted from callbacks, a Bluetooth stream
On the first Echo Show (audio_android.c, OpenSL ES):
- The volume is the music stream's index, set through IAudioService
with the firmware's service tool (setStreamVolume = transaction 3,
getStreamMaxVolume = 10, from IAudioService$Stub's constants in 8149's
boot oat). Fire OS aliases system, voice call and TTS to music, so
every player is on it and it is the one volume. The call runs on a
thread of its own (vol_write is called under core_lock); 0..100 stays
in state/volume and is pushed again at start; a void reply counts as
success. The player's own volume (SLVolumeItf) is not used: Amazon's
stack put a track back to 1.0 some 70 ms in ("TrackVolumeChanged"),
so sounds began at our level and jumped to full. main.sh no longer
forces Android's volumes to their maximum.
- GetPosition stayed at 0 for these players, so every sound counted as
never played. Queued is now what waits in the slots (from the buffer
queue's callbacks); s_drained adds 120 ms for AudioTrack and the HAL
only where a sound's end matters. The earcon wait also ends at the
sound's length + 1 s whatever the player says: it waited for ever
after the first sound, and every later one queued behind it.
- bt_open/bt_write: a player for the Bluetooth stream (a phone playing
to the Echo) beside music; it was -1, so a2dp.c dropped everything.
docs/re-checkers.md: Music Assistant plays, in sync.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers buttons: the mute key by its real name, and grabbed
The gating driver's input device is "gating" (getevent -il,
/dev/input/event0), not "amazon-gating": the mute button was caught
only by the once-a-second poll of the latch. It is grabbed like the
keypad now: it reports KEY_POWER, and Android's framework played a
stock privacy sound for every press (a fallback ringtone once System UI
was gone, at the ring stream's level: the "mute sound at full volume").
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: Amazon's software off the device, hassmic's own home screen
pm disable does not control Amazon's apps on Fire OS: System UI is
enabled again at every boot, persistent apps start at boot disabled or
not (amazon.speech.sim, whad, NativeAccessorProxyServices ran with
enabled=2), and without Alexa's speech service much of the rest crashed
in "has stopped" dialogs. System UI also played stock's sounds for
other apps (its NotificationPlayer: the privacy sound over ours) and
threw on purpose without amazon.speech.sim.
- sysinstall.sh takes the folders of the model's STOCK_APPS_OUT off the
partition into /system/hassmic-removed (a rename; PackageManager does
not look there) at install and with every update that becomes the
factory copy, puts back any no longer listed, and all at uninstall.
checkers: every Amazon app folder of /system/app and priv-app
(pm list packages -f: com.amazon.*, amazon.*, Ivona TTS, Arcus, the
usage stats proxy, Sidewalk, System UI, Amazon's Settings), but not
the shared-library providers declared in /system/etc/permissions
(amazon.jackson-19, DeviceMessagingAndroid[Internal]SDK, MetricsApi,
...): with those gone too FusedLocation (in system_server) and
Settings failed and system_server restarted in a loop. Stay: Android's
own packages, amazon.fireos and the vendor Wi-Fi profile manager.
- tools/mkhome.py -> scripts/device/hassmic-home.apk (HOME_APK): an APK
without code declaring android.app.Activity as a black, full-screen,
direct boot aware MAIN/HOME activity, binary manifest and v1
signature written by the tool. Android needs a home before it
finishes booting, and Amazon's Settings, whose FallbackHome was the
last one, cannot start without Amazon's account apps. Without direct
boot awareness: "No home screen found" and no sys.boot_completed.
sysinstall.sh installs it in /system/app/HassmicHome, the bundle and
install-boot.sh carry it.
- alexa-off.sh: package/class entries disable one component (Settings'
SettingsInitializationHelperService); with a setup wizard disabled it
sets device_provisioned and user_setup_complete, and device.conf's
ANDROID_SETTINGS ("namespace/key=value"), old values recorded for
alexa-on.sh; boot.sh and stock-online count those as something to
undo. Amazon's apps in /data/app (a4b, csm) go through ALEXA_PACKAGES.
The setup runs it at the lockdown step, before Wi-Fi: a wiped Fire OS
showed Amazon's setup wizard on the screen.
- sounds.c looks for an earcon APK under /system/hassmic-removed when
it is not at its path.
Result on the tester's Echo: boot in 30 s, one Amazon process left
(amazonfiled, native), about 550 MB of 1 GB free, no dialogs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: the screen off, a wake lock for the satellite
The black home screen kept the backlight at 238 of 255 with stock's
24-day timeout. ANDROID_SETTINGS sets screen_off_timeout to 15 s. With
the screen off Android lets the SoC suspend once no wake lock is held
(/sys/power/autosleep), and the satellite must keep listening: root's
main.sh holds the kernel wake lock WAKE_LOCK while it runs, alexa-on.sh
lets go. The capture keeps running with the screen asleep.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: Bluetooth is hassmic's
With Android's stack off /dev/stpbt (IBluetoothManager.disable), hciscan
on the Echo Show: HCI reset, address, version, 315 LE adverts in 8 s.
The MT7668 behind btmtksdio speaks H4 as the Dots' combo chips do, so
ble.c and a2dp.c take it as they are: "controller ready, ACL 32 x 251",
the A2DP sink with SBC, AAC, aptX HD and aptX, a Pixel paired and
played. app/Bluetooth joins STOCK_APPS_OUT, global/bluetooth_on=0
ANDROID_SETTINGS, DEFAULT_ARGS loses -B. Open: the Bluetooth speaker
(Echo to speaker), for which the mix would have to come back through
Android's remote submix.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs: Bluetooth announcements need the device to be allowed Home Assistant actions
Only donut's README said so. The guide's phone section, the settings
page's help for "Bluetooth announcements" and the setup's last screen
("Add it in Home Assistant", one tick away) now say it too; without it
a phone connects with the chime only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: plays on a Bluetooth speaker
No remote submix needed: 8149 has AOSP N's audio.a2dp.default.so and
the a2dp module in its audio policy, so btout.c serves the HAL's
abstract sockets as on the Dots (audioserver connects to them), and the
route becomes the backend's (audio.h audio_a2dp_*): the Dots' mixer by
LIPC A2DPSourceConnect plus btmanagerd's AIPC service, Android's
AudioPolicy by media.audio_policy setDeviceConnectionState (1) and
getDeviceConnectionState (2), with C strings built by afe_parcel.c's new
svc_cstr. The volume is set again after each move (AudioService keeps
one per device), a route left by an earlier run is taken back at start
(state/a2dp-route), and one lost to an audioserver restart is moved
again (1.6 s from the kill). Players opened while the route moves wait
for it: sounds started as the speaker went away were moved mid-sound
to the Echo's speaker, with a pop. Keep-awake also runs while
AudioFlinger has the output in standby.
On the tester's Echo with a PC as the speaker: heard clearly, back on
the Echo without a pop, moves in 410-520 ms.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs: the Echo Show 5 as it runs on the tester's device
What the docs said was open or untested and is seen working on the
tester's Echo Show (installed with the guided setup, fixed along the
way): first run, recording as system, the front end's replies and
wake word energies, Android's volume, the equalizer's get and set, the
input devices by their real names ("gating"), earcons, the firewall
with netd running, the setup's Wi-Fi join. README marks the model as
working, setup.sh drops UNTESTED. Also the README's "Each model" line
gets back the E that ecdc40d lost.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Bluetooth speakers start at the Echo's volume, not their own
A speaker with AVRCP absolute volume used to take over at the level it
reported: a PC (PipeWire) said 100 % and then ignored the Echo's
volume, so the Echo played at full scale into a speaker at full
volume. Now the Echo sets the speaker to its own volume first and keeps
scaling the sound itself until the speaker's answer confirms that
level (A_PENDING); a refusal, another value or no answer within 3 s
leave the volume with the Echo, as stock had it for every speaker.
On Android the saved volume (the full scale the mixer played at for
such a speaker) is no longer pushed at start before the core has put
the Echo's own back: the core's first write sets Android's index,
changed or not.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: the light ring as a band along the bottom of the screen
The Echo Show has no LED ring; stock drew Alexa's attention as a 10 px
line over the app in front. Ours keeps the band for itself so any app
can be the screen's UI: ringbar.dex (tools/mkringbar.py on a Dalvik
assembler now shared with mkwifictl.py, tools/dexasm.py) runs as
app_process, sets the window manager's overscan for the band and puts
a SurfaceFlinger layer of its own over it, drawing what hassmic sends.
ring_band.c is a second ring.h (RING in device.mk): every pattern of
the core as the Dots' ring unrolled, 12 virtual LEDs across the width
with the talker in the middle, and Home Assistant's "Light ring" light.
Setting "Light band" (0..40 px, default 10). Screen power as stock's:
a pattern wakes the screen (IPowerManager), timeout 5 min, 1 min muted
or in Do not disturb; uninstall gives the overscan back.
Not turned towards the talker: the front end's beam events (an
IAudioEventListener on audiosignalprocessor) reached a listener on the
device, but only 4 of 7 beams are ever sent and they switched several
times a second wherever the talker stood (docs/re-checkers.md).
Seen on the tester's Echo: the band at 960 x 10, apps at 960 x 470.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: light sensor and Wi-Fi motion
Light sensor: Amazon's stk3x1x driver puts a lux attribute on the
platform driver als_ps (/sys/bus/platform/drivers/als_ps/lux): an I2C
read of the ALS data at every read, scaled by the factory calibration
in idme, the same value Android's light sensor reports (93-94 lux on
the Echo). Home Assistant gets Illuminance; LED auto brightness is
only offered where an engine follows the sensor (core_led_has_auto):
ledcontroller's, which the band does not have. Two of the driver's
attributes are not readings: cali_Light recalibrates and saves
/data/als_cal_data.bin, ir leaves ALS stopped until a reboot
(docs/re-checkers.md).
Wi-Fi motion: hassmic_rcpi4m.c builds for 32-bit ARM too. checkers'
gen4m driver calls nicRxFillRFB at nicRxProcessDataPacket+0x64;
SW_RFB_T has ucGroupVLD at +16 and prRxStatusGroup3 at +32 with 4-byte
pointers. The bl is rewritten by the kernel's patch_text (built for
KGDB, found through kallsyms). Built against kernel.org 4.9.77 with the
IKCONFIG and arm-eabi-4.8 (Amazon's Linaro GCC 6.3 is no longer
published); vermagic and struct module match the kernel's. On the
Echo: hooked, RCPI live, Home Assistant's motion sensor went on and off.
CI builds it (kernel cache entry for checkers).
alexa-off.sh: the p2p group removal's wpa_cli once never returned on
the Echo Show, and the satellite's start with it: timeout 5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* checkers: Amazon downloads through the fireos-dha service
The Show has no libacehal_dha.so: its attestation key sits behind the binder
service amazon.security.dha (version 1, RSA-2048, PSS over the given digest,
as the Dots' HAL). dha.c asks it through service call as system and builds
the drvV1 token as checkers' Java MAP does (padded n/mac, its key order,
cpuid from /proc/cpuinfo, UTC). dha_jwt() takes the registration's serial.
afe_parcel.c is common now (svc_blob). Tested on the Echo against amazon.de:
registered, echo de-DE and aed de-DE installed; whisper-static is refused
for the Show's device type (403 not allowlisted).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* crown: Echo Show 8 1st gen, at the level checkers has (#33)
* crown: Echo Show 8 1st gen, at the level checkers has
The Show 8 is the same platform as the Show 5: devices/crown (board, device.conf, rc, SELinux rules, kernel config,
stubs, guided setup, unlock notes), CI builds it, docs/re-crown.md has what differs from checkers.
Crown-specific fixes that came with it, all shared with the other Android models:
- Amazon downloads: dha.c builds drvV3 from the DHA service's version 2 (certificate chain's first certificate)
- the wake blip is not clipped by the speaker opening (a cold output gets a 350 ms lead-in)
- the mute latch that reads "on" at power-on is shown, not announced (mute_latch)
- alexa-off.sh asks Android for its packages once instead of once per package (36 s -> 14 s at boot)
- TIMEZONE in hassmic.conf and the setup's question; ADB_WIFI asked in the setup
- the firewall admits ping from the local network
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* crown: speaker gain below stock (down to -6 dB), and restart hassmic only once it has stopped
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* crown: a factory reset also forgets a Wi-Fi network that was saved by another user
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* crown: the guided setup's closing notes match what works (screen, Download from Amazon)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* Echo Show: a wake sound of our own, a soft two-note chime, where the firmware has none
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* setup.sh: stop when more than one device is on adb, and say how to disconnect the others
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* crown: the guided setup downloads the kernel sources and compiler for Wi-Fi motion
Without them make leaves hassmic_rcpi4m.ko out and the installed Echo has no Wi-Fi motion setting.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* Wake sound removal: the echo looked for after the Echo Show's lead-in
The 350 ms of silence queued in front of a sound on a cold output reached earsup.c as part of the echo's delay
(85 ms + 350 > D_MAX 400 ms), so the search missed it. audio_earcon_started now says how much lead-in there was.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* setup.sh: stop only for a second USB device; comments back above their functions
Devices on adb over Wi-Fi were already left alone (USB_ONLY, adb -d); a second USB device is what makes adb -d fail.
checkers asks for the time zone and stops on a failed install as crown does; crown's XDA thread by its link.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* crown docs: one status everywhere, unlock steps in our words; ping, TIMEZONE and the chime documented
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* crown: only the port; the changes for every model go to their own PRs
Taken out of this PR, listed in an issue to come back on their own: the guided setup's one-adb-device check, ping
from the local network, TIMEZONE and the setup's time zone and adb over Wi-Fi questions, restart_hassmic, alexa-off.sh's
single package listing, and the synthesized wake chime (the Echo Show plays the blip again). Their docs with them.
Kept, because crown needs them: the DHA version 2 token, the speaker gain below stock, the cold-output lead-in, the mute
latch shown quietly at start and the factory reset's Wi-Fi forget.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* wifi.sh: the gateway's address without mksh's substrings
${g:6:2} and 16# are mksh's; CI runs wifi.sh under dash ("Bad substitution"), so the WifiService pass of
fake_web_wifi.py never found the router. Bytes by sed, numbers by printf's 0x, which dash, bash and toybox take.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* crown docs: the guided setup tried on an Echo Show 8; works in the README's table
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Julian Imhof <julianimhof00@gmail.com>
* athena: Echo Show 8 2nd gen (Android 9, MT8183) [stacked on #33] (#34)
* athena: Echo Show 8 2nd gen (Android 9, MT8183)
A different platform from crown: Android 9 with Treble and enforcing SELinux, rooted in place by saiyaku-athena's zip
(INSTALL=running: install-system.sh writes /system/hassmic and patches the vendor policy), the front end inside the audio
HAL (OpenSL ES, as crown), a TAS5805m amplifier, a TCS3400 light sensor. devices/athena, docs/re-athena.md.
What the platform needed:
- the libc's accept/accept4/connect fail with EBADF (netd's fwmarkd denied on su sockets: sepolicy rule; net_accept,
net_connect_fd and libcurl's already-connected socket stay as workarounds)
- Wi-Fi through Android 9's IWifiManager (package name argument, ParceledListSlice) in wifictl.dex, run as uid system
- ringbar.dex builds the SurfaceControl through its Builder on SDK >= 26
- IAudioService's transaction numbers differ on Android 9: setStreamVolume 7, getStreamMaxVolume 14 (the volume keys
and Music Assistant's volume did nothing before)
- the light sensor's lux from the raw channels as stock's virtual_als does (lux.h)
- speaker gain on the TAS5805m's digital volume, up to +9 dB (listened to: a rap track's bass clips above)
- Sendspin: unpaired sessions are closed when "Music Assistant without pairing" changes
- Drop In: a quiet room's noise no longer counts as the far end talking (NEAR_MIN_DB, far_voice)
- "Download from Amazon" through the fireosdhaservice binder service
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* athena: the mute button is answered at the press, not after the driver's second
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* athena: --uninstall restores the SELinux policy in /vendor and reaches its reboot
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* athena: the guided setup unlocks (saiyaku) and roots (boot-root in TWRP)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* docs: the Show 8's action button is a tap of both volume keys, no hold-to-reset
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* athena: Wi-Fi motion (hassmic_rcpi4m on the 4.4.146 kernel)
The driver is named gen2 (wlan_mt76x3_sdio) but its receive path is gen4m's, so hassmic_rcpi4m.c runs with its 32-bit
defaults. The kernel has no patch_text and read-only module text: the module falls back to set_memory_rw (kallsyms) and a
write under stop_machine. CONFIG_MODVERSIONS is on: devices/athena/Module.symvers carries the kernel's CRCs (read out of
boot.img's Image), which the Makefile copies into the kernel tree. Tested on a Show 8 2nd gen: RCPI 120 for unicast
(0x14009), 129 for broadcasts, the motion sensor switched on when someone walked past.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* athena: the guided setup downloads the kernel sources and compiler for Wi-Fi motion
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* CI: athena builds its Wi-Fi motion module (kernel sources and compiler in the matrix)
The build job left out hassmic_rcpi4m.ko for lack of toolchain/linux-4.4.146 and the check that a bundle
must not lose its module failed.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* athena: only the port; the changes for every model go to their own PRs
Taken out of this PR, to come back on their own (as issue 45 did for crown's): the system-call bypass of the libc's
accept()/connect() (netio.h net_accept/net_connect_fd, net.c net_open_connected, libcurl's already-connected socket in
davs.c and update.c: under __ANDROID__ it changed every model, and athena's cause, netd denied on su sockets, is fixed by
its sepolicy.rules), the 200 ms cold-output lead-in and state/lead_ms (checkers and crown share audio_android.c: back to
350), the Drop In gate (NEAR_MIN_DB, far_voice, dropin_far_level and its log line), closing idle unpaired Sendspin
sessions, the blueprint's "drop into"/"drop it in" sentences, the GUIDE's factory-reset note for every Show, and
docs/known-issues.md (its athena facts are in docs/re-athena.md now). Their docs with them, and the CHANGELOG entry for
restart_hassmic, which is not in this tree.
Kept, because athena needs them: INSTALL=running and SEPOLICY_FILE, wifictl.dex and ringbar.dex for Android 9, the
IAudioService numbers, fireosdhaservice, the TCS3400 lux, speaker_gain_limit, the early mute press, Wi-Fi motion, and
the blueprint's model slug.
Fixed on the way:
- sysinstall.sh: conf_get's fallback to the installed device.conf never ran (mksh ends the subshell when "." is given a
missing file: checked with athena's own sh under qemu), and /vendor is remounted only when the policy is written, not
for every promoted update
- Makefile: Module.symvers is copied at each build of the module, so a changed list reaches it
- ring_band.c: the SDK is read before the fork (a property lookup in the child of a threaded process can deadlock)
- athena's setup.sh: boot-root.zip is needed whenever the root step flashes it, the policy tool is unpacked again
before the install, locals in step_network; device.conf: WPA_SOCKETS is the firmware's /data/vendor/wifi/wpa/sockets,
ambienthome, paladin and whad disabled as on crown
- tests/unit/buttons_privacy_test.c for the early mute press; the CI step name back to what fake_wifi_join.py covers
- docs: one status everywhere (README, devices/README, the model's page, re-athena.md, PLAN, CHANGELOG), unlock.md in
our words, the firmware's FTVDB link, the GUIDE's wake sound and speaker gain lines name the two Show 8s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Julian Imhof <julianimhof00@gmail.com>
* cronos: Echo Show 5 2nd gen (2021), plus setup fixes for the Echo Show models (#65)
* cronos: Echo Show 5 2nd gen (2021), installed on one; setup fixes for Ubuntu 24.04+ and the Raspberry Pi
The 2021 Show 5 runs checkers' platform and Fire OS build (NS65741/8149, its own image): devices/cronos is checkers'
with athena's mute driver (gpio-privacy) and the speaker amplifier of the board revision. One firmware serves boards
with RT5616/RT5616E, TAS5805M or MAX98396, so board.h gets speaker_gain_alt and spkgain.c takes the first control card 0
has (MAX98396: Speaker Volume A, +4..+21 dB in 1 dB steps by the kernel's TLV, capped at +6 dB). Stubs, probe files,
kconfig, pins of the firmware and both XDA zips (amonet's lk/tz are 8149's, the boot-root's adbd is checkers'); the
setup stops for a bootloader older than 8149's. docs/re-cronos.md has what differs and the first install.
Installed with the guided setup from a Raspberry Pi 4 on Ubuntu 26.04, which found, fixed here for every model:
- tools/qrun.sh: Ubuntu 24.04+ refuses users a namespace; qemu runs without one while the PIDs are low, else it says
what to do; install-boot.sh shows why the policy patch failed; the setup warns up front and takes qemu-arm from the
package manager where its x86_64 download would not run
- udev: the rules give the Echos to plugdev too (ssh sessions), cover the Show's adb and fastboot ids, and the Show
setups install them
- wifi-join.sh: a network saved before by another user is changed as the system user (test in fake_wifi_join.py)
- the Drop In blueprint knows the new model
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* cronos: only the port; the changes for every model go to their own PRs
Taken out of this PR, listed in issue #45 to come back on their own: tools/qrun.sh running qemu without a PID
namespace where Ubuntu 24.04+ refuses users one (every model's PC side; install-boot.sh's qrun.log and the setup's
warning with it), qemu-arm from the package manager on a PC that is not x86_64 (scripts/lib/setup.sh qemu_arm, for
every Show), the udev rules' plugdev group for setups over ssh (every model), and the udev step in checkers' and
crown's setups. Their docs with them (CLAUDE.md, DEVELOPMENT.md, FINDINGS.md, the CHANGELOG entries).
Kept, because cronos needs them: board.speaker_gain_alt and spkgain.c, wifi-join.sh's fallback to the system user
(the first cronos hit it), the Shows' fastboot id in the udev rules and cronos' udev step, install-boot.sh's messages
naming the model's own files, and the blueprint's model slug.
Fixed on the way: the setup's bootloader check stopped with "older than 6.5.7.0" when it could not read the version
at all (no fastboot answer, another format); it says so now. The docs say what the setup needs on a Raspberry Pi
until those PRs are in.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Julian Imhof <julianimhof00@gmail.com>
* Rebased onto main: the Echo Show models build and test again
What main added since the branch point and the Show models did not have yet:
- audio_android.c: audio_music_gain/audio_tts_gain/audio_call_gain (separate
volumes, #32), our PCM scaled before the player gets it as audio_mixer.c does
(not the player's volume: Amazon's stack puts a track back to 1.0).
- ring_band.c: main's ring.h (ring_start's reloaded callback, designs' slots,
per-LED layer, rotation, ring_check): none of it on the band, so no slots,
nothing to install, ring_per_led() 0.
- Makefile: the Show models' unit tests as targets of their own, as main split
the rest (make -j unit).
Every model builds with STUBS=1; tests/run.py passes (30 of 30).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Echo Show: review fixes after the rebase onto main
- a2dp.c: a speaker with absolute volume is asked for out_volume_now() (the
loudest kind while the volumes are separate), not the music's: it jumped
there on the next upkeep, replies quiet meanwhile.
- audio_android.c: state/volume and the A2DP route through statefile.c
(#46: a hard reset left an empty file); state/volume written on the volume
thread, since vol_write runs under core_lock and the fsyncs take tens of ms.
- settings.c: "Light ring rotation" only where the ring is LEDs; the band has
none to turn (ring_rotation stays 0).
- ring.js: no designs section, and no designs in the copy, where the ring has
no animations to replace (ring_nslots 0 on the band; Apply could only fail).
- re-checkers.md: separate volumes on Android scale by the Echo Dot 2's curve;
the Show's own is not measured (open).
- CHANGELOG.md: the branch's date sections had come out below main's as a
second run (2026-10-26 and -17 twice); merged by date, newest first.
Every model builds with STUBS=1; tests/run.py passes (30 of 30).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Echo Show: light ring designs on the band, the Show's own volume curve
Light band (ring_band.c):
- The settings page's designs show on the band: ring.c's slot ids and order,
drawn live by the band thread, flattened (band position p = LED p + 5, the
talker's pair in the middle), never turned. Apply needs no root there
(ring_designs_live): state/ring-applied and ring-installed written, the
band reloads; only patterns whose design changed start over.
- ring_stock: the band's own patterns as .animation files for the page
(frames cut where the picture jumps, else every 40 ms).
- hassmic_assist_NN: the replies' own volume in cyan, as on the Dots.
- Status JSON: band, band_on (the page says when "Light band" is 0).
- The band's height comes from state/config (and a pending preset) before
ring_start (settings_peek); settings_load leaves it alone: no flash with
"Light band" 0, no flip when a preset changes it.
- Renderer: argv and environment made before the fork, execve, pipes
close-on-exec, every other descriptor closed before exec; a still
picture is re-sent when the LED brightness changes, a still light no
longer wakes the thread 30 times a second; no 30 s sleep after a failed
start; a failed thread start is tried again.
Settings page (web/ring.js): the band drawn as the Show shows it; the
designer is one editor with a Ring / Band switch on its stage; its Mirror,
Move/Turn, Spin/Run, Rainbow and hit test as top-level helpers.
Volume:
- board.volume_curve (volcurve.c board_vol_db, the Dot 2's where none):
checkers measured 2026-10-27 with tools/vol-curve.py and slplay (an Echo
Dot 2's micRaw beside it), a point every 5 volume points.
- The volume keys' tone plays at the volume they moved (linked kinds
included), not at the sounds' own; at 0 the lowest step's.
- led_auto/led_level atomic (read from the band's and protocols' threads).
- settings: a line longer than the buffer is skipped whole.
Tests: ring_band_test (designs, restart on the same state, Apply that
cannot write, brightness, renderer descriptors), volcurve_test per model,
band_map_test (page vs band, pixel for pixel, and the designer's band
helpers), fake_ha_volumes (the keys' tone, a wait that flaked under load).
Node tests fail in CI without node.
Every model builds with STUBS=1; make unit and tests/run.py pass (30 of
30); on the tester's Echo Show 5: self test, band, designs page.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Tests: wait for hassmic's log lines instead of reading them once
hassmic's stderr reaches the log file through its reader process (clock.c),
so a line can land after the event the test saw: CI failed arb-join
("tags: joined without permission": arb.c adopt() saves state/arbitration
before it logs the join) and sendspin ("the player speaks the server's
dialect": read as soon as the server had the client), both lines present
in the log moments later. Those checks, and the transcript "Stop." one
read right after va.stopped, now wait for the line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: ZCode <noreply@z.ai>
Co-authored-by: baudneo <86508179+baudneo@users.noreply.github.com>
Co-authored-by: taucher4000 <martin@familie-boehme.eu>
Gamer92000
added a commit
that referenced
this pull request
Oct 27, 2026
- Drop In: an empty room's noise no longer opens the sending gate (NEAR_MIN_DB -58 dBFS), and the far end counts as
talking only well over its own floor (far_voice); the wake word works in a call to an empty room again.
fake_ha_dropin.py: a quiet bedroom (-56.7 dBFS sent with the old gate, -73.1 now)
- Sendspin: switching "Music Assistant without pairing" closes the unpaired sessions that wait without a role, so
Music Assistant redials and reads the new answer (fake_ma_sendspin.py unpaired_switch, both dialects)
- Drop In blueprint: "drop into [the] {room}", "drop it in [to] [the] {room}" (ha_real_dropin.py)
- alexa-off.sh: one pm list of what is installed instead of a call per package
- wifi.sh: a WifiService join refused to root (a network Amazon's setup saved) is done as the system user, as
wifi-join.sh does (fake_web_wifi.py)
- Setup: udev_rules for every model (checkers and crown get the step), over ssh a rules file for a group the user is
in; qemu_arm for the Shows (qemu-user off x86_64, the user namespace sysctl asked up front); qrun.sh says why it
cannot run instead of hanging, install-boot.sh shows it
- GUIDE: the Shows' action button is both volume keys, no hold-to-reset
Closes #45
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft, stacked on #33. This branch contains #33's commit and one more: review only the last commit (
athena: Echo Show 8 2nd gen). Once #33 is in, this gets retargeted and the diff shrinks to that one commit.Adds the Echo Show 8 2nd gen (
athena): Android 9 with Treble and enforcing SELinux on an MT8183, rooted in place by saiyaku-athena's zip (INSTALL=running), the front end inside the audio HAL (OpenSL ES, as crown), a TAS5805m amplifier, a TCS3400 light sensor.devices/athena/,docs/re-athena.md.What the platform needed
accept/accept4/connectfail with EBADF. Cause: netd's fwmarkd is denied onsusockets (rule insepolicy.rules);net_accept,net_connect_fdand libcurl's already-connected socket stay as workarounds.IWifiManager(package-name argument,ParceledListSlice) inwifictl.dex, run as uid system.ringbar.dexbuilds theSurfaceControlthrough its Builder on SDK >= 26.IAudioService's transaction numbers differ on Android 9 (setStreamVolume7,getStreamMaxVolume14): the volume keys and Music Assistant's volume did nothing before.virtual_alsdoes (lux.h).fireosdhaservicebinder service.Checked. Every model builds with
STUBS=1,make host,make unit, and the ESPHome, settings page and Wi-Fi tests pass. On a real Echo Show 8 2nd gen: install, Home Assistant, voice round trip, wake sound, the band, Wi-Fi switch from the page, Amazon download, phone Bluetooth audio, Sendspin from Music Assistant, volume, speaker gain. Not tried: Improv, factory reset,install-system.sh --uninstall, hassmic's own HTTPS reply and the update check, Wi-Fi motion (no module for this driver). Open items are listed inPLAN.md.One thing that is deliberately not here: athena's change to
src/hassmic/https.c(the connect bypass), because that file only exists onmain; it goes in oncemainis part of this chain.🤖 Generated with Claude Code