18 KiB
ZONT Prometheus Exporter
Экспортер телеметрии отопительных контроллеров ZONT (H-1V, H-1V.02, H1V02_PRO, H-1000, H-2000 и др.) в формате Prometheus.
Собирает текущее состояние устройства через облачное API my.zont.online и отдаёт метрики на HTTP-эндпоинт /metrics. Подходит для мониторинга в Grafana, алертинга в Alertmanager и любого стека, совместимого с Prometheus.
📋 Содержание
- Возможности
- Требования
- Быстрый старт
- Переменные окружения
- Метрики
- Интеграция с Prometheus
- Пример алертов
- Диагностика
- Ограничения
- Безопасность
- Лицензия
🚀 Возможности
- Текущее состояние контроллера: онлайн-статус, напряжение питания, память, источник питания.
- Связь: уровень GSM, состояние регистрации в сети, RSSI Wi-Fi, наличие связи с сервером ZONT.
- Температуры: проводные и аналоговые датчики (в т.ч. «Погода из интернета»), статус исправности.
- Отопление: целевая и заданная температура по каждому отопительному контуру, время работы.
- Котёл / OpenTherm: расчётная температура теплоносителя, уставка ГВС, наличие связи с котлом, аварии.
- Погода: температура с внешнего источника.
- Аналоговые входы: напряжение на входах (например, контроль питания).
Работает как отдельный контейнер, не требует установки чего-либо на хост.
✅ Требования
- Docker (или Docker Compose)
- Аккаунт в личном кабинете my.zont.online с добавленным устройством ZONT
- Сетевая доступность
my.zont.online:443из контейнера - Prometheus (опционально) для сбора метрик
🏁 Быстрый старт
1. Создайте файлы
Вам нужны два файла:
zont_exporter.py— код экспортераDockerfile— сборка образа
2. Соберите образ
docker build -t zont-exporter .
3. Запустите контейнер
docker run -d \
--name zont-exporter \
--restart unless-stopped \
-p 9101:9101 \
-e ZONT_LOGIN='your_login' \
-e ZONT_PASSWORD='your_password' \
-e ZONT_DEVICE_ID='554007' \
-e ZONT_CLIENT='you@example.com' \
zont-exporter
4. Проверьте
curl http://localhost:9101/metrics | grep zont_
Вы должны увидеть метрики вида:
zont_device_online{device_id="554007"} 1.0
zont_voltage_volts{device_id="554007"} 12.1
zont_gsm_level{device_id="554007"} 17.0
zont_temperature_celsius{device_id="554007",name="Температура гаража 150",object_id="8200"} 18.8
zont_boiler_connected{adapter_id="4096",device_id="554007"} 0.0
🔧 Переменные окружения
| Переменная | Обязательна | По умолчанию | Описание |
|---|---|---|---|
ZONT_LOGIN |
✅ | — | Логин от личного кабинета my.zont.online |
ZONT_PASSWORD |
✅ | — | Пароль от личного кабинета |
ZONT_DEVICE_ID |
✅ | — | Числовой ID устройства (см. ниже, как узнать) |
ZONT_CLIENT |
❌ | my_exporter@example.com |
Контактный email для заголовка X-ZONT-Client. ZONT использует его для связи при изменениях API. Укажите свой. |
SCRAPE_INTERVAL |
❌ | 60 |
Интервал сбора метрик, секунды. Не имеет смысла ставить меньше 30 — API не успевает обновлять данные. |
EXPORTER_PORT |
❌ | 9101 |
Порт, на котором экспортер слушает /metrics внутри контейнера |
LOG_LEVEL |
❌ | INFO |
Уровень логирования: DEBUG, INFO, WARNING, ERROR, CRITICAL. Регистр не важен. |
Как узнать ZONT_DEVICE_ID
Способ 1. Через API (рекомендуется)
curl -s -X POST 'https://my.zont.online/api/devices' \
-u 'login:password' \
-H 'X-ZONT-Client: you@example.com' \
-H 'Content-Type: application/json' \
-d '{"load_io": true}' | python3 -m json.tool | grep -E '"id"|"name"|"serial"'
В ответе найдите блок своего устройства — поле "id" и есть ZONT_DEVICE_ID.
Способ 2. Через личный кабинет
Откройте устройство в веб-интерфейсе my.zont.online — ID обычно видно в URL страницы устройства.
Пример запуска с нестандартным портом и отладкой
docker run -d \
--name zont-exporter \
--restart unless-stopped \
-p 9200:9200 \
-e ZONT_LOGIN='your_login' \
-e ZONT_PASSWORD='your_password' \
-e ZONT_DEVICE_ID='554007' \
-e ZONT_CLIENT='you@example.com' \
-e EXPORTER_PORT='9200' \
-e LOG_LEVEL='DEBUG' \
zont-exporter
⚠️ Номера портов в
-p <хост>:<контейнер>иEXPORTER_PORTдолжны совпадать по контейнерной части. Пример выше:EXPORTER_PORT=9200и-p 9200:9200. Если хост-порт занят — используйте-p 8080:9200.
📊 Метрики
Все метрики имеют префикс zont_ и label device_id. Для удобства читаемые имена объектов (датчиков, контуров) добавляются как label name.
Общие
| Метрика | Тип | Labels | Описание |
|---|---|---|---|
zont_device_online |
gauge | device_id |
1 — устройство на связи, 0 — offline |
zont_device_last_receive_time |
gauge | device_id |
Unix-время последнего пакета от устройства |
zont_voltage_volts |
gauge | device_id |
Напряжение основного питания, В |
zont_power_source |
gauge | device_id |
1 — основное питание, 0 — иное |
zont_memory_used_percent |
gauge | device_id |
Использование памяти контроллера, % |
zont_memory_used_bytes |
gauge | device_id |
Использование памяти, байт |
zont_internet_weather_celsius |
gauge | device_id |
Температура с внешнего источника погоды, °C |
Связь
| Метрика | Тип | Labels | Описание |
|---|---|---|---|
zont_gsm_level |
gauge | device_id |
Уровень сигнала GSM, 0–31 |
zont_gsm_state |
gauge | device_id |
0=not-registered, 1=home-network, 2=searching, 3=rejected, 5=roaming |
zont_wifi_rssi |
gauge | device_id |
Уровень сигнала Wi-Fi |
zont_server_connected |
gauge | device_id |
1 — есть связь с сервером ZONT |
Датчики температуры и аналоговые входы
| Метрика | Тип | Labels | Описание |
|---|---|---|---|
zont_temperature_celsius |
gauge | device_id, object_id, name |
Текущая температура, °C |
zont_temperature_sensor_ok |
gauge | device_id, object_id, name |
1 — датчик исправен |
zont_analog_voltage_volts |
gauge | device_id, object_id, name |
Напряжение на аналоговом входе, В |
Отопление
| Метрика | Тип | Labels | Описание |
|---|---|---|---|
zont_heating_target_temp_celsius |
gauge | device_id, circuit_id, name |
Фактическая целевая температура контура |
zont_heating_setpoint_temp_celsius |
gauge | device_id, circuit_id, name |
Заданная температура (уставка) |
zont_heating_worktime_seconds |
gauge | device_id, circuit_id, name |
Время работы контура за последнюю минуту, сек |
zont_heating_status |
gauge | device_id, circuit_id, name |
Код статуса контура |
Котёл / OpenTherm
| Метрика | Тип | Labels | Описание |
|---|---|---|---|
zont_boiler_cs_celsius |
gauge | device_id, adapter_id |
Расчётная температура теплоносителя, °C |
zont_boiler_ds_celsius |
gauge | device_id, adapter_id |
Уставка температуры ГВС, °C |
zont_boiler_connected |
gauge | device_id, adapter_id |
1 — котёл на связи, 0 — нет |
zont_boiler_fail |
gauge | device_id, adapter_id |
1 — авария котла |
🔌 Интеграция с Prometheus
Добавьте в prometheus.yml:
scrape_configs:
- job_name: 'zont'
scrape_interval: 60s
scrape_timeout: 20s
static_configs:
- targets: ['zont-exporter:9101']
labels:
instance: 'home-boiler'
Если Prometheus работает в том же Docker-сети, используйте имя контейнера. Если на хосте — host.docker.internal:9101 (Windows/macOS) или IP хоста (Linux).
Docker Compose (пример)
services:
zont-exporter:
build: .
container_name: zont-exporter
restart: unless-stopped
ports:
- "9101:9101"
environment:
ZONT_LOGIN: "your_login"
ZONT_PASSWORD: "your_password"
ZONT_DEVICE_ID: "554007"
ZONT_CLIENT: "you@example.com"
SCRAPE_INTERVAL: "60"
EXPORTER_PORT: "9101"
LOG_LEVEL: "INFO"
🚨 Пример алертов
prometheus/rules/zont.yml:
groups:
- name: zont
rules:
- alert: ZontDeviceOffline
expr: zont_device_online == 0
for: 10m
labels:
severity: critical
annotations:
summary: "ZONT {{ $labels.device_id }} offline"
description: "Устройство не выходит на связь более 10 минут."
- alert: ZontServerDisconnected
expr: zont_server_connected == 0
for: 5m
labels:
severity: warning
annotations:
summary: "ZONT {{ $labels.device_id }} потерял связь с сервером"
- alert: ZontBoilerDisconnected
expr: zont_boiler_connected == 0
for: 15m
labels:
severity: warning
annotations:
summary: "ZONT {{ $labels.device_id }}: нет связи с котлом (адаптер {{ $labels.adapter_id }})"
- alert: ZontBoilerFail
expr: zont_boiler_fail == 1
for: 5m
labels:
severity: critical
annotations:
summary: "ZONT {{ $labels.device_id }}: авария котла"
- alert: ZontLowVoltage
expr: zont_voltage_volts < 10
for: 5m
labels:
severity: warning
annotations:
summary: "ZONT {{ $labels.device_id }}: низкое напряжение питания {{ $value }} В"
- alert: ZontWeakGSM
expr: zont_gsm_level < 5
for: 15m
labels:
severity: warning
annotations:
summary: "ZONT {{ $labels.device_id }}: слабый сигнал GSM ({{ $value }})"
- alert: ZontHighMemory
expr: zont_memory_used_percent > 85
for: 30m
labels:
severity: info
annotations:
summary: "ZONT {{ $labels.device_id }}: высокая загрузка памяти {{ $value }}%"
🩺 Диагностика
Метрики пустые или /metrics отдаёт только python_*
-
Проверьте логи:
docker logs zont-exporter --tail 100 -
Если непонятно, что происходит, включите подробное логирование:
docker run -d --name zont-exporter \ -p 9101:9101 \ -e ZONT_LOGIN='...' -e ZONT_PASSWORD='...' \ -e ZONT_DEVICE_ID='554007' \ -e ZONT_CLIENT='you@example.com' \ -e LOG_LEVEL='DEBUG' \ zont-exporterЗатем смотрите логи:
docker logs zont-exporter --tail 200В режиме
DEBUGвидны детали ответов API и структураio-объектов. -
Ищите в логах строки:
Successfully obtained ZONT auth token.— токен получен.Failed to get auth token: ...— проблема с логином/паролем.API error: ...— API вернул ошибку.Device 554007 not found in account.— неверныйZONT_DEVICE_ID.Metrics collected successfully for device ...— всё ок.
Ошибка SyntaxError: name 'auth_token' is used prior to global declaration
Объявление global auth_token должно стоять в самом начале функции, до любого использования переменной. В актуальной версии кода это уже учтено.
Ошибка аутентификации
Проверьте логин/пароль руками:
curl -s -X POST 'https://my.zont.online/api/get_authtoken' \
-u 'login:password' \
-H 'X-ZONT-Client: you@example.com' \
-H 'Content-Type: application/json' \
-d '{"client_name": "debug"}' | python3 -m json.tool
Ожидаемый ответ: {"ok": true, "token": "..."}.
Хочу больше данных (история, а не текущее состояние)
Метод devices отдаёт снимок текущего состояния. Историю (графики за период) можно получить через метод load_data с типами z3k_temperature, z3k_heating_circuit, z3k_boiler_adapter, ztc_state. Для этого требуется отдельная логика — при необходимости расширьте экспортер.
⚠️ Ограничения
- Экспортер собирает только текущее состояние, не историю. Для графиков используйте
load_data(см. выше) или смотрите графики в личном кабинете ZONT. - Работает только с устройствами, привязанными к аккаунту my.zont.online. Локальный доступ к контроллеру по USB/локальной сети не используется.
- Тип
thermostat_workчерезload_dataдля модели H1V02_PRO (H-1V.02) возвращает пустые массивы. Используйте данные изdevices?load_io=true— там вся актуальная телеметрия. - Набор доступных полей в
io.z3k-stateзависит от модели, прошивки и конфигурации. Экспортер игнорирует отсутствующие поля — это нормально. - Требуется HTTPS-доступ к
my.zont.online. При использовании прокси задайтеHTTPS_PROXYв окружении контейнера.
🔒 Безопасность
- Не храните логин/пароль в открытом виде в Docker Compose / systemd unit. Используйте:
- Docker secrets,
- переменные окружения из защищённого файла (
--env-file), - внешний секрет-менеджер (Vault, SOPS, Ansible Vault).
- Заведите отдельного пользователя в ZONT для API-интеграции. Не используйте основную учётную запись владельца.
- Ротируйте пароль, если он где-то засветился (переписка, скриншоты, git-история).
- Экспортер не пишет логин/пароль в логи, но может логировать ответ API. Проверьте уровень логирования, если ответы содержат чувствительные данные.
- Токен ZONT (
X-ZONT-Token) хранится только в памяти процесса и перезапрашивается при истечении (unauthorized/token_expired). - Эндпоинт
/metricsне имеет аутентификации. Не выставляйте его в интернет. Используйте network policy / firewall.
📄 Лицензия
MIT. Используйте на свой риск. Проект не связан с ООО «Микро Лайн» / ZONT — это независимая интеграция с публичным API.
🙏 Благодарности
- Команде ZONT за публичное API и документацию.
- Сообществу Prometheus за
prometheus_client.