Files
energys fc8693d74f
Build and Push / maintence (push) Successful in 1s
Build and Push / buildApp (push) Successful in 6s
Build and Push / pushApp (push) Failing after 4s
Fix
2026-09-25 21:20:34 +09:00

393 lines
18 KiB
Markdown
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.
# 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](#-интеграция-с-prometheus)
- [Пример алертов](#-пример-алертов)
- [Диагностика](#-диагностика)
- [Ограничения](#-ограничения)
- [Безопасность](#-безопасность)
- [Лицензия](#-лицензия)
---
## 🚀 Возможности
- **Текущее состояние контроллера**: онлайн-статус, напряжение питания, память, источник питания.
- **Связь**: уровень GSM, состояние регистрации в сети, RSSI Wi-Fi, наличие связи с сервером ZONT.
- **Температуры**: проводные и аналоговые датчики (в т.ч. «Погода из интернета»), статус исправности.
- **Отопление**: целевая и заданная температура по каждому отопительному контуру, время работы.
- **Котёл / OpenTherm**: расчётная температура теплоносителя, уставка ГВС, наличие связи с котлом, аварии.
- **Погода**: температура с внешнего источника.
- **Аналоговые входы**: напряжение на входах (например, контроль питания).
Работает как отдельный контейнер, не требует установки чего-либо на хост.
---
## ✅ Требования
- Docker (или Docker Compose)
- Аккаунт в личном кабинете [my.zont.online](https://my.zont.online) с добавленным устройством ZONT
- Сетевая доступность `my.zont.online:443` из контейнера
- Prometheus (опционально) для сбора метрик
---
## 🏁 Быстрый старт
### 1. Создайте файлы
Вам нужны два файла:
- `zont_exporter.py` — код экспортера
- `Dockerfile` — сборка образа
### 2. Соберите образ
```bash
docker build -t zont-exporter .
```
### 3. Запустите контейнер
```bash
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. Проверьте
```bash
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 (рекомендуется)**
```bash
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 страницы устройства.
### Пример запуска с нестандартным портом и отладкой
```bash
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`:
```yaml
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 (пример)
```yaml
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`:
```yaml
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_*`
1. Проверьте логи:
```bash
docker logs zont-exporter --tail 100
```
2. Если непонятно, что происходит, включите подробное логирование:
```bash
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
```
Затем смотрите логи:
```bash
docker logs zont-exporter --tail 200
```
В режиме `DEBUG` видны детали ответов API и структура `io`-объектов.
3. Ищите в логах строки:
- `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` должно стоять **в самом начале** функции, до любого использования переменной. В актуальной версии кода это уже учтено.
### Ошибка аутентификации
Проверьте логин/пароль руками:
```bash
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 и [документацию](https://my.zont.online/api).
- Сообществу Prometheus за `prometheus_client`.