Metadata-Version: 2.4
Name: nothing-headphone-cli
Version: 0.3.0
Summary: Cross-platform CLI and orientation visualizer for Nothing Headphone (1)
Author: Nothing CLI contributors
License-Expression: MIT
Project-URL: Homepage, https://github.com/LikelyLucid/nothing-headphone-cli
Project-URL: Documentation, https://github.com/LikelyLucid/nothing-headphone-cli#readme
Project-URL: Issues, https://github.com/LikelyLucid/nothing-headphone-cli/issues
Project-URL: Source, https://github.com/LikelyLucid/nothing-headphone-cli
Keywords: bluetooth,headphones,linux,windows,nothing
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Sound/Audio
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pyright>=1.1; extra == "dev"
Requires-Dist: ruff>=0.9; extra == "dev"
Requires-Dist: twine>=6; extra == "dev"
Dynamic: license-file

# Nothing Headphone (1) CLI

An unofficial cross-platform command-line interface and live orientation
visualizer for Nothing Headphone (1). It communicates directly with the
headphones over Bluetooth RFCOMM and has no runtime Python dependencies.

> [!IMPORTANT]
> This project is experimental, is not affiliated with Nothing Technology
> Limited, and has only been tested with Nothing Headphone (1). Settings are
> changed on the connected device at your own risk.

## Requirements

- Linux or Windows with Bluetooth RFCOMM socket support
- Python 3.11 or newer
- `bluetoothctl` from BlueZ for automatic device discovery on Linux
- A paired and connected Nothing Headphone (1)

## Installation

