Skip to content
Merged
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,9 @@ Run the guided setup:
watcherobot robot setup
```

The command first asks you to open **Settings > Wi-Fi** on the robot. Scanning
starts only after you confirm that the page is open. Results are identified by
The command first asks you to turn on computer Bluetooth and open
**Settings > Wi-Fi** on the robot. Scanning starts only after you confirm that
the page is open. Results are identified by
the stable **Device ID** shown on the robot; when several robots are nearby,
use **Up/Down** and Enter to select the intended Device ID. Older firmware that
does not advertise a Device ID is explicitly marked as unavailable and shows
Expand Down
4 changes: 2 additions & 2 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ watcherobot --version
watcherobot robot setup
```

命令会先提示你在机器人上打开 **Settings > Wi-Fi**;确认页面已经打开后才开始
扫描。扫描结果展示机器人上可核对的稳定 **Device ID**;附近有多台机器人时,使用
命令会先提示你打开电脑蓝牙,并在机器人上打开 **Settings > Wi-Fi**;确认页面已经
打开后才开始扫描。扫描结果展示机器人上可核对的稳定 **Device ID**;附近有多台机器人时,使用
**Up/Down** 和回车键按 Device ID 选择目标设备。旧固件未广播 Device ID 时,命令会
明确标记 Device ID 不可用,并仅把 Bluetooth ID 作为兼容信息展示。随后命令会私密
读取 Wi-Fi 密码并写入网络配置。
Expand Down
40 changes: 23 additions & 17 deletions docs/bluetooth-provisioning.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ Wi-Fi provisioning with Runtime pairing:
watcherobot robot setup
```

The guided command asks the user to keep **Settings > Wi-Fi** open before it
scans. It identifies results by `BluetoothDevice.id`, offers an **Up/Down**
selector when several robots are nearby, and never treats the advertised name
as the pairing identity. After Wi-Fi provisioning, it guides the user to the
robot's **"Python SDK"** app and completes six-digit Runtime pairing in the same
setup flow.
The guided command asks the user to turn on computer Bluetooth and keep
**Settings > Wi-Fi** open before it scans. It identifies results by the stable
`BluetoothDevice.device_id`, offers an **Up/Down** selector when several robots
are nearby, and never treats the advertised name as the pairing identity.
Older firmware that does not advertise a Device ID is marked explicitly and
retains the platform Bluetooth ID only as a compatibility fallback. After
Wi-Fi provisioning, the command guides the user to the robot's **"Python SDK"**
app and completes six-digit Runtime pairing in the same setup flow.

The lower-level API and `watcherobot bluetooth ...` commands below are intended
for diagnostics and custom automation.
Expand Down Expand Up @@ -44,7 +46,7 @@ async def main() -> None:
ssid="MyWiFi",
password="secret",
)
print(result.state) # credentials_saved
print(result.state) # connected


asyncio.run(main())
Expand Down Expand Up @@ -76,18 +78,17 @@ Neither value may contain an embedded NUL character.

## Result semantics

`credentials_saved` means that a `sys.ack` matching both
`cfg.wifi.set` and its `command_id` was received. It does not mean that the
SSID exists, the password is correct, DHCP succeeded, or the robot is online.
Use the later Wi-Fi status separately when needed.
`connected` means that a `sys.ack` matching both `cfg.wifi.set` and its
`command_id` was followed by a correlated `evt.wifi.status` with state
`connected`. The BLE session remains active during Wi-Fi validation. Firmware
may instead report `auth_failed`, `network_not_found`, or `timeout`; each is
raised as `WifiConnectionFailedError` with a stable `reason`.

The SDK subscribes to notifications before writing, writes with an ATT
response, and also reads the characteristic's cached response. After success,
timeout, cancellation, or another error, it makes bounded, independent
attempts to stop notifications and disconnect. Cleanup timeout or failure is
not allowed to replace an already acknowledged `credentials_saved` result.
Consequently, that result does not guarantee BLE disconnected or that the
firmware resumed its Wi-Fi connection attempt.
not allowed to replace an already confirmed `connected` result.

For `cfg.wifi.get` and `cfg.wifi.clear`, the shipped firmware places the
command ACK in the ATT write response, whose payload Bleak does not expose,
Expand All @@ -96,8 +97,9 @@ status obtained by the explicit post-write read as the observable success
signal. A status seen only through Notify remains a candidate until a matching
ACK/NACK arrives, so an unrelated early notification cannot hide rejection.

Default scan, connect, protocol-response, and per-cleanup-step timeouts are
10, 12, 3, and 2 seconds. They can be overridden when constructing
Default scan, connect, protocol-response, Wi-Fi-validation, and
per-cleanup-step timeouts are 10, 12, 3, 25, and 2 seconds. They can be
overridden when constructing
`BluetoothProvisioner`. Notification shutdown and disconnect are bounded
independently, so a stalled notification shutdown does not prevent the SDK
from attempting to disconnect. Cleanup is best-effort and its failure is not
Expand Down Expand Up @@ -139,12 +141,16 @@ without connecting.

## Protocol and security boundary

This release intentionally uses the firmware protocol without modifying it:
The SDK and current firmware use this provisioning protocol:

- device name: `ESP_ROBOT`
- service: `000000ff-0000-1000-8000-00805f9b34fb`
- characteristic: `0000ff01-0000-1000-8000-00805f9b34fb`
- compact UTF-8 JSON, at most 180 bytes per request
- `evt.wifi.status` terminal states: `connected`, `auth_failed`,
`network_not_found`, and `timeout`
- status events carry the originating Wi-Fi `command_id` for attempt
correlation

The protocol sends the SSID and password in JSON and adds no application-layer
authentication or encryption. This SDK release does not strengthen firmware
Expand Down
75 changes: 65 additions & 10 deletions docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,21 +78,67 @@ automation.

### `watcherobot robot setup [--device <id>] [--ssid <name>] [--pairing-code <code>] [--clear-existing]`

Guides first-time setup end to end. It first asks the user to open
**Settings > Wi-Fi** on the robot and starts scanning only after confirmation.
Guides first-time setup end to end. It first asks the user to turn on computer
Bluetooth and open **Settings > Wi-Fi** on the robot, then starts scanning only
after confirmation.
Results are shown by the stable **Device ID** advertised by the robot. With
multiple results, use **Up/Down** and Enter to choose the intended Device ID;
device names are not used as the selection identity. Older firmware without an
advertised Device ID is marked as unavailable and exposes the Bluetooth ID only
as a compatibility fallback. `--device` accepts the Device ID and continues to
accept that fallback Bluetooth ID for older firmware.

The command then reads the Wi-Fi password privately and provisions the
credentials. To finish, return to the robot launcher, open the **"Python SDK"**
The scan normally takes up to 10 seconds. Interactive terminals print progress
dots while it is running and report the number of robots found when it ends.

The guided flow separates recoverable states instead of returning raw scan
logs:

| State | What the command explains | Recovery |
|---|---|---|
| Computer Bluetooth is off or unavailable | Bluetooth cannot be used | Turn on Bluetooth or check the adapter, then rerun setup |
| The adapter or system lacks BLE central support | The computer cannot scan and connect in the required Bluetooth role | Use a BLE adapter with central support and confirm the OS supports BLE scanning |
| Operating-system permission is denied | Bluetooth access was denied | Allow the terminal or Python to use Bluetooth, then rerun setup |
| No robot is found | No provisioning advertisement was discovered | Keep **Settings > Wi-Fi** open and the robot nearby; already-networked robots use `robot pair` |
| One or several current robots are found | Stable Device IDs are displayed | Select the Device ID shown on the robot with **Up/Down** |
| Older firmware does not advertise a Device ID | Device ID is unavailable and a firmware update may be required | Bluetooth ID remains only as a compatibility fallback |
| Bluetooth connection or response times out | Bluetooth communication did not complete | Keep the robot nearby, close competing Bluetooth apps, and retry |
| Robot rejects the Wi-Fi settings | The supplied network settings were rejected | Check the Wi-Fi name and password, then retry |
| Wi-Fi authentication fails | Firmware reports `auth_failed` in the active BLE session | Check the password and rerun setup |
| No compatible network is found | Firmware reports `network_not_found` | Check the Wi-Fi name, range, and security mode |
| Wi-Fi validation times out | Firmware reports `timeout`, or the SDK's bounded wait expires | Move closer to the access point, check the credentials, and retry |
| Firmware returns an incompatible response | The robot and SDK provisioning protocols do not match | Update the firmware and SDK; report both versions if it persists |
| Runtime pairing fails | The six-digit pairing stage did not complete | Keep the **"Python SDK"** app open, confirm the same network, and use the latest code |
| The operation is cancelled | Setup was cancelled | No credentials or pairing code are printed |

`robot setup` is intentionally a human-guided command and its default errors
are plain recovery instructions. Automation that requires compact JSON should
use the lower-level `watcherobot bluetooth ...` commands, whose structured
output contract is unchanged.

Interactive terminals use color as a secondary state cue: blue for progress,
green for success, yellow for confirmation, red for failure, and cyan for
Device IDs. Text and exit codes always carry the same meaning, so color is
never the only signal. Redirected and non-interactive output disables color
automatically. Set `NO_COLOR=1` to disable it explicitly or `FORCE_COLOR=1`
for a compatible special terminal. The SDK enables Windows PowerShell console
compatibility automatically.

The command then reads the Wi-Fi password privately, provisions the
credentials, and keeps the BLE session open while firmware reports
`connecting` followed by `connected`, `auth_failed`, `network_not_found`, or
`timeout`. Pairing starts only after `connected`. To finish, return to the
robot launcher, open the **"Python SDK"**
app, read the six-digit code at the top of its screen, and enter it into the
same setup flow. Omitted values are prompted in an interactive terminal. The
password is never accepted as an argument or printed.

The command does not ask the user to confirm the robot screen manually. The
firmware owns a bounded connection attempt and sends the final result over BLE.
The SDK also applies a slightly longer host-side deadline so a dropped terminal
notification cannot leave setup hanging indefinitely. An authentication,
network-discovery, or timeout failure stops before Runtime pairing and prints a
specific recovery action without exposing the password.

```powershell
watcherobot robot setup
```
Expand All @@ -102,7 +148,7 @@ password remains interactive:

```powershell
watcherobot robot setup `
--device <bluetooth-id> `
--device <device-id> `
--ssid MyWiFi `
--pairing-code 123456
```
Expand Down Expand Up @@ -140,8 +186,9 @@ shortcut for directly executing `app.py`.

Creates a runnable Hello World Application without overwriting an existing
target. When the directory is omitted, an interactive terminal prompts for it.
The ID, display name, author, and description default from the directory and
can be overridden for publishing.
That directory is the only interactive question: ID, display name, author, and
description are generated automatically. For example, `my_app` receives the
stable, readable ID `local.my_app`. Publishing metadata can be overridden later.

```powershell
watcherobot app init my_app
Expand All @@ -153,6 +200,14 @@ watcherobot app init published_app `
--description "An example WatcheRobot Application"
```

If an explicit directory is followed by `Application ID:` or other metadata
prompts, the terminal is running an older CLI. Activate the intended virtual
environment and check the command source with `where.exe watcherobot` on
Windows or `command -v watcherobot` on macOS/Linux. An
Application ID is a stable upgrade identity, so the initializer does not append
a username, timestamp, or random value. Published apps should use a stable
team-owned namespace such as `com.example.my_app`.

It creates `app.json`, `app.py`, `README.md`, `icon.svg`, and `.gitignore`.
The generated `app.py` always logs a Hello World success. When a compatible
robot is connected, it also plays the `happy` behavior once.
Expand Down Expand Up @@ -337,8 +392,8 @@ watcherobot bluetooth scan

Prompts for the Wi-Fi password and sends credentials to the selected device.
`--clear-existing` asks the device to clear saved credentials first. A
`credentials_saved` result confirms only that firmware stored the credentials;
it does not prove that the device joined the network.
`connected` result means firmware reported that Wi-Fi joined successfully;
authentication, discovery, and timeout failures return an error instead.

```powershell
watcherobot bluetooth provision --device <id> --ssid MyWiFi
Expand Down
Loading