Skip to content

Unified Device Response Schema - Detailed Specification

Date: 2025-12-08 Version: 1.0 (Design) Status: 決定済み Target: v1.11.3+

Quick Links:


Overview

OSECHI(検出器)が送信するすべてのデータ(イベント・レスポンス)を単一の統一スキーマに従わせ、クライアント(kazunoko等)が統一されたパーサーで処理できる状態を実現する。

終状態:

  • OSECHI: event/response → unified schema (JSONL) → Serial
  • Client: unified schema (JSONL) → single parser → application logic

Unified Schema Definition

Top-level Structure

すべての出力は以下の統一フォーマットに従う:

{
  "type": "response" | "event",
  "status": "ok" | "error",
  "sent_at": 1732046789,
  "<field_name>": <value>,
  "<nested_object>": { ... }
}

Field Specifications

フィールド 必須 説明
type string "response" = コマンド応答 / "event" = 検出イベント
status string "ok" = 成功 / "error" = エラー
sent_at uint32 Unix timestamp (RTC利用時) または device uptime (秒単位)
error_code int エラーコード(status="error" 時のみ)
error_message string エラーメッセージ(status="error" 時のみ)
他すべてのフィールド * type/status に応じた動的フィールド

Response Schema

type="response" かつ status="ok"

{
  "type": "response",
  "status": "ok",
  "sent_at": 1732046789,
  "<command_specific_field>": <value>
}

Examples:

// GET_VERSION
{"type":"response","status":"ok","sent_at":1732046789,"version":"1.10.0"}

// SET_THRESHOLD (channel=1, value=1234)
{"type":"response","status":"ok","sent_at":1732046789,"threshold":{"channel":1,"value":1234}}

// GET_STATUS (nested structure)
{"type":"response","status":"ok","sent_at":1732046789,"system":{"version":"1.10.0","uptime_ms":123456},"detection":{"poll_count":100,"deadtime_ms":50}}

// GET_GNSS_POSITION
{"type":"response","status":"ok","sent_at":1732046789,"gnss":{"latitude":37.3874,"longitude":121.9724,"altitude":45.9}}

type="response" かつ status="error"

{
  "type": "response",
  "status": "error",
  "sent_at": 1732046789,
  "error_code": <code>,
  "error_message": "<message>"
}

Examples:

{"type":"response","status":"error","sent_at":1732046789,"error_code":1,"error_message":"Invalid argument"}
{"type":"response","status":"error","sent_at":1732046789,"error_code":2,"error_message":"Value out of range"}

Event Schema

type="event" かつ status="ok"

{
  "type": "event",
  "status": "ok",
  "sent_at": 1732046789,
  "hit1": <uint16>,
  "hit2": <uint16>,
  "hit3": <uint16>,
  "adc": <int>,
  "hit_type": <uint8> (optional, ENABLE_HITTYPE=1),
  "adc_raw": <uint16> (optional, ENABLE_ADCMV=1),
  "adc_mv": <uint16> (optional, ENABLE_ADCMV=1),
  "tmp_c": <float> (optional, ENABLE_BME280=1),
  "atm_pa": <float> (optional, ENABLE_BME280=1),
  "hmd_pct": <float> (optional, ENABLE_BME280=1),
  "uptime_ms": <uint32> (optional, ENABLE_TIMESTAMP=1),
  "timedelta_us": <uint64> (optional, ENABLE_TIMESTAMP=1),
  "unix_timestamp": <uint32> (optional, ENABLE_RTC=1),
  "gnss": { ... } (optional, ENABLE_GNSS=1)
}

Examples:

// Minimal event (core fields only)
{"type":"event","status":"ok","sent_at":1732046789,"hit1":95,"hit2":87,"hit3":91,"adc":2048}

// Full event with environmental + timing
{"type":"event","status":"ok","sent_at":1732046789,"hit1":95,"hit2":87,"hit3":91,"adc":2048,"tmp_c":25.35,"atm_pa":101325,"hmd_pct":45.67,"uptime_ms":123456,"timedelta_us":1000000}

