Metadata-Version: 2.4
Name: pywakepsx-on-bt
Version: 0.1.0
Summary: A Python library to wake PlayStation consoles via Bluetooth and extract MAC addresses via USB.
Author: FreeTHX
License-Expression: MIT
Project-URL: Homepage, https://github.com/FreeTHX/pywakepsx-on-bt
Project-URL: Bug Tracker, https://github.com/FreeTHX/pywakepsx-on-bt/issues
Project-URL: Changelog, https://github.com/FreeTHX/pywakepsx-on-bt/releases
Keywords: playstation,bluetooth,wake-on-bt,hci,home-automation,ps3,ps4,ps5
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Home Automation
Classifier: Topic :: System :: Hardware
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pyusb>=1.2.1
Dynamic: license-file

# pywakepsx-on-bt

[![PyPI](https://img.shields.io/pypi/v/pywakepsx-on-bt?style=for-the-badge)](https://pypi.org/project/pywakepsx-on-bt/)
[![Python](https://img.shields.io/pypi/pyversions/pywakepsx-on-bt?style=for-the-badge)](https://pypi.org/project/pywakepsx-on-bt/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=for-the-badge)](https://opensource.org/licenses/MIT)

A Python library for waking PlayStation consoles (PS3, PS4, PS5) over Bluetooth from Linux.

It handles the full wake pipeline: extracting Bluetooth MAC addresses from a connected USB controller, spoofing the host adapter's BD_ADDR, sending the HCI Create Connection command to the console, and restoring the adapter afterwards.

## Background

This library is the unified rewrite of two older projects:

- **[pywakeps4onbt](https://github.com/FreeTHX/pywakeps4onbt)** — original PS4 Bluetooth wake implementation
- **[pywakepsXonbt](https://github.com/FreeTHX/pywakepsXonbt)** — Generic PSX Bluetooth wake implementation


Both are now superseded by `pywakepsx-on-bt`, which consolidates their functionality, introduces proper BD_ADDR spoofing across multiple chipsets, and provides a clean Python API.

## How it works

Waking a PlayStation over Bluetooth requires impersonating the paired controller, because the console only accepts an incoming connection from the specific controller it last paired with (identified by its Bluetooth MAC address, the BD_ADDR).

The full sequence is:

```
1. [USB] Extract the controller BD_ADDR and console BD_ADDR from the physical controller
2. [HCI] Spoof the host Bluetooth adapter's BD_ADDR to match the controller's
3. [HCI] Send HCI Create Connection targeting the console's BD_ADDR
4. [HCI] Wait for Connection Complete or Command Status event
5. [HCI] Restore the adapter's original BD_ADDR
```

Steps 2–5 require a raw HCI socket (`AF_BLUETOOTH / SOCK_RAW / BTPROTO_HCI`) and `CAP_NET_RAW` / `CAP_NET_ADMIN` capabilities (or root). Step 1 only requires USB access to the controller.

## Installation

```bash
pip install pywakepsx-on-bt
```

## Quick start

### Step 1 — Extract MAC addresses via USB

Before issuing a wake command, you need two MAC addresses:

- **`dsx_mac`** — the BD_ADDR of the PlayStation controller (DualShock 3/4, DualSense)
- **`psx_mac`** — the BD_ADDR of the PlayStation console the controller last paired with

Both are stored inside the controller itself. When you connect the controller via USB, it exposes a HID interface over which you can read these addresses using a USB control transfer (`GET_REPORT` request). `pyusb` provides the low-level USB access needed to issue this transfer; the built-in Python `usb` module does not exist on Linux.

```python
from pywakepsx_on_bt import extract_psx_bt_macs

# Controller(s) must be connected via USB
results = extract_psx_bt_macs()

if not results:
    print("No supported Sony controller found on USB.")
else:
    # results is a list — one entry per connected supported controller
    result = results[0]
    print(f"Controller type: {result['controller_type']}")
    print(f"Controller MAC:  {result['dsx_mac']}")   # → spoof target
    print(f"Console MAC:     {result['psx_mac']}")   # → wake target
```

Each dict has three keys: `dsx_mac`, `psx_mac`, `controller_type`.
Supported controller types: `dualshock3`, `dualshock4`, `dualsense`, `dualsense_edge`.

> **Why not just read the pairing info from the Bluetooth stack?**
> BlueZ stores pairing keys by BD_ADDR, but only after the host has connected as a primary device. When the host acts as a third-party waker (not the original pairing peer), those keys are absent. Reading directly from the controller via USB is the only reliable way to get both addresses without prior pairing.

### Step 2 — Wake the console

```python
from pywakepsx_on_bt import wake_psx, detect_strategy

dsx_mac = "AA:BB:CC:DD:EE:FF"  # from extract_psx_bt_macs()
psx_mac = "11:22:33:44:55:66"  # from extract_psx_bt_macs()

strategy = detect_strategy(0)   # auto-detect chipset on hci0 and select spoof strategy
result = wake_psx(dsx_mac, psx_mac, adapter="hci0", spoof_strategy=strategy)

print(f"Status: {result.status_text} (0x{result.status_code:02X})")
```

### Full pipeline

```python
from pywakepsx_on_bt import extract_psx_bt_macs, wake_psx, detect_strategy

controllers = extract_psx_bt_macs()
if not controllers:
    raise RuntimeError("No controller found on USB")

macs = controllers[0]  # pick the first; iterate if multiple are connected
strategy = detect_strategy(0)
result = wake_psx(
    macs["dsx_mac"],
    macs["psx_mac"],
    adapter="hci0",
    spoof_strategy=strategy,
)
print(result.status_text)
```

## API reference

### `extract_psx_bt_macs() -> list[dict[str, str]]`

Scans USB for all connected supported Sony controllers. Returns a list of dicts, each containing `"dsx_mac"`, `"psx_mac"`, and `"controller_type"`. Returns an empty list if no device is found.

### `wake_psx(dsx_mac, psx_mac, *, adapter, timeout, spoof_strategy, backend) -> WakeResult`

High-level wake function. Delegates to `wake_psx_linux` by default. `spoof_strategy` must implement `apply(dev_index: int, dsx_mac: str) -> None`. Pass `backend` to override the default Linux raw-HCI implementation.

### `detect_strategy(dev_index: int) -> SpoofStrategy`

Reads the manufacturer ID from `hci{dev_index}` via `HCI_Read_Local_Version_Information` and returns the matching spoof strategy instance. Returns `UnsupportedSpoofStrategy` (which raises `SpoofNotSupportedError` on use) if the chipset is not recognised.

### `list_compatible_adapters() -> list[AdapterInfo]`

Enumerates all adapters found in `/sys/class/bluetooth/`, probes each one for its manufacturer ID, and returns a list of `AdapterInfo` dataclasses with `adapter`, `manufacturer_id`, `manufacturer_name`, `strategy_name`, `support_rating`, `compatible`, `notes`, and `mac_address` fields.

Filtering out adapters already managed by another application (e.g. the Home Assistant Bluetooth integration) is the caller's responsibility.

### `WakeResult`

Dataclass returned by `wake_psx` / `wake_psx_linux`.

| Field / Property | Type | Description |
|---|---|---|
| `adapter` | `str` | Adapter name used (e.g. `"hci0"`) |
| `status_code` | `int` | Raw HCI status code |
| `status_text` | `str` | Human-readable status (e.g. `"Page Timeout"`) |
| `command_packet` | `bytes` | Raw HCI packet that was sent |
| `outcome` | `str` (property) | Semantic result: `"success"`, `"timeout"`, or `"error"` |

## Adapter spoof strategies

BD_ADDR spoofing uses vendor-specific HCI commands that differ per chipset (Broadcom, Intel, CSR, Cypress, Texas Instruments, Qualcomm/Atheros). Compatibility ratings, technical notes, and implementation details are documented in [pywakepsx_on_bt/strategies/README.md](pywakepsx_on_bt/strategies/README.md).

## Permissions

Raw HCI sockets require elevated privileges on Linux:

```bash
# Option 1 — grant capabilities to the Python interpreter
sudo setcap cap_net_raw,cap_net_admin+eip $(which python3)

# Option 2 — run with sudo
sudo python3 your_script.py
```

Home Assistant add-ons and containers may need `network_mode: host` and the appropriate capability grants.

## Supported controllers

| Controller | Console | USB PID |
|---|---|---|
| DualShock 3 | PS3 | `0x0268` |
| DualShock 4 v1 | PS4 | `0x05C4` |
| DualShock 4 v2 | PS4 | `0x09CC` |
| DualSense | PS5 | `0x0CE6` |
| DualSense Edge | PS5 | `0x0DF2` |

All controllers use USB Vendor ID `0x054C` (Sony Corporation).

## Supported Bluetooth adapters
→ For compatible Bluetooth adapters (chipsets), see [Supported Chipsets](pywakepsx_on_bt/strategies/README.md#supported-chipsets).

## License

MIT License
