Files
AskaEth f91a83ff81
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
feat(urgency): 通用紧急度通道(Declarer/Level + 只抬不压折算)+ IoT 首个生产者 + 她自己的结论走结构化标记穿透安静时段
2026-10-05 13:11:04 +08:00

99 lines
4.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package iot 提供 Cyrene v2 的 IoT 设备来源抽象。
//
// 它把智能家居设备(灯、空调、窗帘、传感器、门锁)建模为强类型设备,交由可插拔的
// Provider 管理。Provider 即设备来源;Manager 依据配置选定 Provider,对外提供
// List/Control/Status,并把设备状态跃迁作为事件发布到进程内 bus,使其他子系统
// (前端、记忆、推送)无需轮询即可感知设备变化(对照
// DevDocs/02-development-constraints.md "IoT 设备状态 bus 事件驱动")。
//
// 里程碑 M5 交付可插拔 Provider 骨架,外加一个 mock Provider:内置八台模拟设备,
// 以及界定每种设备类型支持范围的 control_rules。真实 Provider 集成(MQTT、
// Home Assistant)后续通过同一套 Provider 接口接入。
package iot
import (
"errors"
"git.yeij.top/AskaEth/Cyrene_v2/internal/urgency"
)
// DeviceUpdateSubject 是设备状态跃迁事件发布所用的 bus 主题。订阅方使用该主题
// (或 "iot.>")观察设备变化。
const DeviceUpdateSubject = "iot.device_update"
// iot 子系统返回的哨兵错误,判定时请用 errors.Is。
var (
// ErrDeviceNotFound 表示该设备 ID 对全部已注册 Provider 均未知。
ErrDeviceNotFound = errors.New("iot: device not found")
// ErrUnsupported 表示某动作不被该设备类型支持(受该类型的 capability 约束),
// 或动作参数取值超出该类型的规则集合。
ErrUnsupported = errors.New("iot: unsupported action")
// ErrOffline 表示 Control 调用指向了离线设备。
ErrOffline = errors.New("iot: device offline")
// ErrInvalidParam 表示动作参数缺失或类型错误。
ErrInvalidParam = errors.New("iot: invalid parameter")
// ErrUnknownProvider 表示配置指定了未知的 Provider。
ErrUnknownProvider = errors.New("iot: unknown provider")
// ErrProviderNotRegistered 表示尝试执行设备操作,但没有任何已注册的 Provider
// (例如 "none" Provider)。
ErrProviderNotRegistered = errors.New("iot: no provider registered")
// ErrInvalidArgument 表示传入参数为 nil 或空。
ErrInvalidArgument = errors.New("iot: invalid argument")
// ErrDuplicate 表示同名 Provider 被注册了两次。
ErrDuplicate = errors.New("iot: provider already registered")
)
// Device 是由某个 Provider 暴露的单台智能家居设备。
type Device struct {
// ID 是设备全局唯一标识,Control 与 Status 调用据此定位设备。
ID string `json:"id"`
// Name 是供人阅读的设备名称。
Name string `json:"name"`
// Type 是设备种类,例如 "light"、"ac"、"curtain"、"sensor"、"lock";
// 类型决定 Provider 施加的 control_rules。
Type string `json:"type"`
// State 保存设备当前的键值状态;具体键取决于设备的 Type。
State map[string]any `json:"state"`
// Online 表示设备当前是否可达。
Online bool `json:"online"`
}
// Clone 返回 d 的副本,其中 State 为独立 map,因此调用方可以随意修改返回的设备
// 而不影响 Provider 的内部状态。State 中的值按引用复制;mock Provider 只存放
// 基本类型值。
func (d Device) Clone() Device {
cp := d
if d.State != nil {
cp.State = make(map[string]any, len(d.State))
for k, v := range d.State {
cp.State[k] = v
}
}
return cp
}
// DeviceUpdate 是设备状态跃迁时发布到 DeviceUpdateSubject 的载荷,通常由一次
// Control 调用产生。
type DeviceUpdate struct {
// Provider 是拥有该设备的 Provider 名称。
Provider string `json:"provider"`
// Device 是跃迁后的设备快照。
Device Device `json:"device"`
// Action 是触发该次跃迁的控制动作。
Action string `json:"action"`
// Params 是可选的控制参数。
Params map[string]any `json:"params,omitempty"`
// Message 是跃迁的可读摘要,会呈现到前端的 device_update 信息流中。
Message string `json:"message,omitempty"`
// Severity 是本次跃迁的显式严重度(通用紧急度词汇 urgency.Level 的别名)。
// 零值 SeverityRoutine 表示例行变化,因此既有订阅方与既有的普通设备变化行为
// 逐字不变;命中安全规则(见 safetySeverity)的跃迁才被标成安全域
// (design/12 §6 安全域豁免)。
Severity AlertSeverity `json:"severity"`
}
// Urgency 实现 urgency.Declarer:DeviceUpdate 因此在**通用通道**上声明紧急度,
// 让 backthink(以及任何订阅方)无需认识 IoT 的专有字段就能承认安全域事件。
// 接线点见 backthink 的 triggerForEvent。
func (d DeviceUpdate) Urgency() urgency.Level { return d.Severity }