Something X Documentation
Something X is a Linux-native companion app for Nothing and CMF Bluetooth audio devices.
It provides ANC, EQ, battery monitoring, volume control, and CLI access — all via the
reverse-engineered RFCOMM 0x55 protocol, without requiring the Android app.
Omarchy / Hyprland users: Something X is built and optimised for the Omarchy desktop. Pure black, JetBrains Mono, Nothing Red — it matches your setup out of the box.
Requirements #
System
| Requirement | Version | Notes |
|---|---|---|
bluetoothd / BlueZ | ≥ 5.6 | Must be running; handles D-Bus and RFCOMM |
| GTK4 | ≥ 4.6 | UI toolkit |
| libadwaita | ≥ 1.2 | Navigation, dark theme integration |
| Python | ≥ 3.11 | Match syntax used throughout |
pactl | any | Optional — volume control via PulseAudio / PipeWire |
Python packages
| Package | Purpose |
|---|---|
python-gobject | GTK4, libadwaita, GLib, Gio bindings |
python-dbus | BlueZ D-Bus interface (device discovery, connect/disconnect) |
python-cairo | Splash screen and earbud visual rendering |
Installation #
Arch Linux / Omarchy
# system dependencies
sudo pacman -S python-gobject python-dbus python-cairo gtk4 libadwaita
# install via pip
pip install something-x
# or install from AUR
paru -S something-x
Ubuntu 24.04+
sudo apt install python3-gi python3-dbus python3-cairo gir1.2-gtk-4.0 gir1.2-adw-1
pip install something-x
Fedora 39+
sudo dnf install python3-gobject python3-dbus python3-cairo gtk4 libadwaita
pip install something-x
NixOS
# run directly from the flake
nix run github:SoaOaoS/something-x
# add as an input in your system flake — see flake.nix in the repository
From Source
git clone https://github.com/SoaOaoS/something-x
cd something-x
# install system deps for your distro first, then:
./somethingx
First Launch #
- Run
something-x(pip) or./somethingx(source). The animated splash screen plays for ~2.3 s. - The Home page lists all paired Bluetooth devices. Nothing / CMF devices are highlighted with a NOTHING badge.
- If your device isn't visible, press SCAN FOR DEVICES to run a 30-second BlueZ discovery.
- Tap a device card to open the Device page. The app connects over RFCOMM automatically.
- ANC, EQ, and volume controls are now live. Settings are saved immediately and restored on the next reconnect.
Bluetooth must be paired first. Use your desktop's Bluetooth manager or bluetoothctl to pair before launching Something X.
Home Page #
The Home page shows all Bluetooth devices known to BlueZ, grouped by connection status. Nothing and CMF devices that support the 0x55 RFCOMM protocol receive a red NOTHING badge and expose quick connect / disconnect actions inline.
The Bluetooth settings button in the top-right opens your system's Bluetooth settings panel. The refresh button re-queries BlueZ for device state without running a full scan.
Device Page #
Tapping a device card opens the Device page. The app opens an RFCOMM socket to the device on channel 10 and begins exchanging protocol frames.
ANC Control
Three modes are available: Off, Noise Cancellation, and Transparency. Selecting a mode sends the corresponding RFCOMM command immediately. The chosen mode is saved to the device profile and restored automatically on the next connection.
| Mode | Command byte |
|---|---|
| Off | 0x00 |
| Noise Cancellation | 0x02 |
| Transparency | 0x03 |
EQ Presets
Four presets are shipped: Balanced, More Bass, More Treble, and Voice. Each maps to a fixed payload sent over RFCOMM. Custom per-band EQ is planned for v2.x.
Volume
The volume slider calls pactl set-sink-volume on the active A2DP PipeWire/PulseAudio sink. This controls system volume for the device, not an in-earphone DSP level.
Battery
Battery levels for Left, Right, and Case are polled from the device over RFCOMM and displayed as animated radial rings. A notify-send desktop notification fires when any bud drops below 20 %. The system tray icon shows a battery tooltip on hover.
Background Mode #
Closing the window does not quit the app — it hides it. The Gio single-instance mechanism keeps the process alive so BlueZ reconnects are handled automatically and the tray icon remains active.
Running something-x again while the app is in the background shows the window without a second splash screen. To fully quit, use the tray icon menu or send SIGTERM to the process.
System Tray #
Something X registers a StatusNotifierItem (SNI) tray icon that is compatible with Waybar, KDE Plasma, GNOME (with AppIndicator extension), and any other SNI-aware panel.
The tooltip shows the battery percentage of the active device. Left-clicking the icon shows or hides the main window.
CLI Reference #
All CLI flags connect to the running app instance (or start a headless one) over the Gio D-Bus single-instance channel, so the GUI and CLI always share state.
--battery
something-x --battery
Prints L / R / Case battery percentages and exits. Returns non-zero if no device is connected.
--anc
something-x --anc off | on | transparency
Sets the ANC mode. on maps to Noise Cancellation. The setting is persisted to the device profile.
--eq
something-x --eq balanced | bass | treble | voice
Switches the EQ preset. Saved to the device profile.
--device
something-x --device AA:BB:CC:DD:EE:FF --battery
Targets a specific device by Bluetooth address. Useful when multiple Nothing / CMF devices are connected simultaneously.
Combining flags
# set ANC and EQ in one call
something-x --anc on --eq bass
Device Profiles #
ANC mode and EQ preset are saved per Bluetooth address to:
~/.config/something-x/profiles.json
The file is plain JSON and safe to edit manually. Each key is a Bluetooth MAC address:
{
"AA:BB:CC:DD:EE:FF": {
"anc": "noise_cancellation",
"eq": "balanced"
}
}
Profiles are applied automatically when the device connects over RFCOMM, with no user interaction required.
Desktop Entry #
A .desktop file is bundled in nothing_app/data/. Install it so Something X appears in Walker, Rofi, GNOME Shell, or any XDG-compliant launcher:
cp nothing_app/data/com.something.x.omarchy.desktop \
~/.local/share/applications/
update-desktop-database ~/.local/share/applications/
If installed via pip, the .desktop file is placed automatically by the installer.
Architecture #
├── application.py — Adw.Application: CSS, dark theme, splash, background mode, CLI flags
├── splash.py — Animated splash screen (Cairo, typewriter, ripple rings, ~2.3 s)
├── window.py — AdwNavigationView: home ↔ device routing, HeaderBar
├── bluetooth.py — BlueZ D-Bus manager: discovery, connect/disconnect signals, battery polling
├── protocol.py — Nothing Ear RFCOMM 0x55 protocol: frame encode/decode, CRC16-ARC
├── profiles.py — Per-device ANC/EQ persistence via ~/.config/something-x/profiles.json
├── data/
│ └── style.css — Nothing X dark theme (glass morphism, red accents, JetBrains Mono)
└── pages/
├── home.py — Device list + scan button + quick connect/disconnect
└── device.py — ANC / EQ / volume / info + Cairo earbud visual
RFCOMM Protocol #
The Nothing Ear protocol was reverse-engineered from the official Android APK. All communication happens over an RFCOMM socket on channel 10.
Frame Format
| Field | Size | Value / Notes |
|---|---|---|
| SOF | 1 byte | 0x55 |
| ctrl | 2 bytes LE | 0x0160 for all outgoing frames |
| cmd | 2 bytes LE | Command identifier (see table below) |
| len | 2 bytes LE | Payload length in bytes |
| FSN | 1 byte | Frame sequence number (increments per frame) |
| payload | len bytes | Command-specific data |
| CRC16 | 2 bytes LE | CRC16-ARC over all preceding bytes |
CRC is mandatory. The device silently drops SET commands if any frame in the session was sent without a valid CRC16-ARC checksum.
Command IDs
| Command | ID | Direction |
|---|---|---|
| Battery request | 0x0006 | Host → Device |
| Battery response | 0x0106 | Device → Host |
| ANC set | 0x0802 | Host → Device |
| ANC get | 0x0801 | Host → Device |
| EQ set | 0x0a04 | Host → Device |
| In-ear detection set | 0x0603 | Host → Device |
| Device info | 0x0001 | Host → Device |
Contributing #
Contributions are welcome, especially protocol work for unverified devices. The best place to start is GitHub Issues.
Development setup
git clone https://github.com/SoaOaoS/something-x
cd something-x
# install system deps for your distro, then run directly:
./somethingx
Debug Mode #
Set SOMETHING_X_DEBUG=1 to dump every raw RFCOMM frame to stdout:
SOMETHING_X_DEBUG=1 ./somethingx
If your device doesn't work as expected, capture the debug output and open an issue — include the raw frames so the command IDs can be identified.
Versioning #
This project uses Conventional Commits. Pushing to main triggers automatic versioning and a PyPI release via CI.
| Commit prefix | Version bump |
|---|---|
feat!: / BREAKING CHANGE | Major x.0.0 |
feat: | Minor 1.x.0 |
fix: / perf: / refactor: | Patch 1.0.x |
docs: / chore: / style: / ci: | No release |
Troubleshooting #
Device not appearing
Make sure the device is paired (not just discoverable) via your system Bluetooth manager or bluetoothctl. Then press the refresh button or SCAN FOR DEVICES in the app.
RFCOMM connection fails
Confirm bluetoothd is running (systemctl status bluetooth) and that the device is connected at the Bluetooth level before Something X tries to open the RFCOMM socket. Run with SOMETHING_X_DEBUG=1 to see the exact error.
Volume slider has no effect
Ensure pactl is installed (pacman -S libpulse / apt install pulseaudio-utils). The slider controls the A2DP PipeWire/PulseAudio sink — the device must be connected as an audio sink, not just paired.
Tray icon not showing
Your panel must support the StatusNotifierItem protocol. For GNOME Shell, install the AppIndicator and KStatusNotifierItem Support extension. For Waybar, ensure tray is in your modules.
App won't start — missing module
You're likely missing a system dependency. GTK bindings cannot be installed via pip — they must come from your distro's package manager. Re-run the install command for your distro from the Installation section.
Changelog #
See the GitHub Releases page for the full changelog. Releases are generated automatically from Conventional Commits on every push to main.