diff --git a/.gitignore b/.gitignore index 723ef36..0bfed6f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.idea \ No newline at end of file +.* +*.pyc \ No newline at end of file diff --git a/REPORT.md b/REPORT.md new file mode 100644 index 0000000..3902fb4 --- /dev/null +++ b/REPORT.md @@ -0,0 +1,321 @@ +# Шаг 1: Разработка Simulator для генерации данных + +В файле `sensor.py` создаем четвертый тип датчиков *Radiation*, прназначение которого измерять фоновый уровень радиации. + +```python +class Radiation(Sensor): + step = 0 + + def __init__(self, name): + super().__init__(name) + self.type = "radiation" + + def generate_new_value(self): + import math + + self.value = math.sin(self.step) + self.step = self.step + 0.1 +``` + +Далее в файле `main.py` реализовуем клиента, который подключается к mqtt брокеру и публикует сообщения. + + +```python +import paho.mqtt.client as mqttclient +from os import environ +import time + +from entity.sensor import * + +broker = "localhost" if "SIM_HOST" not in environ.keys() else environ["SIM_HOST"] +port = 1883 if "SIM_PORT" not in environ.keys() else int(environ["SIM_PORT"]) +name = "sensor" if "SIM_NAME" not in environ.keys() else environ["SIM_NAME"] +period = 1 if "SIM_PERIOD" not in environ.keys() else int(environ["SIM_PERIOD"]) +type_sim = "temperature" if "SIM_TYPE" not in environ.keys() else environ["SIM_TYPE"] +sensors = { + "temperature": Temperature, + "pressure": Pressure, + "current": Current, + "radiation": Radiation, +} + +isConnected = False + + +def on_connect(client, userdata, flags, rc): + if rc == 0: + print(f"Connected to {broker}") + global isConnected + isConnected = True + else: + print("Is not connected") + + +def on_publish(client, userdata, result): # create function for callback + print("data published") + + +print(f"Configuring {type_sim} {name} {broker}:{port} T={period}") + +sensor = sensors[type_sim](name=name) +client1 = mqttclient.Client(sensor.name) # create client object +client1.on_connect = on_connect +client1.on_publish = on_publish # assign function to callback + + +print("Client configured!") + +time.sleep(1) + +client1.connect(broker, port=port) # establish connection +client1.loop_start() +while True: + sensor.generate_new_value() + ret = client1.publish( + "sensors/" + sensor.type + "/" + sensor.name, sensor.get_data() + ) + time.sleep(period) + +client1.loop_stop() +client1.disconnect() +``` + + +В `Dockerfile`, необходимом для того, что создать образ, указываем следуюещие инструкции: + +``` Dockerfile +FROM python:alpine3.19 +WORKDIR /app +COPY requirements.txt . +RUN pip install -r requirements.txt +COPY . . +CMD ["python", "main.py"] +``` + +`requirements.txt`: +``` +paho_mqtt==1.6.1 +``` + +После проделанных выше опреаций можно создать образ командой: + +`docker build -t arsenier/data-simulator . ` + +Таким образом мы создали образ, из которого можно развернуть контейнер. + +![alt text](image.png) + +# Шаг 2: Запуск Mosquitto брокера + +Для настройки протокола MQTT необходимо создать конфигурационный файл *mosquitto.conf* со следующим содержимымы: + +```c +listener 1883 +allow_anonymous true +``` +Для более удобного запуска брокера создадим файл *docker-compose.yml* со следующим содержимым: + +```yml +version: "3" +services: + broker: + image: eclipse-mosquitto + container_name: broker + volumes: + - ./mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf + ports: + - "1883:1883" +``` + +Теперь создав контейнер (из Шага 1), получим следующее: + +![alt text](image-1.png) + +Брокер же отображает присоединившегося клиента. + +![alt text](image-2.png) + +Теперь можно запустить несколько датчиков. Но перед этим необходимо прописать *docker-compose.yml*: + +```yml +version: "3" + +services: + temp_sensor: + image: arsenier/data-simulator + environment: + - SIM_HOST=192.168.0.101 + - SIM_PORT=1883 + - SIM_NAME=TEMP_STREET + - SIM_PERIOD=5 + - SIM_TYPE=temperature + pressure_sensor: + image: arsenier/data-simulator + environment: + - SIM_HOST=192.168.0.101 + - SIM_NAME=PRESSURE_COLD + - SIM_PERIOD=6 + - SIM_TYPE=pressure + current_sensor: + image: arsenier/data-simulator + environment: + - SIM_HOST=192.168.0.101 + - SIM_NAME=CURRENT_PUMP + - SIM_PERIOD=1 + - SIM_TYPE=current + pressure_sensor2: + image: arsenier/data-simulator + environment: + - SIM_HOST=192.168.0.101 + - SIM_NAME=PRESSURE_HOT + - SIM_PERIOD=4 + - SIM_TYPE=pressure + current_sensor2: + image: arsenier/data-simulator + environment: + - SIM_HOST=192.168.0.101 + - SIM_NAME=CURRENT_DRAIN + - SIM_PERIOD=1 + - SIM_TYPE=current + radiation_sensor: + image: arsenier/data-simulator + environment: + - SIM_HOST=192.168.0.101 + - SIM_NAME=RADIATION + - SIM_PERIOD=10 + - SIM_TYPE=radiation + +``` +С помощью команды `docker compose up` запустим одноврменно 6 контейнеров: + +![alt text](image-3.png) + +При этом брокер отображает: + +![alt text](image-4.png) + +# Шаг 3: Получение данных от симулятора +Первоначально необходимо настроить Telegraf, который подписывается на MQTT, где датчики публикуют данные. Данные будут сохраняться в InfluxDB. Отображение информации с датчиков будет происходить при помощи Grafana. + +## Telegraf +Перед использованием Telegram необходимо настроить его. +Для этого откроем конфигурационный файл *telegraf.conf* и в разделе `[[inputs.mqtt_consumer]]`пропишем следующее: + +```c +servers = ["tcp://192.168.0.101:1883"] # адрес vm с mqtt-брокером +topics = [ + "sensors/#" +] +data_format = "value" +data_type = "float" +``` +Тем самым мы настраиваем Telegraf на чтение данных с машины IP адрес которой 192.168.0.101 через порт 1883. + +Также настроим разедл вывода `[[outputs.influxdb]]`: +```c +urls = ["http://influxdb:8086"] +database = "sensors" +skip_database_creation = true +username = "telegraf" +password = "telegraf" +``` +Настройка Telegraf на этом завршена. + +## InfluDB + +Для создания базы данных необходимо в конфигурационном файле *influxdb-init.iql* прописать следующее: +```sql +CREATE database sensors +CREATE USER telegraf WITH PASSWORD 'telegraf' WITH ALL PRIVILEGES +``` + +## Grafana + +Данные для отображения датчиков берутся из InfluxDB. +Для настройки в конфигурационном файле необходимо прописать следующее: +```yaml +apiVersion: 1 + +datasources: + - name: InfluxDB_v1 + type: influxdb + access: proxy + database: sensors + user: telegraf + url: http://influxdb:8086 + jsonData: + httpMode: GET + secureJsonData: + password: telegraf +``` + +Для запуска всех трех контенйеров воспользуемся docker-compose. + +В *docker-compose.yml* пропишем следующее: + +```yml +version: "3" +services: + influxdb: + image: influxdb:1.8 + container_name: influxdb + volumes: + - ./influxdb/scripts:/docker-entrypoint-initdb.d + - influx_data:/var/lib/influxdb + networks: + - server-net + telegraf: + image: telegraf + container_name: telegraf + volumes: + - ./telegraf:/etc/telegraf:ro + restart: unless-stopped + networks: + - server-net + grafana: + image: grafana/grafana + container_name: grafana + volumes: + - grafana_data:/var/lib/grafana + - ./grafana/:/etc/grafana/ + + environment: + - GF_SECURITY_ADMIN_USER=admin + - GF_SECURITY_ADMIN_PASSWORD=admin + - GF_USERS_ALLOW_SIGN_UP=false + restart: unless-stopped + ports: + - 3000:3000 + networks: + - server-net + +volumes: + influx_data: {} + grafana_data: {} + +networks: + server-net: {} +``` + +После чего можно выполнить команду `docker compose up` + +![alt text](image-5.png) + +# Настройка дашборда +После запуска всех необходимых контейнеров, в браузере переходим по `192.168.0.101:3000` + +![alt text](image-6.png) + +Для проверки соединения перейдем в Menu -> Connections -> Data sources. Находим в истончиках InfluxDB и проверяем подключение: + +![](assets/2024-05-23_12-17.png) + +После создания необходимо количества графиков, отображающих инфомрацию с Simluator, экспортируем дашборд как JSON-файл. + +Для этого находим функцию `Share` -> ``Export` -> `Save to file`. Сохраненный файл помещаем в папку `vms\server\infra\grafana\provisioning\dashboards\mqtt.json` + +# Пример выполненной работы + +![alt text](image-8.png) + +![alt text](image-7.png) \ No newline at end of file diff --git a/assets/2024-05-23_12-17.png b/assets/2024-05-23_12-17.png new file mode 100644 index 0000000..9d8c2ac Binary files /dev/null and b/assets/2024-05-23_12-17.png differ diff --git a/image-1.png b/image-1.png new file mode 100644 index 0000000..c924462 Binary files /dev/null and b/image-1.png differ diff --git a/image-2.png b/image-2.png new file mode 100644 index 0000000..b27eb13 Binary files /dev/null and b/image-2.png differ diff --git a/image-3.png b/image-3.png new file mode 100644 index 0000000..5dc7ef9 Binary files /dev/null and b/image-3.png differ diff --git a/image-4.png b/image-4.png new file mode 100644 index 0000000..df6d75c Binary files /dev/null and b/image-4.png differ diff --git a/image-5.png b/image-5.png new file mode 100644 index 0000000..323654a Binary files /dev/null and b/image-5.png differ diff --git a/image-6.png b/image-6.png new file mode 100644 index 0000000..82e0cf3 Binary files /dev/null and b/image-6.png differ diff --git a/image-7.png b/image-7.png new file mode 100644 index 0000000..85a80e3 Binary files /dev/null and b/image-7.png differ diff --git a/image-8.png b/image-8.png new file mode 100644 index 0000000..04efc7d Binary files /dev/null and b/image-8.png differ diff --git a/image.png b/image.png new file mode 100644 index 0000000..f9ead02 Binary files /dev/null and b/image.png differ diff --git a/vms/client/simulator/.env b/vms/client/simulator/.env new file mode 100644 index 0000000..b33159b --- /dev/null +++ b/vms/client/simulator/.env @@ -0,0 +1,2 @@ +SIM_HOST=192.168.0.101 +SIM_TYPE=temperature \ No newline at end of file diff --git a/vms/client/simulator/docker-compose.yml b/vms/client/simulator/docker-compose.yml index b9e08bb..cd570b0 100644 --- a/vms/client/simulator/docker-compose.yml +++ b/vms/client/simulator/docker-compose.yml @@ -2,23 +2,50 @@ version: "3" services: temp_sensor: - image: antonaleks/data-simulator + image: arsenier/data-simulator environment: - - SIM_HOST=192.168.1.1 - - SIM_NAME=TIRCAHL24 + - SIM_HOST=192.168.0.101 + - SIM_PORT=1883 + - SIM_NAME=TEMP_STREET - SIM_PERIOD=5 - SIM_TYPE=temperature pressure_sensor: - image: antonaleks/data-simulator + image: arsenier/data-simulator environment: - - SIM_HOST=192.168.1.1 - - SIM_NAME=PIRCAHL11 - - SIM_PERIOD=10 + - SIM_HOST=192.168.0.101 + - SIM_NAME=PRESSURE_COLD + - SIM_PERIOD=6 - SIM_TYPE=pressure current_sensor: - image: antonaleks/data-simulator + image: arsenier/data-simulator + environment: + - SIM_HOST=192.168.0.101 + - SIM_NAME=CURRENT_PUMP + - SIM_PERIOD=1 + - SIM_TYPE=current + pressure_sensor2: + image: arsenier/data-simulator + environment: + - SIM_HOST=192.168.0.101 + - SIM_NAME=PRESSURE_HOT + - SIM_PERIOD=4 + - SIM_TYPE=pressure + current_sensor2: + image: arsenier/data-simulator environment: - - SIM_HOST=192.168.1.1 - - SIM_NAME=A0_CURRENT + - SIM_HOST=192.168.0.101 + - SIM_NAME=CURRENT_DRAIN - SIM_PERIOD=1 - SIM_TYPE=current + radiation_sensor: + image: arsenier/data-simulator + environment: + - SIM_HOST=192.168.0.101 + - SIM_NAME=RADIATION + - SIM_PERIOD=10 + - SIM_TYPE=radiation + + +# networks: +# home: +# bridge \ No newline at end of file diff --git a/vms/client/simulator/entity/sensor.py b/vms/client/simulator/entity/sensor.py index 922fea5..7ac5509 100644 --- a/vms/client/simulator/entity/sensor.py +++ b/vms/client/simulator/entity/sensor.py @@ -50,5 +50,20 @@ def __init__(self, name): def generate_new_value(self): import math + self.value = math.sin(self.step) self.step = self.step + 1 + + +class Radiation(Sensor): + step = 0 + + def __init__(self, name): + super().__init__(name) + self.type = "radiation" + + def generate_new_value(self): + import math + + self.value = math.sin(self.step) + self.step = self.step + 0.1 diff --git a/vms/client/simulator/main.py b/vms/client/simulator/main.py index 4d17730..5785c06 100644 --- a/vms/client/simulator/main.py +++ b/vms/client/simulator/main.py @@ -1,4 +1,4 @@ -import paho.mqtt.client as paho +import paho.mqtt.client as mqttclient from os import environ import time @@ -9,19 +9,49 @@ name = "sensor" if "SIM_NAME" not in environ.keys() else environ["SIM_NAME"] period = 1 if "SIM_PERIOD" not in environ.keys() else int(environ["SIM_PERIOD"]) type_sim = "temperature" if "SIM_TYPE" not in environ.keys() else environ["SIM_TYPE"] -sensors = {"temperature": Temperature, "pressure": Pressure, "current": Current} +sensors = { + "temperature": Temperature, + "pressure": Pressure, + "current": Current, + "radiation": Radiation, +} + +isConnected = False + + +def on_connect(client, userdata, flags, rc): + if rc == 0: + print(f"Connected to {broker}") + global isConnected + isConnected = True + else: + print("Is not connected") def on_publish(client, userdata, result): # create function for callback - print(f"data published {userdata}") - pass + print("data published") +print(f"Configuring {type_sim} {name} {broker}:{port} T={period}") + sensor = sensors[type_sim](name=name) -client1 = paho.Client(sensor.name) # create client object +client1 = mqttclient.Client(sensor.name) # create client object +client1.on_connect = on_connect client1.on_publish = on_publish # assign function to callback -client1.connect(broker, port) # establish connection + + +print("Client configured!") + +time.sleep(1) + +client1.connect(broker, port=port) # establish connection +client1.loop_start() while True: sensor.generate_new_value() - ret = client1.publish("sensors/" + sensor.type + "/" + sensor.name, sensor.get_data()) # publish + ret = client1.publish( + "sensors/" + sensor.type + "/" + sensor.name, sensor.get_data() + ) time.sleep(period) + +client1.loop_stop() +client1.disconnect() diff --git a/vms/docker-compose.yml b/vms/docker-compose.yml new file mode 100644 index 0000000..e56095f --- /dev/null +++ b/vms/docker-compose.yml @@ -0,0 +1,33 @@ +version: "3" + +services: + # temp_sensor: + # image: arsenier/data-simulator + # environment: + # - SIM_HOST=127.0.0.1 + # - SIM_NAME=TIRCAHL24 + # - SIM_PERIOD=5 + # - SIM_TYPE=temperature + # - SIM_PORT=1883 + # pressure_sensor: + # image: arsenier/data-simulator + # environment: + # - SIM_HOST=192.168.1.1 + # - SIM_NAME=PIRCAHL11 + # - SIM_PERIOD=10 + # - SIM_TYPE=pressure + # current_sensor: + # image: arsenier/data-simulator + # environment: + # - SIM_HOST=192.168.1.1 + # - SIM_NAME=A0_CURRENT + # - SIM_PERIOD=1 + # - SIM_TYPE=current + + broker: + image: eclipse-mosquitto + container_name: broker + volumes: + - ./gateway/mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf + ports: + - "1883:1883" diff --git a/vms/gateway/docker-compose.yml b/vms/gateway/docker-compose.yml new file mode 100644 index 0000000..a98d85f --- /dev/null +++ b/vms/gateway/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3' +services: + broker: + image: eclipse-mosquitto + container_name: broker + volumes: + - ./mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf + ports: + - "1883:1883" + # networks: + # - home + +# networks: +# home: +# bridge \ No newline at end of file diff --git a/vms/server/infra/grafana/provisioning/dashboards/New dashboard-1716457299101.json b/vms/server/infra/grafana/provisioning/dashboards/New dashboard-1716457299101.json new file mode 100644 index 0000000..05bcaab --- /dev/null +++ b/vms/server/infra/grafana/provisioning/dashboards/New dashboard-1716457299101.json @@ -0,0 +1,585 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 1, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "influxdb", + "uid": "P4B5EB7AC8565B06F" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "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", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P4B5EB7AC8565B06F" + }, + "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": "topic::tag", + "operator": "=", + "value": "sensors/current/CURRENT_DRAIN" + } + ] + }, + { + "datasource": { + "type": "influxdb", + "uid": "P4B5EB7AC8565B06F" + }, + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "mqtt_consumer", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "topic::tag", + "operator": "=", + "value": "sensors/current/CURRENT_PUMP" + } + ] + } + ], + "title": "Panel Title", + "type": "timeseries" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P4B5EB7AC8565B06F" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 4, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "10.4.3", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P4B5EB7AC8565B06F" + }, + "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": "topic::tag", + "operator": "=", + "value": "sensors/pressure/PRESSURE_COLD" + } + ] + }, + { + "datasource": { + "type": "influxdb", + "uid": "P4B5EB7AC8565B06F" + }, + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "mqtt_consumer", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "topic::tag", + "operator": "=", + "value": "sensors/pressure/PRESSURE_HOT" + } + ] + } + ], + "title": "Panel Title", + "type": "gauge" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P4B5EB7AC8565B06F" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 2, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.3", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P4B5EB7AC8565B06F" + }, + "groupBy": [], + "measurement": "mqtt_consumer", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "topic", + "operator": "=", + "value": "sensors/temp/TEMP_STREET" + } + ] + } + ], + "title": "Panel Title", + "type": "stat" + }, + { + "datasource": { + "type": "influxdb", + "uid": "P4B5EB7AC8565B06F" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "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", + "value": null + }, + { + "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": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "P4B5EB7AC8565B06F" + }, + "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": "topic::tag", + "operator": "=", + "value": "sensors/radiation/RADIATION" + } + ] + } + ], + "title": "Panel Title", + "type": "timeseries" + } + ], + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "New dashboard", + "uid": "admk81h2b7j7kf", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/vms/server/infra/telegraf/telegraf.conf b/vms/server/infra/telegraf/telegraf.conf index ddd8b05..4a9c173 100644 --- a/vms/server/infra/telegraf/telegraf.conf +++ b/vms/server/infra/telegraf/telegraf.conf @@ -8558,7 +8558,7 @@ password = "telegraf" # "telegraf/+/mem", # "sensors/#", # ] -servers = ["tcp://192.168.26.1:1883"] # адрес vm с mqtt-брокером +servers = ["tcp://192.168.0.101:1883"] # адрес vm с mqtt-брокером topics = [ "sensors/#" ]