首页
/ Home Assistant Prometheus 集成:指标命名规范与 /api/prometheus 实现原理

Home Assistant Prometheus 集成:指标命名规范与 /api/prometheus 实现原理

2026-09-04 16:58:34作者:何将鹤

本篇围绕 Home Assistant 的 Prometheus 集成展开:它以 README 中的三条指标命名准则 为核心骨架,结合 集成主源码测试用例,讲清该集成如何把实体状态转换为 Prometheus 兼容格式、如何暴露 /api/prometheus 抓取端点,以及命名规则在代码中的落地点,帮助你在自有监控体系中正确配置、抓取并理解每一条指标的由来。

集成定位:把 Home Assistant 变成 Prometheus 指标源

集成文档 README.md 开篇即给出定位:该集成以 Prometheus 兼容格式对外暴露指标(exposes metrics in a Prometheus compatible format)。也就是说,Home Assistant 自身作为被抓取方(scrape target),把实体状态、设备注册表信息、房间/楼层拓扑等数据,实时转换为 Prometheus 文本 exposition 格式,供 Prometheus、Grafana、Alertmanager 等工具消费。

manifest.json 可以确认其工程特征:

  • 依赖 http 集成("dependencies": ["http"]),因为指标端点挂在 HTTP 服务上;
  • 通过固定依赖 prometheus-client==0.21.0 提供指标序列化能力,并在 loggers 中把 prometheus_client 的日志纳入 Home Assistant 日志体系;
  • iot_classassumed_state,即集成不实时连接外部设备,仅基于 Home Assistant 内部状态推导。

抓取端点常量定义在源码第 91 行:API_ENDPOINT = "/api/prometheus",由 PrometheusView 类 注册为 HomeAssistantView。其 get 方法在请求到达时调用 prometheus_client.generate_latest(prometheus_client.REGISTRY)(放入执行器线程以避免阻塞事件循环),并以 text/plain 返回最新快照。由于指标注册在进程级全局 REGISTRY 上,抓取端点天然还包含 python_infopython_gc_* 等 Python 运行时指标——测试代码 中即断言了 python_infopython_gc_objects_collected_total 等行会出现在响应体中。

配置入口

该集成是纯 YAML 配置型组件,setup()源码第 136-192 行 完成三件事:向 hass.http 注册视图、构建 PrometheusMetrics 实例、订阅五类总线事件(state_changed 以及实体/设备/房间/楼层四个注册表的 updated 事件),并在启动时遍历现存实体完成首次枚举。

指标命名准则:README 三条规则与源码落点

README 的“Metric naming guidelines”一节给出了三条准则。逐条对照源码,可以看到每一条都有明确的实现支撑。

准则一:指标名与标签名须符合 Prometheus 命名规范

原文要求 metric 和 label 名称遵循 Prometheus 官方命名实践。源码中的直接证据是指标名清洗函数 _sanitize_metric_name

ALLOWED_METRIC_CHARS = set(string.ascii_letters + string.digits + "_:")

@staticmethod
def _sanitize_metric_name(metric: str) -> str:
    metric = metric.replace("\u03bc", "\u00b5")
    return "".join(
        [c if c in ALLOWED_METRIC_CHARS else f"u{hex(ord(c))}" for c in metric]
    )

它把允许字符集限定为字母、数字、下划线与冒号(冒号用于 :job 风格的记录规则指标),并把希腊字母 μ(U+03BC,常见于密度单位 “μg/m³”)替换为度量衡符号 μ(U+00B5)——这与 _unit_string 中对 UnitOfDensity.MICROGRAMS_PER_CUBIC_METER 的注释相互印证。任何不在允许集内的字符会被转写为 u<hex(ord(c))> 形式,保证指标名在 Prometheus 端永不非法。

准则二:领域特定指标以 domain 作为指标名前缀

原文要求:sensorswitchclimate 等特定领域(domain)的指标,必须以 domain 作为指标名前缀。这一规则体现在通用数值指标生成器 _numeric_metric 中:

metric = self._metric(
    f"{domain}_state_{unit}",      # 有单位时:如 binary_sensor_state_w
    prometheus_client.Gauge,
    f"State of the {title} measured in {unit}",
    self._labels(state),
)
# 无单位时退化为 f"{domain}_state"

binary_sensorinput_booleannumberlockpersonhumidifier 等十余个领域共用这条路径(见 _handle_binary_sensor_handle_lock 等处理函数,源码第 755-909 行),因此你会看到 binary_sensor_state_*lock_state_*input_number_state_* 这类带 domain 前缀的指标名。领域专属指标同样遵循该约定,例如 climate_target_temperature_celsiuscover_positionfan_speed_percentwater_heater_away_mode 等,前缀即其所属 domain。

