diff --git a/root/assets/images/A_sensors_ps.png b/root/assets/images/A_sensors_ps.png new file mode 100644 index 0000000..8bd2bb6 Binary files /dev/null and b/root/assets/images/A_sensors_ps.png differ diff --git a/root/assets/images/B_mosquitto_ps.png b/root/assets/images/B_mosquitto_ps.png new file mode 100644 index 0000000..4b1e8a3 Binary files /dev/null and b/root/assets/images/B_mosquitto_ps.png differ diff --git a/root/assets/images/C_grafana_dashboard_1.png b/root/assets/images/C_grafana_dashboard_1.png new file mode 100644 index 0000000..cbdaa58 Binary files /dev/null and b/root/assets/images/C_grafana_dashboard_1.png differ diff --git a/root/assets/images/C_grafana_dashboard_2.png b/root/assets/images/C_grafana_dashboard_2.png new file mode 100644 index 0000000..0e92c99 Binary files /dev/null and b/root/assets/images/C_grafana_dashboard_2.png differ diff --git a/root/assets/images/C_stack_ps.png b/root/assets/images/C_stack_ps.png new file mode 100644 index 0000000..55111ce Binary files /dev/null and b/root/assets/images/C_stack_ps.png differ diff --git a/root/assets/images/MQTT.png b/root/assets/images/MQTT.png new file mode 100644 index 0000000..d9eb915 Binary files /dev/null and b/root/assets/images/MQTT.png differ diff --git a/root/assets/images/linA_docker status.png b/root/assets/images/linA_docker status.png new file mode 100644 index 0000000..2df96fa Binary files /dev/null and b/root/assets/images/linA_docker status.png differ diff --git a/root/assets/images/linB_docker status.png b/root/assets/images/linB_docker status.png new file mode 100644 index 0000000..ab5ddfa Binary files /dev/null and b/root/assets/images/linB_docker status.png differ diff --git a/root/assets/images/linC_docker status.png b/root/assets/images/linC_docker status.png new file mode 100644 index 0000000..0b16a4f Binary files /dev/null and b/root/assets/images/linC_docker status.png differ diff --git a/root/report.md b/root/report.md new file mode 100644 index 0000000..92fc947 --- /dev/null +++ b/root/report.md @@ -0,0 +1,101 @@ +# Отчет по практической работе: Развертывание системы мониторинга IoT с Docker + +**Цель работы:** Развернуть и настроить распределенную систему для симуляции, сбора, хранения и визуализации данных от IoT-датчиков с использованием Docker и Docker Compose на трех виртуальных машинах Linux. + +**Используемые инструменты:** VirtualBox, Ubuntu Server 24.04 LTS, Docker, Docker Compose, Python 3 (с библиотекой `paho-mqtt`), Mosquitto, InfluxDB 1.8.10, Telegraf, Grafana. + +**Личные данные:** +* Фамилия: ismukhanova +* День рождения: 13 +* Месяц рождения: 08 + +--- + +## 1. Подготовка Инфраструктуры и Установка Docker + +* **Виртуальные машины:** Использованы три виртуальные машины (`Linux-A`, `Linux-B`, `Linux-C`), настроенные в предыдущей лабораторной работе. +* **Установка Docker и Docker Compose:** На каждой из трех виртуальных машин были выполнены шаги по установке Docker Engine и плагина Docker Compose из официальных репозиториев Docker. Членство текущего пользователя было добавлено в группу `docker` для выполнения команд без `sudo`. +--- + +## 2. Настройка Linux-B (ismukhanovagateway) - Mosquitto MQTT Broker + +* **Цель:** Развернуть MQTT-брокер для обмена сообщениями между симуляторами и сборщиком данных. +* **Действия:** + 1. На `Linux-B` создана директория `~/mosquitto_config`. + 2. Внутри нее создан файл `mosquitto.conf` со следующей конфигурацией: + ```conf + # Полный файл в репозитории: vms/gateway/mosquitto/mosquitto.conf + persistence true + persistence_location /mosquitto/data/ + log_dest stdout + allow_anonymous true + listener 1883 + ``` + 3. Запущен контейнер Mosquitto с использованием официального образа `eclipse-mosquitto`: + ```bash + # На Linux-B + sudo docker run -d \ + -p 1883:1883 \ + -v /home/ismukhanova_2/mosquitto_config/mosquitto.conf:/mosquitto/config/mosquitto.conf \ + -v /home/ismukhanova_2/mosquitto_data:/mosquitto/data \ + --name mqtt_broker \ + --restart unless-stopped \ + eclipse-mosquitto + ``` + 4. Проверен статус контейнера `mqtt_broker` и его логи. + 5. Настроен файрвол `ufw` на `Linux-B` для разрешения входящих соединений на порт `1883/tcp`. +## 3. Настройка Linux-A (ismukhanovaserver) - Симуляторы Сенсоров + +![Mosquitto PS B](<./assets/images/B_mosquitto_ps.png>) + + +* **Цель:** Создать и запустить Docker-контейнеры, симулирующие отправку данных от различных датчиков на MQTT-брокер. +* **Действия:** + 1. На `Linux-A` создана структура директорий `~/sensor_project/sensor_app/`. + 2. Установлена библиотека `paho-mqtt` для Python. + 3. Разработан скрипт `sensor_simulator.py` (класс `Sensor`, чтение конфигурации из переменных окружения, подключение к MQTT-брокеру на `Linux-B` (IP `192.168.13.1`), публикация JSON-данных). + 4. Создан `Dockerfile` на базе `python:3.9-slim`. + 5. Собран Docker-образ `iasiks/sensor-simulator:latest` (используя твой Docker Hub ID). + 6. Образ опубликован на Docker Hub. + 7. Создан `docker-compose.yml` для запуска 6 контейнеров-симуляторов (4 типа датчиков) с разными конфигурациями и опциями `tty: true`, `stdin_open: true`. + 8. Контейнеры симуляторов запущены (`docker compose up -d`). + +![Sensor Log A](<./assets/images/A_sensors_ps.png>) + + +## 4. Настройка Linux-C - Стек Мониторинга (InfluxDB, Telegraf, Grafana) + +* **Цель:** Развернуть компоненты для сбора, хранения и визуализации данных. +* **Действия:** + 1. На `Linux-C` создана структура директорий `~/iot_stack/` с поддиректориями для конфигураций Telegraf и Grafana Provisioning. + 2. Подготовлен `telegraf.conf` с настройками `outputs.influxdb` (URL `http://influxdb_server:8086`, БД `sensors`, пользователь `telegraf`) и `inputs.mqtt_consumer` (сервер `:1883`, топики `sensors/#`, `data_format = "json_v2"` с парсингом `measurement_name_path = "@topic[1]"`). + 3. Подготовлены файлы Grafana Provisioning: `datasources/influxdb_datasource.yaml` и `dashboards/dashboards_provider.yaml`. + 4. Создан `docker-compose.yml` для запуска `influxdb:1.8.10`, `telegraf`, `grafana/grafana` в общей сети `iot_monitoring_network` с именованными томами и монтированием конфигураций. + 5. Стек запущен (`docker compose up -d`). + 6. В CLI InfluxDB создана база данных `sensors` и пользователь `telegraf` с паролем и правами. + 7. Проверен источник данных в Grafana и создан дашборд "Мониторинг Сенсоров". + 8. JSON-модель дашборда экспортирована и добавлена в директорию для provisioning. Grafana перезапущена. + +![Stack PS C](<./assets/images/C_stack_ps.png>) + + + +## 5. Результаты и Визуализация + +* **Поток данных:** Данные от симуляторов на `Linux-A` успешно передаются через MQTT-брокер на `Linux-B`, собираются Telegraf на `Linux-C`, сохраняются в InfluxDB и визуализируются в Grafana. +* **Дашборд Grafana:** Настроенный дашборд "Мониторинг Сенсоров" доступен через веб-интерфейс (`http://192.168.31.102:3000`) и корректно отображает показания всех 6 запущенных симуляторов сенсоров, а также агрегированные значения. Дашборд успешно загружается автоматически благодаря механизму provisioning. +* **Персистентность:** Данные InfluxDB и конфигурации/дашборды Grafana сохраняются между перезапусками контейнеров. Контейнеры с политикой `restart: unless-stopped` автоматически запускаются после перезагрузки ВМ. + +![Final Grafana Dashboard 1](<./assets/images/C_grafana_dashboard_1.png>) + +![Final Grafana Dashboard 2](<./assets/images/C_grafana_dashboard_2.png>) + +--- + +## 6. Выводы + +В ходе выполнения практической работы была успешно развернута и настроена распределенная система мониторинга IoT-данных с использованием Docker и Docker Compose. Продемонстрирована настройка взаимодействия между симуляторами сенсоров, MQTT-брокером, сборщиком метрик Telegraf, базой данных временных рядов InfluxDB и платформой визуализации Grafana, развернутыми на трех отдельных виртуальных машинах. Реализована автоматическая настройка компонентов Grafana через provisioning. Обеспечена персистентность данных. Все компоненты системы успешно взаимодействуют, данные корректно собираются, хранятся и визуализируются. + +--- + + diff --git a/root/vms/client/Dockerfile b/root/vms/client/Dockerfile new file mode 100644 index 0000000..48e85c2 --- /dev/null +++ b/root/vms/client/Dockerfile @@ -0,0 +1,15 @@ +# Используем легковесный базовый образ Python +FROM python:3.9-slim + +# Устанавливаем рабочую директорию в контейнере +WORKDIR /app + +# Копируем файл с зависимостями и устанавливаем их +COPY sensor_app/requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +# Копируем код приложения в рабочую директорию контейнера +COPY sensor_app/ . + +# Команда, которая будет выполняться при запуске контейнера +CMD ["python", "sensor_simulator.py"] \ No newline at end of file diff --git a/root/vms/client/docker-compose.yml b/root/vms/client/docker-compose.yml new file mode 100644 index 0000000..05c5878 --- /dev/null +++ b/root/vms/client/docker-compose.yml @@ -0,0 +1,90 @@ +services: + temperature_sensor_1: + image: iasiks/sensor-simulator:latest # Убедись, что это имя твоего локально собранного образа + container_name: temp_sensor_alpha + restart: unless-stopped + tty: true + stdin_open: true + environment: + - MQTT_BROKER_HOST=192.168.31.103 + - MQTT_BROKER_PORT=1883 + - SENSOR_NAME=alpha_temp + - SENSOR_TYPE=temperature + - PUBLISH_INTERVAL=10 + - BIRTH_DAY_OPERAND=13 # Твой день рождения + - TOPIC_STYLE=json + + pressure_sensor_1: + image: iasiks/sensor-simulator:latest + container_name: pressure_sensor_beta + restart: unless-stopped + tty: true + stdin_open: true + environment: + - MQTT_BROKER_HOST=192.168.31.103 + - MQTT_BROKER_PORT=1883 + - SENSOR_NAME=beta_pressure + - SENSOR_TYPE=pressure + - PUBLISH_INTERVAL=12 + - BIRTH_DAY_OPERAND=13 + - TOPIC_STYLE=json + + current_sensor_1: + image: iasiks/sensor-simulator:latest + container_name: current_sensor_gamma + restart: unless-stopped + tty: true + stdin_open: true + environment: + - MQTT_BROKER_HOST=192.168.31.103 + - MQTT_BROKER_PORT=1883 + - SENSOR_NAME=gamma_current + - SENSOR_TYPE=current + - PUBLISH_INTERVAL=15 + - BIRTH_DAY_OPERAND=13 + - TOPIC_STYLE=json + + humidity_sensor_1: + image: iasiks/sensor-simulator:latest + container_name: humidity_sensor_delta + restart: unless-stopped + tty: true + stdin_open: true + environment: + - MQTT_BROKER_HOST=192.168.31.103 + - MQTT_BROKER_PORT=1883 + - SENSOR_NAME=delta_humidity + - SENSOR_TYPE=humidity + - PUBLISH_INTERVAL=18 + - BIRTH_DAY_OPERAND=13 + - TOPIC_STYLE=json + + temperature_sensor_2: + image: iasiks/sensor-simulator:latest + container_name: temp_sensor_epsilon + restart: unless-stopped + tty: true + stdin_open: true + environment: + - MQTT_BROKER_HOST=192.168.31.103 + - MQTT_BROKER_PORT=1883 + - SENSOR_NAME=epsilon_temp + - SENSOR_TYPE=temperature + - PUBLISH_INTERVAL=11 + - BIRTH_DAY_OPERAND=13 + - TOPIC_STYLE=json + + pressure_sensor_2: + image: iasiks/sensor-simulator:latest + container_name: pressure_sensor_zeta + restart: unless-stopped + tty: true + stdin_open: true + environment: + - MQTT_BROKER_HOST=192.168.31.103 + - MQTT_BROKER_PORT=1883 + - SENSOR_NAME=zeta_pressure + - SENSOR_TYPE=pressure + - PUBLISH_INTERVAL=14 + - BIRTH_DAY_OPERAND=13 + - TOPIC_STYLE=json \ No newline at end of file diff --git a/root/vms/client/requirements.txt b/root/vms/client/requirements.txt new file mode 100644 index 0000000..d173f65 --- /dev/null +++ b/root/vms/client/requirements.txt @@ -0,0 +1 @@ +paho-mqtt \ No newline at end of file diff --git a/root/vms/client/sensor_simulator.py b/root/vms/client/sensor_simulator.py new file mode 100644 index 0000000..7fe2540 --- /dev/null +++ b/root/vms/client/sensor_simulator.py @@ -0,0 +1,140 @@ +import paho.mqtt.client as mqtt +import time +import random +import os +import json + +# Базовый класс Sensor +class Sensor: + def __init__(self, sensor_name, sensor_type, birth_date_operand): + self.sensor_name = sensor_name + self.sensor_type = sensor_type + self.birth_date_operand = birth_date_operand + self.current_value = self._initialize_value() + + def _initialize_value(self): + if self.sensor_type == "temperature": + return random.uniform(15.0, 25.0) + elif self.sensor_type == "pressure": + return random.uniform(980.0, 1050.0) + elif self.sensor_type == "current": + return random.uniform(0.5, 5.0) + elif self.sensor_type == "humidity": + return random.uniform(30.0, 70.0) + else: + return random.uniform(0, 100) + + def generate_new_value(self): + change = random.uniform(-0.5, 0.5) + modifier_from_birth = 1.0 + if self.birth_date_operand != 0: + modifier_from_birth = self.birth_date_operand / 10.0 if self.birth_date_operand >=1 else 1.0 + + if self.sensor_type == "temperature": + self.current_value += change * modifier_from_birth + self.current_value = max(0, min(50, self.current_value)) + elif self.sensor_type == "pressure": + self.current_value += change * 5 * modifier_from_birth + self.current_value = max(900, min(1100, self.current_value)) + elif self.sensor_type == "current": + self.current_value += change * 0.1 * modifier_from_birth + self.current_value = max(0, min(10, self.current_value)) + elif self.sensor_type == "humidity": + self.current_value += change * 2 * modifier_from_birth + self.current_value = max(0, min(100, self.current_value)) + else: + self.current_value += change + return round(self.current_value, 2) + + def get_topic_and_payload_type(self, topic_style="json"): + value = self.generate_new_value() + + topic_for_default_style = f"sensors/{self.sensor_type}" + payload = json.dumps({"name": self.sensor_name, "value": value}) + + if topic_style == "value_in_topic": + topic_for_value_style = f"sensors/{self.sensor_type}/{self.sensor_name}/value" + payload_for_value_style = str(value) + return topic_for_value_style, payload_for_value_style + + return topic_for_default_style, payload + + +def on_connect(client, userdata, flags, rc): + if rc == 0: + print(f"INFO [{client._client_id.decode() if client._client_id else 'UnknownSensor'}]: Connected to MQTT Broker!") + else: + print(f"ERROR [{client._client_id.decode() if client._client_id else 'UnknownSensor'}]: Failed to connect to MQTT Broker, return code {rc}") + +def on_publish(client, userdata, mid): + pass + +if __name__ == "__main__": + MQTT_BROKER_HOST = os.getenv("MQTT_BROKER_HOST", "localhost") + MQTT_BROKER_PORT_STR = os.getenv("MQTT_BROKER_PORT", "1883") + try: + MQTT_BROKER_PORT = int(MQTT_BROKER_PORT_STR) + except ValueError: + print(f"FATAL ERROR (Initial Env Parse): Invalid MQTT_BROKER_PORT: '{MQTT_BROKER_PORT_STR}'. Must be an integer.") + exit(1) + + SENSOR_NAME = os.getenv("SENSOR_NAME", "default_sensor") + SENSOR_TYPE = os.getenv("SENSOR_TYPE", "temperature") + PUBLISH_INTERVAL_STR = os.getenv("PUBLISH_INTERVAL", "5") + try: + PUBLISH_INTERVAL = int(PUBLISH_INTERVAL_STR) + if PUBLISH_INTERVAL <= 0: + print(f"WARN [{SENSOR_NAME}]: PUBLISH_INTERVAL ('{PUBLISH_INTERVAL_STR}') is not positive, defaulting to 5 seconds.") + PUBLISH_INTERVAL = 5 + except ValueError: + print(f"FATAL ERROR [{SENSOR_NAME}]: Invalid PUBLISH_INTERVAL: '{PUBLISH_INTERVAL_STR}'. Must be an integer.") + exit(1) + + BIRTH_DAY_STR = os.getenv("BIRTH_DAY_OPERAND", "13") + try: + BIRTH_DAY = int(BIRTH_DAY_STR) + except ValueError: + print(f"FATAL ERROR [{SENSOR_NAME}]: Invalid BIRTH_DAY_OPERAND: '{BIRTH_DAY_STR}'. Must be an integer.") + exit(1) + + TOPIC_STYLE = os.getenv("TOPIC_STYLE", "json") + + print(f"\n--- Sensor Simulator Starting: {SENSOR_NAME} ({SENSOR_TYPE}) ---") + print(f"Target MQTT Broker: {MQTT_BROKER_HOST}:{MQTT_BROKER_PORT}") + print(f"Publish Interval: {PUBLISH_INTERVAL}s, Topic Style: {TOPIC_STYLE}") + print(f"-----------------------------------------------------\n") + + client_id = f"sensor-{SENSOR_NAME}-{random.randint(0,10000)}" + client = mqtt.Client(client_id=client_id, callback_api_version=mqtt.CallbackAPIVersion.VERSION1) + client.user_data_set(SENSOR_NAME) + client.on_connect = on_connect + client.on_publish = on_publish + + try: + client.connect(MQTT_BROKER_HOST, MQTT_BROKER_PORT, 60) + except Exception as e: + print(f"FATAL ERROR [{SENSOR_NAME}]: Could not connect to MQTT Broker: {e}") + exit(1) + + client.loop_start() + sensor = Sensor(SENSOR_NAME, SENSOR_TYPE, BIRTH_DAY) + + try: + while True: + topic, payload = sensor.get_topic_and_payload_type(TOPIC_STYLE) + result = client.publish(topic, payload) + status = result[0] + if status == 0: + print(f"INFO [{SENSOR_NAME}]: Sent `{payload}` to topic `{topic}`") + else: + print(f"ERROR [{SENSOR_NAME}]: Failed to send message to topic {topic}, status: {status}") + + time.sleep(PUBLISH_INTERVAL) + except KeyboardInterrupt: + print(f"INFO [{SENSOR_NAME}]: Simulation stopped by user (KeyboardInterrupt).") + except Exception as e: + print(f"FATAL ERROR [{SENSOR_NAME}]: An error occurred in the main loop: {e}") + finally: + print(f"INFO [{SENSOR_NAME}]: Stopping and disconnecting...") + client.loop_stop() + client.disconnect() \ No newline at end of file diff --git a/root/vms/gateway/mosquitto/mosquitto.conf b/root/vms/gateway/mosquitto/mosquitto.conf new file mode 100644 index 0000000..796fe76 --- /dev/null +++ b/root/vms/gateway/mosquitto/mosquitto.conf @@ -0,0 +1,5 @@ +persistence true +persistence_location /mosquitto/data/ +log_dest stdout +allow_anonymous true +listener 1883 \ No newline at end of file diff --git a/root/vms/server/docker-compose.yml b/root/vms/server/docker-compose.yml new file mode 100644 index 0000000..fd63315 --- /dev/null +++ b/root/vms/server/docker-compose.yml @@ -0,0 +1,51 @@ +services: + influxdb: + image: influxdb:1.8 + container_name: influxdb_server + restart: unless-stopped + ports: + - "8086:8086" + volumes: + - influxdb_storage:/var/lib/influxdb + environment: + + - INFLUXDB_DB=sensors_temp + networks: + - iot_network + + telegraf: + image: telegraf:latest + container_name: telegraf_agent + restart: unless-stopped + volumes: + - ./telegraf_config/telegraf.conf:/etc/telegraf/telegraf.conf:ro # Монтируем конфиг Telegraf (ro - read-only) + depends_on: + - influxdb # Запускать Telegraf после InfluxDB + networks: + - iot_network + + grafana: + image: grafana/grafana:latest + container_name: grafana_server + restart: unless-stopped + ports: + - "3000:3000" # Порт для веб-интерфейса Grafana + volumes: + - grafana_storage:/var/lib/grafana # Именованный том для данных Grafana (дашборды, пользователи и т.д.) + - ./grafana_config/provisioning/datasources:/etc/grafana/provisioning/datasources:ro # Provisioning для источников данных + - ./grafana_config/provisioning/dashboards:/etc/grafana/provisioning/dashboards:ro # Provisioning для папки дашбордов + environment: + - GF_SECURITY_ADMIN_USER=admin + - GF_SECURITY_ADMIN_PASSWORD=admin + depends_on: + - influxdb + networks: + - iot_network + +volumes: + influxdb_storage: # Определяем именованный том для InfluxDB + grafana_storage: # Определяем именованный том для Grafana + +networks: + iot_network: # Определяем пользовательскую сеть для этих сервисов + driver: bridge \ No newline at end of file diff --git a/root/vms/server/grafana/provisioning/dashboards/dashboards_provider.yaml b/root/vms/server/grafana/provisioning/dashboards/dashboards_provider.yaml new file mode 100644 index 0000000..d1e667e --- /dev/null +++ b/root/vms/server/grafana/provisioning/dashboards/dashboards_provider.yaml @@ -0,0 +1,12 @@ +apiVersion: 1 + +providers: + - name: 'SensorDashboards' + orgId: 1 + folder: '' + type: file + disableDeletion: false + editable: true + allowUiUpdates: true + options: + path: /etc/grafana/provisioning/dashboards \ No newline at end of file diff --git a/root/vms/server/grafana/provisioning/dashboards/sensor_overview_dashboard.json b/root/vms/server/grafana/provisioning/dashboards/sensor_overview_dashboard.json new file mode 100644 index 0000000..4bb0d99 --- /dev/null +++ b/root/vms/server/grafana/provisioning/dashboards/sensor_overview_dashboard.json @@ -0,0 +1,675 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 1, + "links": [], + "panels": [ + { + "datasource": { + "type": "influxdb", + "uid": "P279BEF41BBDF73F8" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.0.1", + "targets": [ + { + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "mqtt_consumer", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "name::tag", + "operator": "=", + "value": "alpha_temp" + } + ] + } + ], + "title": "График температуры", + "type": "timeseries" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P279BEF41BBDF73F8" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.0.1", + "targets": [ + { + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "mqtt_consumer", + "orderByTime": "ASC", + "policy": "autogen", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "name::tag", + "operator": "=", + "value": "beta_pressure" + } + ] + } + ], + "title": "График давления", + "type": "timeseries" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P279BEF41BBDF73F8" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.0.1", + "targets": [ + { + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "mqtt_consumer", + "orderByTime": "ASC", + "policy": "autogen", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "name::tag", + "operator": "=", + "value": "delta_humidity" + } + ] + } + ], + "title": "График влажности", + "type": "timeseries" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P279BEF41BBDF73F8" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.0.1", + "targets": [ + { + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "mqtt_consumer", + "orderByTime": "ASC", + "policy": "autogen", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "name::tag", + "operator": "=", + "value": "epsilon_temp" + } + ] + } + ], + "title": "График eps температуры", + "type": "timeseries" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P279BEF41BBDF73F8" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 16 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.0.1", + "targets": [ + { + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "mqtt_consumer", + "orderByTime": "ASC", + "policy": "autogen", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "name::tag", + "operator": "=", + "value": "zeta_pressure" + } + ] + } + ], + "title": "График zeta давления", + "type": "timeseries" + } + ], + "preload": false, + "schemaVersion": 41, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "New dashboard", + "uid": "cd425eff-e374-4031-b208-da4727f37d20", + "version": 6 +} \ No newline at end of file diff --git a/root/vms/server/grafana/provisioning/datasources/influxdb_datasource.yaml b/root/vms/server/grafana/provisioning/datasources/influxdb_datasource.yaml new file mode 100644 index 0000000..dae5813 --- /dev/null +++ b/root/vms/server/grafana/provisioning/datasources/influxdb_datasource.yaml @@ -0,0 +1,17 @@ +apiVersion: 1 + +datasources: + - name: InfluxDB_Sensors + type: influxdb + access: proxy + url: http://influxdb:8086 + database: sensors + user: telegraf + isDefault: true + jsonData: + dbName: sensors + httpMode: POST + timeInterval: "10s" + version: InfluxQL + secureJsonData: + password: "telegraf_password_safe" \ No newline at end of file diff --git a/root/vms/server/telegraf/telegraf.conf b/root/vms/server/telegraf/telegraf.conf new file mode 100644 index 0000000..c01a64d --- /dev/null +++ b/root/vms/server/telegraf/telegraf.conf @@ -0,0 +1,35 @@ +[agent] + interval = "10s" + round_interval = true + metric_batch_size = 1000 + metric_buffer_limit = 10000 + collection_jitter = "0s" + flush_interval = "10s" + flush_jitter = "0s" + + precision = "" + debug = true + quiet = false + hostname = "" + omit_hostname = false + +[[outputs.influxdb]] + urls = ["http://influxdb_server:8086"] + database = "sensors" + precision = "s" + timeout = "5s" + username = "telegraf" + password = "telegraf_password_safe" + skip_database_creation = true + +[[inputs.mqtt_consumer]] + servers = ["tcp://192.168.8.1:1883"] + topics = [ + "sensors/#", + ] + +data_format = "json" +tag_keys = [ + "name", + "value" +] \ No newline at end of file