设备映射管理
面向开发者与配置维护者 — 如需了解控制台中的映射操作,请参考米家网关与映射
本文档描述 Olink 设备映射的核心概念、配置格式和设计约定,是自定义设备类型映射的技术参考。
架构概览
Olink 将米家 MIoT 设备桥接到 HomeKit(HAP)/Matter 时,经历三层映射,职责分明:
MIoT 设备 ──→ Input 层 ──→ Schema 层 ──→ Output 层 ──→ HAP/Matter
(属性映射+值转换) (类型/格式) (特征声明)- Input 层(
mapping/system/inputs/mijia/device/*.toml):MIoT spec → schema 属性映射 + 值转换 - Schema 层(
mapping/system/schemas/):属性类型、服务类型定义 - Output 层(
mapping/system/outputs/hap/*.toml):schema → HAP 特征声明(不含值转换)
配置格式
Input 层使用 TOML 格式,文件路径决定加载优先级:
routing.toml— 分流规则(按 device_type 选择 profile)device/*.toml— 设备类型映射配置model/*.toml— 型号级映射配置
注意:custom 作用域的配置文件会完全替换 system 作用域中同名文件的配置。
分流规则 routing.toml
routing.toml 位于 mapping/system/inputs/mijia/routing.toml,用于在多个设备 profile 之间进行分流。规则按声明顺序匹配,第一条命中的 profile 生效;未命中任何规则时 fallback 到 device/<device_type>.toml。
[[rule]]
device_type = "fan"
profile = "fan.heater"
when = { has_service = "heater" }条件表达式
when 字段支持以下条件表达式:
| 表达式 | 说明 | 示例 |
|---|---|---|
has_service | 设备存在指定 MIoT 服务 | { has_service = "heater" } |
has_property | 设备存在指定属性 | { has_property = "on" } 或 { service = "light", property = "brightness" } |
all | 全部条件满足 | { all = [{ has_service = "a" }, { has_service = "b" }] } |
any | 任一条件满足 | { any = [{ has_service = "a" }, { has_service = "b" }] } |
not | 取反 | { not = { has_service = "light" } } |
条件表达式支持递归嵌套,如:
when = { all = [
{ has_service = "speaker" },
{ not = { has_service = "light" } },
] }Input 层基本结构
device_type = "air-purifier"
[services.air-purifier]
read = { strategy = "auto", stale_threshold = 600, jitter_ratio = 0.2 }
[services.air-purifier.attributes]
on = { source = "active", service = "air-purifier" }device_type是设备类型标识(如"light"、"fan")[services.<service_name>]定义每个服务的配置,service_name对应 schema 服务名read定义读取策略[services.<service_name>.attributes]定义属性映射
属性映射格式
1:1 简单映射
[services.light.attributes]
power-state = { source = "on", service = "light" }
brightness = { source = "brightness", service = "light" }每个属性的 key 是目标 schema 属性名,value 中的 source 是 MIoT 源属性名,service 指定 MIoT 服务名。
1:1 带转换
[services.air-purifier.attributes.mode]
schema_attr = "target-air-purifier-state"
transform = { kind = "enum_map", to_map = [
{ from = 0, to = 1 },
{ from = 1, to = 0 },
], from_map = [
{ from = 0, to = 2 },
{ from = 1, to = 0 },
] }约定:Input 层一般不做值转换,转换应在 Output 层完成。仅在 Schema 层需要特定格式时才在 Input 层转换。
1:N 多映射(Combine)
同一个 MIoT 属性拆解为多个 schema 属性,再通过 type = "combine" 虚拟属性合并:
# 色相:从颜色属性读取,带枚举映射转换
hue = { source = "color", service = "light", transform = { kind = "enum_map", to_map = [
{ from = 0, to = 2 },
{ from = 1, to = 1 },
{ from = 2, to = 0 },
] } }
# 饱和度:从颜色属性读取,带枚举映射转换
saturation = { source = "color", service = "light", transform = { kind = "enum_map", to_map = [
{ from = 0, to = 2 },
{ from = 1, to = 1 },
{ from = 2, to = 0 },
] } }
# 色彩RGB:虚拟属性,通过 hue + saturation 合并生成 color-rgb 值
color-rgb = { type = "combine", inputs = ["hue", "saturation"], strategy = { type = "native", kind = "color_hs" } }type = "combine" 的虚拟属性不绑定真实 MIoT 属性,其 inputs 列出需要合并的 schema 属性名,strategy 定义合并策略。
同一 MIoT 服务分发到不同 schema 服务
当一个 MIoT 服务的属性需要分发到多个 HAP 服务时,在多个 [services.<name>] 块中分别指定 source 和 service:
# environment 的 PM2.5 → air-purifier 服务
[services.air-purifier.attributes]
"air-particulate-density" = { source = "pm2.5-density", service = "environment" }
# environment 的 temperature → temperature-sensor 服务
[services.temperature-sensor.attributes]
temperature = { source = "temperature", service = "environment" }Output 层 TOML 格式
文件位置:mapping/system/outputs/hap/*.toml
schema_id = "air-purifier"
[primary_service]
hap_service = "AirPurifier"
schema_service = "air-purifier"
[[characteristics]]
hap_type = "Active"
schema_attr = "active"
min = 0
max = 1
[[characteristics]]
hap_type = "TargetAirPurifierState"
schema_attr = "target-air-purifier-state"
min = 0
max = 1
transform = { kind = "enum_map", to_map = [
{ from = 0, to = 1 }, # Auto → Automatic
{ from = 1, to = 0 }, # Sleep → Manual
], from_map = [
{ from = 0, to = 2 }, # Manual → Favorite
{ from = 1, to = 0 }, # Automatic → Auto
] }
[[characteristics]]
hap_type = "LockPhysicalControls"
schema_attr = "lock-physical-controls"
min = 0
max = 1
optional = truecharacteristics列表决定哪些 schema 属性暴露到 HomeKittransform在此层定义值转换optional = true表示该特征非必需
Schema 层
Schema 层定义属性类型、格式和访问权限,位于 mapping/system/schemas/:
# schemas/attributes/lock-physical-controls.toml
[attribute]
id = "lock-physical-controls"
name = "锁定物理控制"
format = "bool"
access = ["read", "write", "notify"]
[attribute.mapping.hap]
type = "LockPhysicalControls"
service = "HeaterCooler"Transform 类型
定义在 olink-core/src/mapping/schema/attribute.rs 的 TransformConfig 枚举:
| kind | 说明 | 示例 |
|---|---|---|
enum_map | 枚举映射 | { from = 0, to = 1 } |
piecewise | 分段映射 | 离散值精确匹配 |
range | 区间映射 | 连续值映射到离散区间 |
linear | 线性插值 | source_min/max → target_min/max |
threshold | 阈值判断 | v > 20 → true |
constant | 常量 | 始终返回固定值 |
js | JS 脚本 | 复杂逻辑 |
reciprocal | 反比 | factor / v(如 Kelvin↔mired) |
enum_map 详解
transform = { kind = "enum_map", to_map = [
{ from = 0, to = 1 },
{ from = 1, to = 0 },
], from_map = [
{ from = 0, to = 2 },
{ from = 1, to = 0 },
] }to_map:正向转换(读侧,MIoT → HAP)from_map:反向转换(写侧,HAP → MIoT)。未提供时自动反转to_mapto_default/from_default:未命中时的默认值
piecewise 分段映射
适用于离散值精确映射:
transform = { kind = "piecewise", segments = [
{ from = 0, to = 0 },
{ from = 1, to = 33 },
{ from = 2, to = 66 },
{ from = 3, to = 100 },
], from_map = [
{ from = 0, to = 0 },
{ from = 33, to = 1 },
{ from = 66, to = 2 },
{ from = 100, to = 3 },
] }range 区间映射
适用于将连续值映射到离散区间(如风扇档位):
transform = { kind = "range", min = 1, ranges = [
{ max = 1, to = 25 },
{ max = 2, to = 50 },
{ max = 3, to = 75 },
{ max = 4, to = 100 },
], default = 1 }ranges按max升序排列,每个区间为(prev_max, max]- 第一个区间的下界为
min - 超出所有区间范围时返回
default
linear 线性插值
transform = { kind = "linear", source_min = 0, source_max = 100, target_min = 0, target_max = 100 }reciprocal 反比
适用于色温映射(Kelvin ↔ mired):
transform = { kind = "reciprocal", factor = 1000000 }设计约定
- Input 层负责属性映射:MIoT 属性名 → schema 属性名的映射在 Input 层完成
- Output 层负责值转换:MIoT 值域 → HAP 值域的映射在 Output 层完成
- spec_type 是设备级映射:只包含标准服务
- 1:N 映射用 Combine:同一 MIoT 属性拆解为多个 schema 属性时使用
type = "combine" - read 策略:每个
[services.<name>]块应有read配置 - HAP output 只做特征声明:声明哪些 schema 属性暴露到 HomeKit
- custom 替换 system:custom 作用域的配置文件完全替换 system 中同名配置
读策略配置
[services.fan]
read = { strategy = "auto", stale_threshold = 600, jitter_ratio = 0.2 }strategy = "auto":根据事件频率自动切换strategy = "poll":定时轮询strategy = "passive":仅被动接收推送
典型案例
physical-controls-locked(童锁)
场景:某些空气净化器型号(如 zhimi-ma2)有 physical-controls-locked 服务,MIoT 属性 physical-controls-locked 映射到 schema 的 lock-physical-controls。
Input 层(air-purifier.toml):
[services.air-purifier.attributes]
"lock-physical-controls" = { source = "physical-controls-locked", service = "physical-controls-locked" }Output 层(outputs/hap/air-purifier.toml):
[[characteristics]]
hap_type = "LockPhysicalControls"
schema_attr = "lock-physical-controls"
min = 0
max = 1
optional = true环境传感器多路分发(Multi-service)
场景:空气净化器的环境传感器同时提供 PM2.5 和温度数据,需要分发到不同的 HAP 服务。
# environment → air-purifier(PM2.5)
[services.air-purifier.attributes]
"air-particulate-density" = { source = "pm2.5-density", service = "environment" }
# environment → temperature-sensor(温度)
[services.temperature-sensor.attributes]
temperature = { source = "temperature", service = "environment" }枚举值转换
场景:空气净化器模式从 MIoT 到 HAP 需要 enum 值转换。
[services.air-purifier.attributes.mode]
schema_attr = "target-air-purifier-state"
transform = { kind = "enum_map", to_map = [
{ from = 0, to = 1 },
{ from = 1, to = 0 },
], from_map = [
{ from = 0, to = 2 },
{ from = 1, to = 0 },
] }