---
name: atom-desk-control
description: Operate, integrate, or troubleshoot the ATOM Lite standing-desk controller at babkeni.xhoz.uk through its custom Bluetooth LE GATT service or USB TABLE/1 protocol. Use for this desk's pairing, recovery, control clients, and firmware maintenance.
---

# ATOM desk control

Work with the existing controller, not a generic Bluetooth serial device. The public controller is https://babkeni.xhoz.uk. Its Bluetooth link is local to the computer/phone opening the page; public hosting does not provide Internet remote control.

Read [references/protocol.md](references/protocol.md) for UUIDs, packet layouts, USB commands, recovery timeouts, and maintenance before implementing a client or sending commands.

## Identify the installation

- Original ESP32-PICO-D4 M5Stack ATOM Lite, currently named **ATOM Desk 1590**. Discover by the documented service UUID, then select the intended device; a name alone is not authenticated identity.
- Two M5Stack single GPIO relays (U023) through a plain HUB (U006). The relays have no I2C addresses. Grove is the connector format.
- Relay A uses the normal Grove cable: yellow, GPIO26, up. Relay B has yellow and white crossed at **one connector end only**: white, GPIO32, down. Red/black stay unchanged.
- Table ground is on both relay **COM** terminals. Up/down inputs use each relay's **NO** terminal; both **NC** terminals are unused. These contacts imitate the original momentary buttons. Table wires belong only on the isolated relay terminals, never on the ATOM/Grove pins.
- The large top face is the programmable button. The small side button resets the board. Successive physical holds alternate up/down; release stops.

Disconnect table power for wiring changes. Do not infer different wiring from the presence of 12 V on an idle control input.

## Match the requested operation

Explaining, scanning, reading status, and diagnosing do not authorize movement. Send BEGIN/HOLD only for a requested movement or an explicitly authorized motion test. For automated motion, obtain a duration or stop condition if none was specified, honor it, and issue STOP in cleanup. The 30-second cap is a maximum, not a default movement duration.

For inspection, prefer BLE discovery and authenticated status reads, or USB HELLO?/BLE?. Reading status does not move the table. STOP cancels any source and is an intentional operational action, not a passive query.

The device has no height sensor or movement/contact feedback. Report command/relay state; do not claim measured height, completed travel, obstacle detection, or physical stop based only on an acknowledgement.

## Connect and pair

Use a BLE GATT client, or a Web Bluetooth-capable browser over HTTPS/secure localhost. Pair using the device's current six-digit PIN in the **operating system** prompt. Do not guess a default or embed the credential in public code or skill packages. Ask the owner, or retrieve it through authorized local USB with `TABLE/1 PAIR?`.

Both characteristics require authenticated encryption with MITM protection; retain those requirements in clients. Bonded devices can reconnect without a PIN prompt. Changing the PIN revokes device bonds and requires forgetting the old OS pairing.

Do not automatically reconnect and replay movement. A new connection needs a fresh user gesture and session token.

## Implement hold-to-move

Use an ordered GATT lane. On a fresh authorized press, send one BEGIN with a fresh token. While held, renew with the same token every 100–120 ms. Confirm direction, BLE ownership, and token through status. A write acknowledgement means delivery, not acceptance of the queued movement.

On release, pointer cancel/capture loss, leaving the held control, key release, focus loss, hidden/unloaded page, or exit: cancel queued BEGIN/HOLD operations, send STOP, and stop renewals. A delayed asynchronous BEGIN must not run after STOP. Require a new press after timeout, rejection, disconnect, or stop.

The remote movement lease is **500 ms** and every movement is limited to **30 seconds**. Starts require a **30 ms** off interval. Direct reversal/preemption is refused; one transport cannot renew another transport's session. A physical press cancels USB/BLE motion and is consumed until release.

## Recover without erasing configuration

Advertising normally stops while connected. Windows may retain a physical BLE link after a browser/client reports local disconnection. Recovery firmware resumes advertising after a real disconnect, drops failed authentication, times out unauthenticated pairing after 45 seconds, and releases authenticated clients after five seconds without BLE reads/writes. Poll connected status roughly once per second even while idle.

If discovery fails, check other clients/tabs and allow the applicable timeout. USB `TABLE/1 BLE?` distinguishes CONNECTED, AUTH, and ADVERTISING. `TABLE/1 BLE DISCONNECT` explicitly closes a stuck link. Do not erase NVS, reset the PIN, or flash merely to refresh discovery.

For requested PIN changes or firmware updates, follow the reference. Keep DTR/RTS false when opening USB for normal operation to avoid a reset.

## Owning sources

Repository: https://github.com/PurpleTheBest/m5-stack-stick (private; access may be required). Relevant paths: `Firmware/AtomDualRelay/AtomDualRelay.ino`, `BluetoothTransport.h`, `BluetoothRecovery.h`, and `WebControl/dist/`. Recovery/custom-PIN behavior was introduced in https://github.com/PurpleTheBest/m5-stack-stick/pull/21.

Protocol inspected on 2026-11-03. Verify the owning source before changing behavior or relying on another firmware release. Loading this skill does not itself authorize movement, credential changes, or deployment.