准则三:枚举型状态导出为按标签拆分的 0/1 布尔指标

原文要求:类似枚举的值(实体状态、当前模式等)应导出为取值 0 或 1 的“布尔”指标,并按状态/模式值作为指标标签拆分。源码中对应的通用实现是 _enum_metric

def _enum_metric(self, state, current_value, values, metric_name,
                 metric_description, enum_label_name):
    if current_value is None or values is None:
        return
    for value in values:
        self._metric(
            metric_name,
            prometheus_client.Gauge,
            metric_description,
            self._labels(state, {enum_label_name: value}),
        ).set(float(value == current_value))

它对候选值序列中的每一个取值都打一个标签组合,当前值对应 1、其余全为 0。典型例子:

  • cover 实体导出 cover_state{state="closed"}{state="opening"}{state="open"}{state="closing"} 四组标签(_handle_cover);
  • climate 实体导出 climate_mode{mode="..."}climate_action{action="..."}climate_preset_modeclimate_fan_mode,候选值分别来自实体的 hvac_modesHVACAction 枚举、preset_modesfan_modes 能力属性;
  • alarm_control_panel 实体按 AlarmControlPanelState 全枚举展开 alarm_control_panel_state{state="..."}

这种“one-hot 展开”正是 Prometheus 社区处理分类状态的惯用做法,便于在 PromQL 中用 climate_mode{mode="heat"} == 1 直接做判断。

配置参数全解(基于源码 Schema)

README 未列出配置项,但 CONFIG_SCHEMA 完整定义了七项参数,可据此写出可复制的配置:

prometheus:
  filter:
    include_domains: []   # 使用 entityfilter 过滤语法,精确控制哪些实体参与导出
  namespace: "homeassistant"   # 指标名前缀,默认 "homeassistant"
  requires_auth: true          # 抓取端点是否要求认证,默认 true
  default_metric: "sensor_value"        # 传感器默认指标名
  override_metric: "my_sensor"          # 所有传感器的统一覆盖指标名
  component_config:                  # 按 entity_id 精确覆盖
    sensor.living_room_temp:
      override_metric: "lr_temperature"
  component_config_glob:             # 按 glob 通配覆盖
    "sensor.living_room_*":
      override_metric: "lr_metric"
  component_config_domain:           # 按 domain 覆盖
    sensor:
      override_metric: "all_sensors"

各参数语义与源码依据:

参数 默认值 作用 源码依据
filter {}(全量) 采用 entityfilter.FILTER_SCHEMA,决定哪些实体进入指标导出 setup() L141-L142;被过滤实体在调试日志中打印 “Filtered out entity”
namespace homeassistant 生成 metrics_prefix,拼在每个指标名前;设为空字符串则不加前缀 L109、L243-L246测试 test_view_empty_namespace / test_view_default_namespace 分别验证空/默认前缀行为
requires_auth true 控制 PrometheusView 抓取是否需要认证 setup() L138PrometheusView L1148-L1156
default_metric 未设置 传感器命名回退链中的兜底指标名 _sensor_default_metric L1087-L1089
override_metric 未设置 全局统一覆盖所有传感器指标名 _sensor_override_metric L1110-L1114
component_config {} entity_id 为键的单实体覆盖,值为 {override_metric: str} COMPONENT_CONFIG_SCHEMA_ENTRYL104-L106
component_config_glob / component_config_domain {} 以 glob / domain 为键的批量覆盖 三者经 EntityValues 组合查询,L146-L150

传感器指标名的决定链

传感器(sensor)是指标命名最复杂的领域。_handle_sensor 按一个有序处理链确定指标名,取第一个非空结果:

  1. _sensor_override_component_metric —— 命中 component_config / _glob / _domain 中的 override_metric
  2. _sensor_override_metric —— 命中全局 override_metric
  3. _sensor_timestamp_metric —— device_class: timestamp 的传感器固定导出为 sensor_timestamp_seconds(该 device class 没有单位属性,值经 as_timestamp 转成时间戳);
  4. _sensor_attribute_metric —— 有 device_class 时导出 sensor_{device_class}_{unit},如 sensor_temperature_celsius测试中的断言示例);
  5. _sensor_default_metric —— 命中 default_metric
  6. _sensor_fallback_metric —— 兜底逻辑:有单位则 sensor_unit_{unit},否则 sensor_state,用于向后兼容(L1122-L1127)。