Install the published package with [`pipx`](https://pipx.pypa.io/), which keeps
command-line applications isolated:

```sh
pipx install nothing-headphone-cli
```

Alternatively, install the current source checkout in a virtual environment:

```sh
python -m venv .venv
# Linux:  . .venv/bin/activate
# Windows PowerShell: .venv\Scripts\Activate.ps1
python -m pip install .
```

This installs three commands: `nothing-cli`, the Linux broker
`nothing-headphonesd`, and `nothing-visualizer`. Windows does not provide
BlueZ's `bluetoothctl`, so pass the paired device address with `--address` or
`NOTHING_HEADPHONE_ADDRESS` there.

## Settings CLI

On Linux, connected headphones are auto-detected through `bluetoothctl`:

```sh
nothing-cli status
nothing-cli watch
nothing-cli anc anc-high
nothing-cli anc transparency
nothing-cli eq balanced
nothing-cli spatial head-tracking
nothing-cli --json status
```

`status` prints a concise, decoded snapshot. `watch` refreshes that snapshot when a
setting changes and runs until you press Ctrl-C; use `watch --duration SECONDS`
for a time-limited session. When attached to a terminal it updates in place, while
`--json watch` emits one JSON object per changed snapshot for scripts.

Run `nothing-cli --help` or `nothing-cli COMMAND --help` for the full command
reference. To select a device explicitly, use
`--address AA:BB:CC:DD:EE:FF` or set `NOTHING_HEADPHONE_ADDRESS`.

The `raw-query` command accepts only read-only `0xC000`-class opcodes:

```sh
nothing-cli raw-query 0xc001
nothing-cli raw-query 0xc06a
```

The Nothing X 3.6.0 APK contains additional read and write commands that are
not all exposed as high-level settings yet. The catalog is available without a
Bluetooth connection and includes the common protocol table plus Headphone (1)
features such as Auracast, sound mode, party mode, call transparency, Audiodo,
case versions, third-driver EQ, and Essential Space:

```sh
nothing-cli commands
nothing-cli --json commands --kind query
nothing-cli --json commands --kind set
nothing-cli --json commands --kind firmware
nothing-cli --json commands --kind recording
nothing-cli --json commands --kind debug
nothing-cli --json commands --kind alert-tone
nothing-cli --json commands --kind event
```

For commands whose payload format is known, the app's payload shape is shown in
the catalog description. Send an APK-recovered write explicitly with
`raw-set`; it accepts only `0xF000`-class opcodes and does not guess or validate
feature-specific payloads (the `0xFCxx` recording and alert-tone transfer
families are accepted as write-class opcodes too):

```sh
nothing-cli raw-set 0xf06a 01       # Auracast enable payload example
```

These additional commands were recovered statically from Nothing X 3.6.0 and
have not been exercised against hardware in this project. Use them only if you
understand the target device and payload; unsupported commands may be rejected
or change device state.

## Persistent broker (Linux)

Desktop widgets and other frequently polling clients should use the broker so
one process owns the RFCOMM connection. It serializes setting changes, keeps a
decoded status snapshot, reconnects after transient failures, and streams only
real state changes over a private Unix socket in `$XDG_RUNTIME_DIR`.

Start it in one terminal:

```sh
nothing-headphonesd
```

Then query or control it from another process:

```sh
nothing-cli broker ping
nothing-cli broker status
nothing-cli broker set anc transparency
nothing-cli --json broker watch
```

Use the same custom socket for both processes when needed:

```sh
nothing-headphonesd --socket "$XDG_RUNTIME_DIR/my-private-dir/broker.sock"
nothing-cli broker --socket "$XDG_RUNTIME_DIR/my-private-dir/broker.sock" status
```

The socket directory must be owned by the current user with mode `0700`; the
broker refuses to chmod shared directories or replace unknown files. Broker
commands exit with status `2` only when the Unix-socket transport is unavailable
and with status `1` when a running broker rejects the request. This lets callers
fall back to direct RFCOMM safely without racing a live broker.

Direct commands such as `nothing-cli status` remain available and do not depend
on the broker. Do not run direct commands and the broker concurrently because
the headphones permit only one RFCOMM owner.

An example systemd user unit is provided at
`contrib/systemd/user/nothing-headphonesd.service`. After a `pipx` install:

```sh
mkdir -p ~/.config/systemd/user
cp contrib/systemd/user/nothing-headphonesd.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now nothing-headphonesd.service
```

## Live orientation visualizer

Pair and connect the headphones, then run:

```sh
nothing-visualizer
```

The visualizer opens at <http://127.0.0.1:8765>. Face forward and select
**Recenter forward** (or press `R`) to zero yaw, pitch, and roll. The server
binds to localhost by default. Non-loopback binding is rejected unless
`--allow-remote` is passed; the control endpoints do not authenticate requests,
so remote access is unsafe without an external access-control layer.

An existing calibration is loaded from the operating system's temporary
directory as `nothing-headtrack-calibration.json`. Override it with
`--calibration PATH`, or recenter at any time. The optional fast-yaw workspace
gesture uses `hyprctl` and is therefore available only on Hyprland.

## Troubleshooting

First confirm that BlueZ sees the connected device:

```sh
bluetoothctl devices Connected
```

If it is not listed, pair and connect it with your desktop Bluetooth settings or
`bluetoothctl`. If automatic discovery cannot identify it, pass the address
explicitly:

```sh
nothing-cli --address AA:BB:CC:DD:EE:FF status
```

- **`could not run bluetoothctl`**: install the BlueZ command-line tools.
- **`no connected Nothing Headphone was found`**: connect the headphones or use
  `--address`/`NOTHING_HEADPHONE_ADDRESS`.
- **RFCOMM connection errors**: verify the device remains connected and that the
  current user can create Bluetooth sockets.
- **Visualizer port errors**: choose another local port with `--port PORT`.

When reporting a problem, follow [CONTRIBUTING.md](CONTRIBUTING.md) and remove
Bluetooth addresses from logs. See [SECURITY.md](SECURITY.md) for private
vulnerability reporting guidance.

## Development

```sh
python -m venv .venv
. .venv/bin/activate
python -m pip install -e '.[dev]'
ruff check src tests
pyright
pytest
python -m build
python -m twine check dist/*
```

## License

Distributed under the [MIT License](LICENSE).
