diff --git a/zont-exporter/zont_exporter.py b/zont-exporter/zont_exporter.py index 818fa61..14a37a5 100644 --- a/zont-exporter/zont_exporter.py +++ b/zont-exporter/zont_exporter.py @@ -92,77 +92,112 @@ class ZontCollector(object): return None def collect(self): - """Основной метод, который вызывает Prometheus.""" devices = self._fetch_data() if not devices: - logger.warning("Не удалось получить данные, пропускаем цикл.") return - - # --- Метрики температур --- + + # --- Температуры --- temp_gauge = GaugeMetricFamily( 'zont_temperature_celsius', 'Температура с датчиков ZONT', labels=['device_id', 'device_name', 'sensor_name'] ) - - # --- Метрики состояния котла --- + + # --- Работа котла --- boiler_work_gauge = GaugeMetricFamily( - 'zont_boiler_working', - 'Работает ли котел (1 - да, 0 - нет)', + 'zont_boiler_work_seconds', + 'Время работы котла за последнюю минуту (секунд)', labels=['device_id', 'device_name'] ) - - # --- Метрики уровня сигнала --- + + # --- Режим термостата --- + mode_gauge = GaugeMetricFamily( + 'zont_thermostat_mode', + 'Режим термостата (0=выкл, 1=комфорт, 2=эконом, 3=расписание)', + labels=['device_id', 'device_name'] + ) + + # --- Целевая температура --- + target_gauge = GaugeMetricFamily( + 'zont_target_temperature_celsius', + 'Целевая температура', + labels=['device_id', 'device_name'] + ) + + # --- Авария котла --- + fail_gauge = GaugeMetricFamily( + 'zont_boiler_fail', + 'Авария котла (1 - есть, 0 - нет)', + labels=['device_id', 'device_name'] + ) + + # --- Питание --- + power_gauge = GaugeMetricFamily( + 'zont_power_ok', + 'Наличие основного питания (1/0)', + labels=['device_id', 'device_name'] + ) + + # --- Сигнал GSM --- signal_gauge = GaugeMetricFamily( 'zont_signal_level', - 'Уровень сигнала (GSM или Wi-Fi)', + 'Уровень сигнала GSM', labels=['device_id', 'device_name', 'type'] ) - - # --- Метрики состояния охраны --- - guard_gauge = GaugeMetricFamily( - 'zont_guard_state', - 'Состояние охраны (1 - включена, 0 - выключена)', - labels=['device_id', 'device_name'] - ) - + for device in devices: dev_id = str(device.get('id')) dev_name = device.get('name', 'unknown') io_data = device.get('io', {}) if not io_data: continue - - # --- Обработка термодатчиков --- + + # --- Термодатчики --- for sensor in device.get('thermometers', []): if sensor.get('is_assigned_to_slot') and sensor.get('last_value') is not None: temp_gauge.add_metric( [dev_id, dev_name, sensor.get('name', 'sensor')], sensor['last_value'] ) - - # --- Обработка состояния котла --- + + # --- Состояние котла --- boiler_state = io_data.get('last-boiler-state') if boiler_state: - is_working = 1 if boiler_state.get('boiler_work_time', 0) > 0 else 0 - boiler_work_gauge.add_metric([dev_id, dev_name], is_working) - - # --- Обработка уровня сигнала GSM --- + # Время работы котла + work_time = boiler_state.get('boiler_work_time', 0) + boiler_work_gauge.add_metric([dev_id, dev_name], work_time) + + # Режим (строку в число) + mode_map = {'idle': 0, 'comfort': 1, 'econom': 2, 'schedule': 3} + mode_str = boiler_state.get('thermostat_mode', 'idle') + mode_gauge.add_metric([dev_id, dev_name], mode_map.get(mode_str, 0)) + + # Целевая температура + target = boiler_state.get('target_temp') + if target is not None: + target_gauge.add_metric([dev_id, dev_name], target) + + # Авария + fail = boiler_state.get('fail', False) + fail_gauge.add_metric([dev_id, dev_name], 1 if fail else 0) + + # Питание + power = boiler_state.get('power', True) + power_gauge.add_metric([dev_id, dev_name], 1 if power else 0) + + # --- GSM --- gsm_state = io_data.get('gsm-state') if gsm_state and gsm_state.get('level') is not None: signal_gauge.add_metric([dev_id, dev_name, 'gsm'], gsm_state['level']) - - # --- Обработка состояния охраны --- - guard_state = io_data.get('guard-state') - if guard_state is not None: - is_guarded = 1 if guard_state == 'enabled' else 0 - guard_gauge.add_metric([dev_id, dev_name], is_guarded) - + yield temp_gauge yield boiler_work_gauge + yield mode_gauge + yield target_gauge + yield fail_gauge + yield power_gauge yield signal_gauge - yield guard_gauge - + if __name__ == '__main__': REGISTRY.register(ZontCollector())