Metadata-Version: 2.4
Name: quote0
Version: 0.2.0
Summary: Python API client for Quote/0 display device
Project-URL: Repository, https://github.com/daviddwlee84/Quote0
Project-URL: Streamlit, https://quote0.streamlit.app/
Author: Da-Wei Lee
License-Expression: MIT
License-File: LICENSE
Keywords: api,display,iot,quote0
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
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: Programming Language :: Python :: 3.13
Requires-Python: >=3.9
Requires-Dist: pillow>=10.0.0
Requires-Dist: pydantic>=2.11.8
Requires-Dist: python-dotenv[cli]>=1.1.1
Requires-Dist: requests>=2.31.0
Requires-Dist: tyro>=0.9.31
Provides-Extra: examples
Requires-Dist: matplotlib>=3.8.0; extra == 'examples'
Requires-Dist: numpy>=1.26.0; extra == 'examples'
Provides-Extra: ui
Requires-Dist: streamlit>=1.49.1; extra == 'ui'
Requires-Dist: watchdog>=6.0.0; extra == 'ui'
Description-Content-Type: text/markdown

# Quote/0

A Quote/0 Client + Streamlit App and Notes about SSPAI's Quote/0

> Firmware 1.6.x · **client v0.2.0 targets the current `authV2` open API**
>
> The device had a major firmware update. The open API moved to
> `https://dot.mindreset.tech/api/authV2/open/device/{deviceId}/{image|text}`
> (device id now in the **URL path**). The legacy `/api/open/{image|text}` endpoints
> are **deprecated but still forward** to the new API (no removal date announced).
> `Quote0(...)` defaults to authV2; pass `legacy=True` to use the old endpoints.
> Official docs source: <https://github.com/MindReset/dot_web_docs>
> (`en-US/service/open/image_api.mdx`, `text_api.mdx`).

## Getting Started

1. Connect Type-C
2. Bind device in Mobile App
3. Select content to show
4. (optional) Request API key in App (and get Device ID) -> use [API](#API)
5. (optional) Setup `.env` (follow [`.env.example`](./.env.example))

- [Update Software](https://dot.mindreset.tech/tool/update)
  - update firmware
  - reset network
  - reset device

NOTE: to test if the display is normal you can use the script [checkerboard_gray.sh](scripts/image_api_test/checkerboard_gray.sh)

### CLI

- [quote0 · PyPI](https://pypi.org/project/quote0/)

```bash
# Install this package (core client is lightweight: requests + pydantic + pillow + tyro)
$ uv tool install quote0
# Optional extras:
#   quote0[ui]        Streamlit web app (streamlit, watchdog)
#   quote0[examples]  chart-rendering example scripts (matplotlib, numpy)

# Image API
# NOTE: the CHECKERBOARD_GRAY pattern is good to test if your monitor is defect
$ quote0 image --preset CHECKERBOARD_GRAY --api-key dot_app_.... --device-id ABCD1234ABCD
🖼️  Using preset image: checkerboard_gray
📤 Sending image to Quote/0 device... (border: WHITE)
✅ Image sent successfully!

# Text API with Environment Variable
export DOT_API_KEY=dot_app_....
export DOT_DEVICE_ID=ABCD1234ABCD

$ quote0 text --title Hello --message World
📤 Sending text to Quote/0 device...
✅ Text sent successfully!
```

### Python

```python
from quote0 import Quote0

client = Quote0(api_key="dot_app_...", device_id="ABCD1234ABCD")  # authV2 by default
client.send_text(title="总市值 12.34M", message="持仓盈亏 +98,765", signature="14:31")
client.send_image(image_base64=b64, dither_type="DIFFUSION")

# new authV2 fields:
#   send_text(..., styles={"fontSize": 18}, task_key=..., task_alias=...)
#   send_image(..., task_key=..., task_alias=...)
# legacy endpoints (device id in body):
#   Quote0(api_key, device_id, legacy=True)
```

### Streamlit UI

- [Quote/0 API Playground · Streamlit](https://quote0.streamlit.app/)

```bash
uv sync --extra ui   # or: pip install "quote0[ui]"
uv run streamlit run Streamlit_Playground.py
```

## Todo

- [ ] Determine whether same API Key can control multiple Device ID

Notes / gotchas:

- **authV2 `404` on push / screen doesn't change**: the device needs an *Open API*
  content slot in its loop task, otherwise pushed content has nowhere to show. Add an
  Open API card to the device in the Dot App.
- Rate limit is **10 requests/second**; image payload max **3MB** (base64) and `image`/
  `icon` may also be a public `http(s)` URL.
- [ ] Somehow Image API's "link" didn't work => NFC is not working

## Resources

- [Quote/0 摘录 - 少数派](https://sspai.com/create/quote0)
- [关于 Quote/0](https://dot.mindreset.tech/docs/quote_0)

### API

- Docs site: [了解 API](https://dot.mindreset.tech/docs/server/template/api)
  - [图像 API](https://dot.mindreset.tech/docs/server/template/api/image_api) (296px × 152px)
  - [文本 API](https://dot.mindreset.tech/docs/server/template/api/text_api)
- Docs **source** (Markdown, authoritative for endpoints/fields):
  [MindReset/dot_web_docs](https://github.com/MindReset/dot_web_docs)
  - `en-US/service/open/image_api.mdx` — authV2 image endpoint, dithering, `taskKey`/`taskAlias`
  - `en-US/service/open/text_api.mdx` — authV2 text endpoint, `styles`, fonts, `\n`/`\t`

#### authV2 quick reference

| | authV2 (default) | legacy (`legacy=True`, deprecated) |
|---|---|---|
| Image | `POST /api/authV2/open/device/{deviceId}/image` | `POST /api/open/image` |
| Text  | `POST /api/authV2/open/device/{deviceId}/text`  | `POST /api/open/text`  |
| device id | URL path | request body (`deviceId`) |
| auth | `Authorization: Bearer <DOT_API_KEY>` | same |
| rate limit | 10 req/s | 10 req/s |