// Event with GNSS data
{"type":"event","status":"ok","sent_at":1732046789,"hit1":100,"hit2":100,"hit3":100,"adc":2000,"gnss":{"latitude":37.3874,"longitude":121.9724,"altitude":45.9,"satellites":8,"hdop":1.04}}

See Also: For detailed implementation steps and task breakdown, refer to unified-device-response-protocol-design.md


Client-side Integration (kazunoko 対応)

kazunoko Parser 統一化

# kazunoko/parser.py

class DeviceResponse(BaseModel):
    """統一スキーマに従うデバイスレスポンス"""
    type: Literal["response", "event"]
    status: Literal["ok", "error"]
    sent_at: int

    # Dynamic fields (Pydantic's extra="allow")
    model_config = ConfigDict(extra="allow")

    # Optional error fields
    error_code: Optional[int] = None
    error_message: Optional[str] = None

# パーサーは既存の parse_jsonl() で対応可能
response = DeviceResponse(**json.loads(line))

クライアント実装例

# Any client language can follow the schema
def handle_osechi_output(jsonl_line):
    msg = parse_json(jsonl_line)

    if msg.type == "response":
        if msg.status == "ok":
            handle_command_response(msg)
        else:
            handle_error(msg.error_code, msg.error_message)

    elif msg.type == "event":
        if msg.status == "ok":
            handle_detection_event(msg)

Key Design Decisions

1. Single Schema for All Output

決定: response と event を同一スキーマで表現

メリット: - ✅ クライアント実装がシンプル(単一パーサーで全対応) - ✅ スキーマ仕様がシンプル(扱う型が統一) - ✅ 将来の拡張が容易(新フィールド追加も スキーマ内で完結)

2. Dynamic Fields via JSON

決定: response/event 固有フィールドは JSON 内に格納

メリット: - ✅ スキーマは固定だが、ペイロード内は可変 - ✅ nested object/array にも対応 - ✅ Optional fields(ENABLE_* フラグ)も自然に対応

3. sent_at = Common Timestamp

決定: すべての出力に sent_at フィールドを含める

メリット: - ✅ イベント/レスポンスのタイムスタンプが一貫 - ✅ ENABLE_RTC 時は Unix time、なければ device uptime で自動フォールバック - ✅ クライアント側で時系列ソートが容易

4. Zero-cost Adoption via Conditional Compilation

決定: ENABLE_DEVICE_RESPONSE フラグで段階的採用

メリット: - ✅ Phase 1 段階では response のみ、binary size 影響最小 - ✅ phase 2-3 で完全移行後、response.h を削除 - ✅ リスク最小化(既存機能温存)


Note: Testing details and strategies are provided in unified-device-response-protocol-design.md (Implementation Checklist section).


Future Extensions

Multi-language Client Libraries

スキーマが固定なので、以下の客動言語で同一パーサーを実装可能:

  • Python: kazunoko (現在開発中)
  • JavaScript/TypeScript: osechi-client
  • Rust: osechi-rs
  • Go: osechi-go

各言語とも、JSON スキーマバリデーター自動生成が可能:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["type", "status", "sent_at"],
  "properties": {
    "type": {"enum": ["response", "event"]},
    "status": {"enum": ["ok", "error"]},
    "sent_at": {"type": "integer"}
  },
  "additionalProperties": true
}

Summary

統一スキーマにより実現される開発体験:

OSECHI (firmware)          kazunoko (Python)       custom client (Any language)
    |                            |                         |
    +---> unified JSON -------> single parser <------- single schema
    |     (JSONL)               (auto-generated)       definition
    |
    +---> JSON Schema validation (multi-language)
    |
    +---> Client library code generation (OpenAPI-like)

最終状態: - ✅ OSECHI: unified schema に従った出力のみ - ✅ Client: schema definition から自動生成可能なパーサー - ✅ Documentation: 単一の schema spec (JSON Schema)


Design approved by: qumasan Target implementation: v1.11.3 Phase 1 (Protocol Layer)