# mijia-spec

[中文文档](README.zh.md)

A lightweight Rust library and CLI tool for querying Xiaomi MIoT v2 device specifications.

## Introduction

`mijia-spec` fetches Xiaomi MIoT v2 device definitions using device URNs and constructs a query-friendly Rust data model (`DeviceSpec`).

Key features include:

- Synchronous and asynchronous network APIs
- Optional fetching of multi-language translation payloads
- A two-level caching system (memory and disk)
- A CLI tool for querying devices by URN and outputting the results as JSON

## API Overview

- `miot_spec_v2::fetch_spec(urn)` (`sync`)
  Fetches the official MIoT v2 instance JSON and deserializes it into a `DeviceInstance`.
- `miot_spec_v2::fetch_spec_async(urn)` (`async`)
  The asynchronous equivalent of the instance fetch API.
- `miot_spec_v2::fetch_translation(urn)` / `fetch_translation_async(urn)`
  Fetches optional multi-language translation payloads.
- `MijiaSpecClient`
  A high-level client with built-in caching support:
  - `with_mem_cache(capacity)`
  - `with_disk_cache(path)`
  - `get(urn)` / `get_async(urn)`

`MijiaSpecClient` returns a `DeviceSpec` (`miot_spec_v2::query::DeviceSpec`). This struct retains the original instance data while providing convenient query helpers, such as:

- `get_property(siid, piid)`
- `get_property_by_name(service_name, property_name)`
- `get_action(siid, aiid)`
- `get_event(siid, eiid)`

## Implementation Details

This crate interacts with the following official MIoT v2 endpoints:

- Instance data: `https://miot-spec.org/miot-spec-v2/instance?type=<URN>`
- Translations: `https://miot-spec.org/instance/v2/multiLanguage?urn=<URN>`

The retrieved payloads are normalized into a queryable model and can optionally be cached in memory or on disk.

## Feature Flags

- `default = ["sync", "ureq-client"]`
- `sync`: Enables synchronous APIs.
- `async`: Enables asynchronous APIs.
- `ureq-client`: Uses `ureq` for synchronous HTTP requests.
- `reqwest-client`: Uses `reqwest` (supporting both blocking and async) for HTTP requests.
- `cli`: Builds the CLI binary (`mijia-spec`, requires the `sync` feature).

## CLI Usage

To build and run the CLI:

```bash
cargo run --features cli -- --urn urn:miot-spec-v2:device:light:0000A001:yeelink-mbulb3:1:0000C802 --pretty
```

Available options:

- `-u, --urn <URN>`: The target device URN (required).
- `--cache-dir <DIR>`: Specifies a directory for reading/writing disk cache.
- `--pretty`: Pretty-prints the JSON output.

Output format:

```json
{
  "instance": { ... },
  "translation": { ... }
}
```

*Note: The `translation` field is omitted if no translation data is available.*

## Test Data

- The `tests/test-dev-list.json` file stores device entries in a `{ "model": ..., "urn": ... }` format.
- This file is generated from a snapshot of the repository's `instances?status=released` endpoint.
- Integration tests ensure that the test data remains synchronized with the released status snapshot.

## Example

```rust,no_run
use mijia_spec::MijiaSpecClient;

fn main() -> Result<(), mijia_spec::SpecError> {
    let urn = "urn:miot-spec-v2:device:light:0000A001:yeelink-mbulb3:1:0000C802";

    // Initialize the client with a memory cache capacity of 128
    let client = MijiaSpecClient::new().with_mem_cache(128);
    let spec = client.get(urn)?;

    println!("Device: {}", spec.instance().description);

    if let Some(power) = spec.get_property(2, 1) {
        println!("Property: {}", power.name);
    }

    Ok(())
}
```