单位字符串本身也经过规范化(_unit_string):/ 转为 _per_、统一小写、% 映射为 percent°F 映射为 celsius(因为华氏值会被统一换算,见下文)。

标签体系与基础指标

每条实体指标都携带固定三标签(_labels):

  • entity:实体 ID;
  • domain:实体所属 domain;
  • friendly_name:实体友好名称(重命名时旧标签组合会被移除,见 handle_state_changed_event 对 friendly name 变化的检测)。

在领域专属指标之外,每个实体状态变化还会更新一组“元指标”(handle_state L279-L326):

  • *_state_change(Counter):状态变更累计次数;
  • *_entity_available(Gauge):实体是否可用(unavailable/unknown 记 0);
  • *_last_updated_time_seconds(Gauge):last_updated 的 Unix 时间戳;
  • *_entity_info(Gauge,值为 1):记录实体与房间(area 标签)的归属关系,房间取自实体自身 area_id,或回退到其所属设备的有效房间(_find_area_id L615-L631)。

注册表级指标 area_infofloor_info 则把房间/楼层拓扑本身导出为指标(handle_area / handle_floor L423-L481),标签含 area/area_name/floorfloor/floor_name/floor_level,便于在 Grafana 中做维度下钻。

标签集清理机制

Prometheus 客户端库不擅长“查询某指标已设置过哪些标签值”,而旧标签组合若不清理会永久残留在抓取输出中。为此源码定义了 MetricNameWithLabelValues 数据类,按实体记录其写过的 (metric_name, label_values) 组合;实体从注册表移除、被禁用、重命名或变为 unavailable 时,_remove_labelsets 会逐一调用 metric.remove(*label_values) 回收对应序列(L483-L508)。房间/设备归属变化也会触发 entity_info 的移除与重建(handle_entity_registry_updatedhandle_device_registry_updated,含父设备房间变更时刷新子设备实体的逻辑)。

温度与距离的单位统一

从源码结构看,该集成强制把温度统一到摄氏度:_temperature_metric 检测到系统单位为 °F 时用 TemperatureConverter 先把属性值转成 °C 再导出(L649-L664);_numeric_metric_handle_sensorunit_of_measurement: °F 的状态值同样先换算(L745-L753、L1071-L1077)。geo_location 的距离则统一为米(DistanceConverter 转换后写入 geo_location_distance_metersL773-L802)。这样跨实体、跨集成查询时,单位语义始终一致。

其他值得注意的领域导出:light 导出 0-100 的亮度百分比(on 时取 brightness/255L829-L843);switch 除数值状态外还会导出全部可浮点化的属性(switch_attr_*_handle_attributes L510-L522);带 battery_level 属性的实体(含 zwave)额外导出 battery_level_percentautomation 每次触发累加 automation_triggered_count(Counter)。

验证方式

集成自带完整测试 tests/components/prometheus/test_init.py(3400 余行),其核心模式与真实使用一致:

  1. fixture 中先重置 prometheus_client.REGISTRY 并注册 ProcessCollectorPlatformCollectorGCCollectorL485-L506);
  2. 通过 async_setup_component(hass, "prometheus", {...}) 以 YAML 配置加载集成;
  3. client.get("/api/prometheus") 断言 200、content-type: text/plain,并逐行比对指标文本(generate_latest_metrics L509-L519);
  4. EntityMetric 辅助类强制校验每条断言必须包含 domainfriendly_nameentity 三个必备标签(L113-L150)。

实际部署时,可在 Home Assistant 所在主机验证端点(requires_auth: true 时需带认证):

curl http://<home-assistant-host>:8123/api/prometheus

随后在 Prometheus 侧添加对应 scrape job(路径 /api/prometheus)即可开始采集;命名是否符合上文三条准则、前缀是否为 homeassistant_(默认 namespace),都可以直接在返回的文本 exposition 中核对。

小结

  • README 的三条命名准则并非口号,分别由 _sanitize_metric_name 的字符集清洗、_numeric_metric 等的 domain 前缀拼接、_enum_metric 的 one-hot 标签展开在源码中逐条兑现;
  • 指标端点为 /api/prometheus,默认带 homeassistant 前缀、默认要求认证,均可通过 YAML 配置调整;
  • 传感器指标名有六级优先回退链,温度统一换算为摄氏度,标签固定含 entity/domain/friendly_name,并配有实体/注册表事件驱动的标签集清理机制;
  • 若你正在为该集成新增领域处理函数,应沿用 _float_metric_bool_metric_enum_metric 等通用构建器并保持 domain 前缀命名,同时参照 test_init.py 的断言风格补充测试。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
980
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384