Введение

В данной статье приведен скоуп информации о том, что взять за основу, чтобы развернуть свой домашний Linux-сервер и систему визуализации на нем, используя MQTT в качестве транспорта с оконечного оборудования. 

Многие статьи или инструкции, которые есть в интернете, в части работы с InfluxDB и Telegraf – имеют отношения к довольно старым версиям рассматриваемого ПО, в виду чего у меня ушло какое-то время, чтобы со всем разобраться. Хотелось бы оставить небольшое обновление по инструкциям здесь, возможно, они помогут кому-то сэкономить время и нервы, так как информация агрегирована в виде summury моего погружения в реализацию данного решения. 

Значит понадобилось, как оно водится, по работе, часто взаимодействовать с Linux: CentOS/RHEL, Debian/Ubuntu Server и даже с немного специфичным Clear Linux, специально собранный под процессоры Intel, что дает прирост в производительности во многих бенчмарках (например, тык).

Держать у себя постоянно включенную виртуальную машину стало накладно и решено было найти какой-нибудь интересный мини-пк на просторах популярной китайской площадки, дабы вынести все рабочие моменты на отдельное железо. Бонусом я также получил возможность дополнить данный мини-пк функционалом домашнего Linux-сервера, назначение которого варьируется сколь угодно широко, в зависимости от вашей фантазии. 

В моем случае, учитывая контекст работы и дополнительное увлечение в виде преподавания в сфере IoT, я решил показать студентам, как самим собрать систему визуализации для дипломных устройств, где транспортом для передачи данных служит знакомый им MQTT. 

Состав и описание решения

Рассмотрим состав решения :

Схема взаимодействия компонентов ПО
Схема взаимодействия компонентов ПО
  1. Оконечное оборудование, собирающее телеметрию, доступом в интернет, разрабатываемое студентами индивидуально.

    На оконечном оборудовании реализуется MQTT клиент, который публикует в определённый топик MQTT брокера некую информацию, например, температуру окружающей среды в градусах цельсия.

  2. Mosquitto MQTT broker.

    MQTT брокер служит неким посредником, который позволяет собирать (принимать) информацию от устройств в определенные топики и сразу же «отдавать» ее клиентам, которые эти топики слушают для сбора, обработки, анализа, визуализации получаемых данных.

  3. Telegraf.

    Чтобы получить информацию от MQTT брокера, также необходим клиент, который подписывается на топики брокера для получения данных, реализуя тем самым паттерн Издатель-подписчик (англ. publisher-subscriber или англ. pub/sub). Для этого и используется Telegraf. Он, как клиент-подписчик, прослушивает заданные MQTT топики и, получив сообщение, сразу же записывает информацию в InfluxDB. Вообще, Telegraf – это не только MQTT клиент. Telegraf – это серверный агент для сбора, обработки, агрегирования и записи метрик из различных стеков, датчиков и систем в InfluxDB.

  4. InfluxDB.

    InfluxDB – это система баз данных, оптимизированная для предоставления данных временных рядов и их хранения в привязке ко времени и значению (иными словами база данных временных рядов (time series database – TSDB)), разработанная компанией InfluxData.

    И немного про временные ряды и их данные.

    Временной ряд – это совокупность наблюдений за четко определенными элементами данных, полученных в результате повторяющихся измерений в течение определенного времени. Данные временного ряда индексируются во временном порядке, который представляет собой последовательность точек данных. 

    В InfluxDB есть встроенный конструктор дашбордов для визуализации – Chronograf, на котором можно было бы и остановиться, но он больше сделан для быстрого прототипирования дашбордов и проверки отображения тех или иных метрик в том или ином виде в самой InfluxDB. Гораздо удобнее использовать платформу Grafana, которая является плюс минус стандартном в вопросах визуализации (особенно в сфере IoT). Для этого будет настраиваться интеграция в Grafana на подключение к InfluxDB.

  5. Grafana.

    Grafana – программное обеспечение с открытым исходным кодом, позволяющее запрашивать, визуализировать и исследовать метрики (данные), где бы они ни хранились. По сути, предоставляет пользователю инструменты для преобразования информации из базы данных временных рядов (TSDB) в удобные графики и визуализации.

  6. Node-RED*.

    Это инструмент визуального программирования для интернета вещей, позволяющий подключать друг к другу устройства, API и онлайн-сервисы. Выступает в роли многофункцильного бекэнда с поддержкой множества интерфейсов и протоколов. 

    Звездочка здесь стоит только потому, что данный компонент не обязателен, но всегда должна быть альтернатива, и Node-RED позволяет собирать и передавать данные альтернативным от Telegraf способом, имея мощный функционал промежуточной обработки.

  7. WireGuard.

    Современный VPN-протокол. Необходим, чтобы подключаться к нашему серверу из любой точки через домашнюю сеть. Приятное дополнение – это возможность шифровать трафик в любой публичной Wi-Fi сети без существенных ограничений по скорости и задержкам.

На чем все запускать?

Сердце домашнего сервера и обитель всех рассматриваемых программных компонентов в моем случае – мини-пк Beelink U59 в конфигурации 16(8+8)RAM/512SSD на базе процессора Intel Celeron N5095. Таких характеристик хватит с запасом под разные задачи. Получается отличный вариант по качеству, производительности, сборке. Особенно в контексте цены – 250$, а если еще и распродажа, сами понимаете. На борту есть гигабитный Ethernet-порт и Wi-FI 5 (ac). И все это в очень компактном корпусе.

Очень радует функция автоматического включения в случае пропадания и восстановления питания. Действительно получается такой мини-сервер, который всегда включен, если есть электричество. Дело остается за малым: чтобы и доступ в интернет не пропадал.

Изначально думал взять какой-нибудь микрокомпьютер, а-ля Raspberry Pi 4 или что-то похожее. Но против тех.спеки не попрешь: U59 на мой взгляд гораздо производительнее и удобнее под рассматриваемые задачи, а стоит аналогично Pi 4. (Если говорить о производительности, то тот же Geekbench на U59 показывает 711/2308 (тык) против 337/877 на Pi 4 (тык

Ознакомиться с подробными техническими характеристиками и отзывами можно по ссылке (тык), а выглядит он вот так:

Вы можете поступить аналогичным образом и раздобыть себе такой же или аналогичный мини-пк. Возможно, перепрофилировать какой-нибудь старый ноутбук или компьютер под эти задачи, или, в конце концов, развернуть виртуальную машину с характеристиками: 1GB RAM/ 1 CPU / 15GB (HDD/SSD). Есть решения, которые позволяют стартовать виртуальные машины при старте системы в фоновом режиме, без какого-либо интерфейса. А чтобы система при старте на помирала, можно настроить отложенный автозапуск. (Знаю, что у Hyper-V или VMware это есть). 

В моем случае U59 стоит рядом с роутером, подключенный к нему по проводу. IP-адрес выдается DHCP-сервером. Итоговая общая схема получается следующая:

На этой схеме дополнительно появляются два блока, которые мы настроим в самом конце статьи. 

Функция "Динамический DNS" (Dynamic DNS / DDNS) позволяет присвоить постоянное доменное имя (адрес для доступа из интернета) публичному IP-адресу, который роутер получает от интернет-провайдера. Публичный IP-адрес может поменяться, а доменное имя, которые вы зарегистрируете – нет. (есть сервисы, позволяющие сделать это бесплатно и вне ПО роутера, рассматриваемого в данной статье). Это будет необходимо для того, чтобы получать доступ к устанавливаемым сервисам через интернет с любого устройства по доменному имени. И порядком упростить конфигурацию, потому что не нужно прописывать конкретный IP адрес в различных конфигурациях ПО.

Далее, Port Forwarding (или Virtual Server) – настройка для WAN-интерфейса (который отвечает за подключение к интернету), позволяющая извне (через интернет) обращаться к конкретным клиентам локальной сети (например, к нашему мини-пк) по определенному порту приложения. 

Таким образом, можно на любом устройстве открыть браузер, ввести зарегистрированное доменное имя и указать порт необходимого приложения, и вуаля, вы зашли на приложение своего сервера. Почти также, как вы попали на habr.com

Установка и настройка ОС

Теперь, когда мы вкратце рассмотрели схемы решения и назначение каждого из компонентов, перейдем к установке и настройке программного обеспечения. 

В качестве основной ОС будет использоваться Linux Debian 11.4. 

Так как Debian поддерживает три модели выпуска своих ОС «стабильный», «тестируемый», «нестабильный», был выбран второй, так как хотелось иметь более свежие версии ядра и пакетов устанавливаемого ПО. (подробное описание есть на сайте: тык). 

Остается скачать netinst iso-образ для платформы amd64, потому что он содержит минимально необходимый набор базового устанавливаемого ПО. А все пакеты в процессе установки будут загружены из сети, что дает самую актуальную версию ОС и пакетов (ссылочка на образ, чтобы не искать: тык). 

Процесс установки описывать не буду, он достаточно простой даже для новичков (почти все этапы требуют простого нажатия enter). Пара моментов, которые хотел бы отметить: обязательная установка пароля для root-пользователя, так как все операции будут выполняться под ним; а также выбор устанавливаемых компонентов, который задается почти в самом конце установки, должен включать только SSH server:

Так выглядит конфигурация установки ОС без лишних компонентов, но с доступом по SSH
Так выглядит конфигурация установки ОС без лишних компонентов, но с доступом по SSH

После установки необходимо войти под пользователем root с паролем, который задавался при установке (и да, пароль при вводе никак не отображается, это нормально).

После ввода root пароля просто нажимаем enter
После ввода root пароля просто нажимаем enter

И внести последнее изменение с самого мини-пк: в конфигурации SSH необходимо разрешить подключение root пользователю, так как, повторюсь, все операции будем выполнять от него. Для этого вводим:

nano /etc/ssh/sshd_config

Ищем закомментированную строку #PermitRootLogin prohibit-password и правим в это: PermitRootLogin yes

Выглядит это так:

Записываем файл ctrl+o, enter и выходим из редактора ctrl+x.
Записываем файл ctrl+o, enter и выходим из редактора ctrl+x.

Перезапускаем сервер:

systemctl restart ssh || systemctl restart sshd

Узнаем ip адрес машины через команду:

ip a

Скорее всего нам нужен будет именно второй интерфейс, а так как IP-адрес получаем по DHCP от роутера, то он будет примерно следующего вида: 

192.168.XXX.YYY (Например, 192.168.0.25 или 192.168.25.136). 

(Во всей статье будет использоваться IP-адрес 192.168.50.56, поэтому держите в уме, что в вашем случае нужно будет заменить его на актуальный IP именно для вашего сервера. Вместо IP-адреса может быть указано также доменное имя)

Узнав адрес, можно отложить ПК в сторону и подключиться по SSH через терминал с основной машины, находящейся в одной локальной сети с сервером, следующей командой (работает в любой ОС):

ssh root@192.168.50.56 

Остается только ввести пароль от пользователя root.

(если на вашей основной машине по каким-либо причинам не установлен ssh-клиент, можете воспользоваться PuTTy)

Как только получилось авторизоваться, немножко настроим и почистим систему. Уберем поддержку IPv6 и включим переадресацию для IPv4 между сетевыми интерфейсами командой (в терминал вставляется все, так как команды объединены связкой " && \"):

echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /etc/sysctl.conf && \
sysctl -w net.ipv4.ip_forward=1

Удалим лишние пакеты и подчистим зависимости:

apt remove -y vim-common vim-tiny rsyslog ispell iamerican ibritish ienglish-common dictionaries-common emacsen-common wamerican cron cron-daemon-common apparmor && \
apt autoclean -y && apt autoremove -y

Теперь установим базовый набор пакетов, необходимый для установки остального ПО:

apt install -y sudo curl wget gnupg2 htop lm-sensors

Выключим ненужные сервисы:

systemctl disable console-setup && \
systemctl disable keyboard-setup && \
systemctl mask --now systemd-journal-flush && \
systemctl mask --now systemd-journald

Отредактируем загрузчик, чтобы убрать 5 секундное ожидание при старте и отключить ограничения по уязвимостям Spectre, Meltdown и другим, открыв файл загрузчика для редактирования:

nano /etc/default/grub

Значения меняем на следующие:

GRUB_TIMEOUT=0
GRUB_CMDLINE_LINUX_DEFAULT="mitigations=off quiet"

Записываем файл ctrl+o, enter и выходим из редактора ctrl+x.

Обновляем загрузчик и перезагружаемся:

update-grub && \
reboot

Установка ПО: Mosquitto, Node-RED, WireGuard, Influx, Telegraf, Grafana

После перезагрузки снова коннектимся по SSH:

ssh root@192.168.50.56

Установка Mosquitto

Добавляем пакет и проверяем актуальную версию, должна быть 2.0.14 :

wget http://repo.mosquitto.org/debian/mosquitto-repo.gpg.key && \
apt-key add mosquitto-repo.gpg.key && \
cd /etc/apt/sources.list.d/ && \
wget http://repo.mosquitto.org/debian/mosquitto-bullseye.list && \
apt-get update && \
apt-cache show mosquitto | grep Version && \
cd

Устанавливаем:

apt-get install -y mosquitto=2.0.14-0mosquitto1~bullseye1 mosquitto-clients

Создаем пароль для учетной записи IoT (после ввода команды нужно дважды ввести пароль):

sudo mosquitto_passwd -c /etc/mosquitto/passwd IoT

Создаем конфигурацию:

sudo nano /etc/mosquitto/conf.d/default.conf

И вставляем туда следующие содержимое:

allow_anonymous false
password_file /etc/mosquitto/passwd
listener 1883

Записываем файл ctrl+oenter и выходим из редактораctrl+x.

Сохраненная только что конфигурация запрещает анонимное подключение, без связки логин-пароль, указывает путь к файлу с заданным ранее паролем для пользователя IoT, а также задает порт, на котором будет работать MQTT брокер. Перезапускаем службу:

systemctl restart mosquitto

Проверим, что все работает, выполнив в двух отдельных терминальных окнах следующие команды (пароль необходимо изменить на свой или использовать student):

mosquitto_sub -h 192.168.50.56 -p 1883 -t Habr -u "IoT" -P "student"
mosquitto_pub -h 192.168.50.56 -p 1883 -t "Habr" -m "Hello, Habr!" -u "IoT" -P "student"

Верхняя команда будет прослушивать топик Habr, командой sub. Нижняя команда отправит на топик с названием Habr сообщение: «Hello, Habr!», командой pub. Что и получилось: В режиме прослушивания (подписки) терминалом была создана строка с полученным значением.

Установка Node-RED + Node.js

Установим сперва актуальную версию Node.js 18:

curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \
apt-get install -y nodejs

Далее, воспользуемся скриптом-установщиком, который установит Node-RED:

bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)

Установщик трижды спросит подтверждение, необходимо дважды ввести «y» и последний раз «n».

Are you really sure you want to install as root ? [y/N] ? y
Are you really sure you want to do this ? [y/N] ? y
Would you like to install the Pi-specific nodes ? [y/N] ? n

Далее, нам необходимо инициализировать параметры командой:

node-red admin init

Небольшая шпаргалка по ответам на вопросы скрипта:

Settings file -> enter
Do you want to setup user security? –> yes
Username -> admin
Password -> задаете_пароль_для_admin
User permissions -> full access
Add another user? -> yes
Username -> user
Password -> задаете_пароль_для_user
User permissions -> read-only access
Add another user? -> no
Do you want to enable the Projects feature? -> no
Enter a name for your flows file -> enter
Provide a passphrase to encrypt your credentials file -> задаете_пароль_для_credentials_file
Select a theme for the editor -> default 
Select the text editor component to use in the Node-RED Editor -> monaco (default)
Allow Function nodes to load external modules? -> yes

Данная конфигурация включает форму авторизации на Node-RED и создает двух пользователей: admin и user, с полными правами и правами только на чтение соответственно. Затем необходимо включить и запустить сервисы Node-RED:

sudo systemctl enable nodered && \
sudo systemctl start nodered

Проверить, что все работает, можно зайдя по адресу: http://192.168.50.56:1880/

Если все действия выполнены успешно, вас встретит эта замечательная приветственная страница
Если все действия выполнены успешно, вас встретит эта замечательная приветственная страница

Установка WireGuard

WireGuard, как и Node-RED, тоже очень просто устанавливается скриптом-установщиком. Единственный нюанс, который возникает на Debian 11 в тестовой сборке, это отсутствие версии в базовых сведениях о системе, к которой привязывается скрипт. Исправим это:

nano /etc/os-release

Добавляем строчку со значением:

VERSION_ID=11

Записываем файл ctrl+o, enter и выходим из редактора ctrl+x.

 Загружаем скрипт, делаем его исполняемым:

curl -O https://raw.githubusercontent.com/angristan/wireguard-install/master/wireguard-install.sh && \
chmod +x wireguard-install.sh

И запускаем:

./wireguard-install.sh

Небольшая шпаргалка по ответам на вопросы скрипта:

IPv4 or IPv6 public address: -> my-home-server.noip.com (указываем доменное имя или публичный IP адрес с 2ip.ru, полученное в конце статьи)
Public interface: -> ens## (автоматом подтягивает имеющийся сетевой интерфейс, который мы видели командой ip a, если это он, можно не менять))
WireGuard interface name: -> wg0 (оставляем без изменений)
Server's WireGuard IPv4: -> 10.66.66.1 (оставляем предложенную адресацию без изменений)
Server's WireGuard IPv6: -> fd42:42:42::1(оставляем предложенную адресацию без изменений)
Server's WireGuard port [1-65535]: -> 1870 (указываем любой порт)
First DNS resolver to use for the clients: ->1.1.1.1
Second DNS resolver to use for the clients (optional): -> 1.0.0.1

После нажатия Enter’a, установки и конфигурирования серверной части скриптом, что был выше, скрипт переходит дальше, к настройке клиентской конфигурации, с помощью которой можно будет подключиться через клиентское приложение WireGuard к нашему серверу. Там указывается следующее:

Client name: -> Client_id_1 (или устанавливаем свое название файла)
Clinet's WireGuard IPv4: -> 10.66.66.2 (оставляем предложенную адресацию без изменений)
Clinet's WireGuard IPv6: -> fd42:42:42::2(оставляем предложенную адресацию без изменений)

Конфигурацию можно скачать по QR-коду или через FTP по пути /root/wg0-client-####.conf .

Результат выглядит вот так:

В итоговой конфигурации удаляем все упоминания об IPv6 и ip6tables в строчках с PostUp и PostDown:

nano /etc/wireguard/wg0.conf

Результат должен быть примерно следующий:

[Interface]
Address = 10.66.66.1/24
ListenPort = 1870
PrivateKey = sLdyJJPFXSZCTuPbuaCKdvDvVDOCCdbwjmPj7QgQkEs
PostUp = iptables -A FORWARD -i enp2s0 -o wg0 -j ACCEPT; iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o enp2s0 -j MASQUERADE
PostDown = iptables -D FORWARD -i enp2s0 -o wg0 -j ACCEPT; iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o enp2s0 -j MASQUERADE

### Client
[Peer]
PublicKey = Rxo33+25X0oBni2v94+ftMXBSEveTpeXDDhmb7/x0mc=
PresharedKey = FNKcatwzm8KyAtP4lj8ZuXfSvQY0nh/SeV34TYMYaL0=
AllowedIPs = 10.66.66.2/32

Записываем файл ctrl+o, enter и выходим из редактора ctrl+x.

Перезапускаем службу:

systemctl restart wg-quick@wg0

Если захотите добавить еще одного пользователя (потому что каждая конфигурация поддерживает только одно активное подключение), то снова запустите скрипт (выбрав 1):

./wireguard-install.sh

Для проверки необходимо запустить клиентское приложение WireGuard, импортировать в него созданную ранее клиентскую конфигурацию (wg0-client-####.conf) и запустить подключение:

Установка InfluxDB2 + Telegraf + Grafana

Добавим репозитории для InfluxDB2 и Telegraf, скачаем заданную версию Grafana, установим и запустим службы (для Grafana проверяйте наличие обновленной версии перед установкой здесь. Версию можно поправить прямо в скрипте, когда выйдет более актуальная)

wget -q https://repos.influxdata.com/influxdb.key && \
echo '23a1c8836f0afc5ed24e0486339d7cc8f6790b83886c4c96995b88a061c5bb5d influxdb.key' | sha256sum -c && cat influxdb.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/influxdb.gpg > /dev/null && \
echo 'deb [signed-by=/etc/apt/trusted.gpg.d/influxdb.gpg] https://repos.influxdata.com/debian stable main' | sudo tee /etc/apt/sources.list.d/influxdata.list && \
sudo apt-get install -y adduser libfontconfig1 && \
wget https://dl.grafana.com/oss/release/grafana_9.0.6_amd64.deb && \
sudo dpkg -i grafana_9.0.6_amd64.deb && \
sudo rm /root/grafana_9.0.6_amd64.deb && \
sudo systemctl enable grafana-server && \
sudo systemctl start grafana-server && \
sudo apt-get update && sudo apt-get install -y influxdb2 telegraf && \
sudo systemctl start influxd && \
sudo systemctl enable telegraf

Проверим, что InfluxDB и Grafana доступны, зайдя по адресам: http://192.168.50.56:8086/ и http://192.168.50.56:3000/

Должно быть так:

Если все действия выполнены успешно, вас встретит эта замечательная приветственная страница
Если все действия выполнены успешно, вас встретит эта замечательная приветственная страница

И так:

Если все действия выполнены успешно, вас встретит эта замечательная приветственная страница
Если все действия выполнены успешно, вас встретит эта замечательная приветственная страница

Настройка Influx, Telegraf, Grafana

Заходим в InfluxDB по адресу http://192.168.50.56:8086 и нажимаем “GET STARTED” и первым делом создаем учетную запись, указываем название организации и корзины для данных (Organization Name и Bucket Name -> IoT). После заполнения нажать «CONTINUE», а в следующем окне «QUICK START»

Создаем учетную запись, указываем название организации и корзины для данных
Создаем учетную запись, указываем название организации и корзины для данных
Выбираем QUICK START
Выбираем QUICK START

Далее, нам необходимо создать файл конфигурации для Telegraf. Для этого нам сперва необходимо скопировать токен доступа из InfluxDB. 

В левом боковом меню нажимаем Load Data -> API Tokens -> admin’s Token -> копируем через “COPY TO CLIPBOARD” и сохраняем где-нибудь.

 Load Data -> API Tokens -> admin’s Token -> копируем через “COPY TO CLIPBOARD”
 Load Data -> API Tokens -> admin’s Token -> копируем через “COPY TO CLIPBOARD”

Далее, создаем саму конфигурацию для Telegraf:

nano /etc/telegraf/telegraf.d/IoT.conf

И вставляем туда следующее содержимое, которое в части ip-адресов и токена вам нужно будет немного отредактировать:

# Configuration for telegraf agent
[agent]
  interval = "3s"
  round_interval = true
  metric_batch_size = 1000
  metric_buffer_limit = 10000
  collection_jitter = "0s"
  flush_interval = "3s"
  flush_jitter = "0s"
  precision = ""
  hostname = ""
  omit_hostname = false

[[outputs.influxdb_v2]]
  urls = ["http://192.168.50.56:8086"]
  token = "gj8siSCDDuWyPd31LvrA2JIzldDzso_e_R_NiRkjKGJei4VgdoBV4heKIYSb7jMXLvEufhKgZfEv2pjTCHYUXA=="
  organization = "IoT"
  bucket = "IoT"

[[inputs.mqtt_consumer]]
  servers = ["tcp://192.168.50.56:1883"]
  topics = ["#"]
  username = "IoT"
  password = "student"
  data_format = "value"
  data_type = "float"

Записываем файл ctrl+o, enter и выходим из редактора ctrl+x. Затем перезапускаем службу, чтобы применить конфиг:

systemctl restart telegraf

Теперь необходимо отправить данные на наш MQTT брокер:

mosquitto_pub -h 192.168.50.56 -p 1883 -t "Habr/Temp" -m "28.5" -u "IoT" -P "student"

А в InfluxDB проверить, что в Data Explorer -> IoT -> mqtt_consumer есть топик Habr/Temp и данные. Для этого необходимо настроить пространство, как на скриншоте ниже ( нужно поменять тип график на Gauge, aggregate function указать last и нажать SUBMIT):

Все MQTT-сообщения от Telegraf будут собираться в mqtt_consumer
Все MQTT-сообщения от Telegraf будут собираться в mqtt_consumer

Вуаля, наш температурный «спидометр» показывает ровно то значение, которое было отправлено в MQTT сообщении на топик Habr/Temp. Последний шаг, который осталось сделать: скопировать скрипт получения данных из БД. Делается это через SCRIPT EDITOR (рядом с SUBMIT со скриншота выше). Копируем запрос из 6 строк и сохраняем где-нибудь рядом с токеном.

Запрос может быть и больше, если шагом ранее вы выберете несколько метрик
Запрос может быть и больше, если шагом ранее вы выберете несколько метрик

Далее, перейдем к настройкам Grafana. Первая авторизация происходит по логину/паролю admin/admin, после чего система попросит установить новый пароль. 

Hello :)
Hello :)

После чего попадаем на приветсвенное пространство Grafana. Далее, нам необходимо добавить интеграцию (подключение) с InfluxDB. Нажимаем значок настроек -> Data Sources -> Add Data Sourse -> InfluxDB -> Query Language (Flux) -> URL -> Basic Auth (off) -> Organozation(IoT) -> Default Bicket (IoT) -> Token (Берется в InfluxDB -> Load Data -> Api Tokens -> Admin`stoken) -> Save&Test (должен быть ok)

Много картинок здесь:
Нажимаем значок настроек -> Data Sources ->
Нажимаем значок настроек -> Data Sources ->
-> Add Data Sourse ->
-> Add Data Sourse ->
-> InfluxDB ->
-> InfluxDB ->
-> Query Language (Flux) -> URL (http://192.168.50.56:8086)-> Basic Auth (off) -> Organozation(IoT) -> Default Bicket (IoT) -> Token (Берется в InfluxDB -> Load Data -> Api Tokens -> Admin`stoken) -> Save&Test (должен быть ok)
-> Query Language (Flux) -> URL (http://192.168.50.56:8086)-> Basic Auth (off) -> Organozation(IoT) -> Default Bicket (IoT) -> Token (Берется в InfluxDB -> Load Data -> Api Tokens -> Admin`stoken) -> Save&Test (должен быть ok)

После того, как Grafana успешно подключилась к InfluxDB и обнаружила все корзины с данными, можно добавить дашборд: Dashboards -> New Dashboard -> Add New Panel -> вставляем данные их SCRIPT EDITOR -> Apply -> Save -> Имя дашборда

И много картинок здесь
Dashboards -> New Dashboard ->
Dashboards -> New Dashboard ->
-> Add New Panel ->
-> Add New Panel ->
вставляем данные из SCRIPT EDITOR в InfluxDB -> минимально настраиваем -> Apply
вставляем данные из SCRIPT EDITOR в InfluxDB -> минимально настраиваем -> Apply
Создаем еще одну панель с табличным отображением
Создаем еще одну панель с табличным отображением
Сохраняем итоговый дашборд
Сохраняем итоговый дашборд

На этом настройка первого дашборда по визуализации условной температуры завершена. 

P.S. Службу Telegraf необходимо перезапускать после каждой перезагрузки системы. Почему-то она стартует в статусе «failed», а перезагружается со статусом «Active». Видимо баг в последних сборках. Делается это следующей командой:

systemctl restart telegraf

Альтернатива с Node-RED

Для этого нам необходимо зайти в приложение http://192.168.50.56:1880/ и авторизоваться под администратором, пароль которого задавался ранее. В базовом наборе есть множество узлов(нод), в том числе MQTT, поэтому остается добавить и настроить интеграцию с InfluxDB. Для этого необходимо загрузить дополнительную палитру node-red-contrib-influxdb, а еще нам понадобится random-generator_node-red-contrib, для генерации случайных чисел.

Для этого в боковом меню выбирается "Управление палитрой", затем установить и в поле поиска вводится название палитры и нажимается кнопка "установить".

Выглядит это так
Боковое меню -> Управление палитрой
Боковое меню -> Управление палитрой
Устанавливаем палитру node-red-contrib-influxd, аналогично действуем для random-generator_node-red-contrib
Устанавливаем палитру node-red-contrib-influxd, аналогично действуем для random-generator_node-red-contrib

После установки всего необходимого соберем поток:

Делаем так:
  1. Возьмем узел стартового генератор событий «inject» в разделе общее, который будет генерировать сообщение с текущей временной меткой

  2. Возьмем узел «Number», в разделе Random Generator, где зададим диапазон случайно генерируемых чисел.

    Настройка узла Number
    Настройка узла Number
  3. Возьмем узел «mqtt out» в разделе сеть, чтобы отправить данные MQTTброкеру. И настроим его. Указав тему (топик), адрес сервера, и данные авторизации.

    (Шаги с 1 по 3 нужны, чтобы с эмулировать данные от устройства, передающего данные по MQTT.)

    Задается тема для публикации и настраивается сервер
    Задается тема для публикации и настраивается сервер
    Задается адрес и порт сервера
    Задается адрес и порт сервера
    Задаются параметры аутентификации
    Задаются параметры аутентификации
  4. Возьмем узел «mqtt in» в разделе сеть, чтобы получать данные от MQTT брокера. И настроем его по аналогии с П.3

    Указывается уже настроенный сервер и задается тема для подписки
    Указывается уже настроенный сервер и задается тема для подписки
  5. Возьмем узел «influx out» в разделе хранилище, чтобы данные записывались в InfluxDB. И настроим его. Укажем организацию и корзину: IoT, задаим название переменной для измерений, укажем версию InfluxDB (2.0), адрес БД и знакомый по прошлым пунктам токен.

    Указывается Org, Bucket и настраивается подключение к InfluxDB
    Указывается Org, Bucket и настраивается подключение к InfluxDB
    Указывается версия БД (2.0 обязательно), адрес и токен
    Указывается версия БД (2.0 обязательно), адрес и токен
  6. Для удобства к узлам «Number» и «mqtt in» можно подключить узел debug, который покажет, что было сгенерировано такое-то значение, на узле “Number”, а оно же было получено на узле «mqtt in». (и, соответственно, записано в БД).

  7. Нажимаем развернуть (чтобы применить любый изменения)

Проверим, что все настройки работают, нажав на запуск события узла «inject»:

Успех!
Успех!

Как мы видим, MQTT подключение к брокеру успешно установлено. А сгенерированные данные были отправлены и получены по MQTT. Проверим теперь запись измерения в InfluxDB. Заходим в уже знакомый раздел Data Explorer и видим там измерение с названием Habr_temp, которые было задано в узле «influx out». 

Данные в метрику Habr_temp получены!
Данные в метрику Habr_temp получены!

Преимущество данного способа в том, что при получении информации по mqtt на шаге 4 выше, после него можно написать какую-нибудь функцию на javasсript по обработке полученных данных. И только потом записать их в InfluxDB.

Немного про DDNS и PortFowarding на роутере ASUS и адресацию.

Под конец настроим проброс портов установленных приложений. Для этого необходимо зайти на роутер (в моем случае адрес 192.168.50.1), авторизоваться и перейти в раздел бокового меню WAN. Там выбрать раздел Virtual Server / Port Forwarding и настроить значения следующим образом через “Add profile”. Необходимо ввести имя профиля, порт, который открываем, тип протокола и адрес нашего сервера:

В зависимости от производителя интерфейс может отличаться, но суть остается без изменений.
В зависимости от производителя интерфейс может отличаться, но суть остается без изменений.

На любом другом роутере интерфейс и названия могут отличаться, но функционал должен присутствовать почти на всех современных моделях. Теперь у нас есть доступ к нашим приложениям через интернет, при указании вашего публичного IP адреса и порта приложения.

Далее, перейдем к настройке нашего доменного имени. Необходимо перейти в соседнюю секцию, включить службу DDNS, установить метод запроса IP -> External. Указать свободное доменное имя и зарегистрировать его (в качестве примера используется: yours-linux-server-1.asuscomm.com). Когда процесс успешно завершится, применить всю конфигурацию. Через небольшой промежуток времени ваш публичный IP адрес привяжется к доменному имени, которое вы зарегистрировали и доступ к приложениям можно будет запрашивать по нему, вместо публичного IP адреса.

Немного про адресацию:

Доступ, например, в Node-Red, осуществляется по адресу http://localhost:1880 с компьютера, на котором он установлен, по адресу http://192.168.50.56:1880 если запрос идет из любого другого компьютера домашней локальной сети, и http://<ваш ip адрес на 2ip.ru / или доменное имя>:1880 если настроен проброс портов и запрашивается доступ через интернет. Итого это будет выглядеть следующим образом:

На самом сервере доступ к ПО осуществляется по ссылкам:

http://localhost:1880     –>     Node-RED
http://localhost:1883     –>     Mosquitto MQTT
http://localhost:1871     –>     WireGuard VPN
http://localhost:3000     –>     Grafana
http://localhost:8086     –>     InfluxDBv2

На любом устройстве домашней локальной сети доступ к ПО осуществляется по ссылкам:

http://192.168.50.56:1880     –>     Node-RED
http://192.168.50.56:1883     –>     Mosquitto MQTT
http://192.168.50.56:1871     –>     WireGuard VPN
http://192.168.50.56:3000     –>     Grafana
http://192.168.50.56:8086     –>     InfluxDBv2

На любом устройстве доступ к ПО через интернет осуществляется по ссылкам (на месте yours-linux-server-1.asuscomm.com может быть ваш публичный IP адрес на 2ip.ru):

http://yours-linux-server-1.asuscomm.com:1880     –>     Node-RED
http://yours-linux-server-1.asuscomm.com:1883     –>     Mosquitto MQTT
http://yours-linux-server-1.asuscomm.com:1871     –>     WireGuard VPN
http://yours-linux-server-1.asuscomm.com:3000     –>     Grafana
http://yours-linux-server-1.asuscomm.com:8086     –>     InfluxDBv2

P.S.

Если любопытно посмотреть потребление ресурсов развернутой системы, то можно воспользоваться утилитой htop:

htop

P.S.S: Docker

Для тех, кто предпочитает контейнеры:

Вставляем один большой скрипт (вот прям весь весь):

sudo apt install -y iptables && \
wget https://download.docker.com/linux/debian/dists/bullseye/pool/stable/amd64/containerd.io_1.6.6-1_amd64.deb && \
wget https://download.docker.com/linux/debian/dists/bullseye/pool/stable/amd64/docker-ce-cli_20.10.17~3-0~debian-bullseye_amd64.deb  && \
wget https://download.docker.com/linux/debian/dists/bullseye/pool/stable/amd64/docker-ce_20.10.17~3-0~debian-bullseye_amd64.deb  && \
sudo dpkg -i containerd.io_1.6.6-1_amd64.deb  && \
sudo dpkg -i docker-ce-cli_20.10.17~3-0~debian-bullseye_amd64.deb && \
sudo dpkg -i docker-ce_20.10.17~3-0~debian-bullseye_amd64.deb && \
DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker} && \
mkdir -p $DOCKER_CONFIG/cli-plugins && \
curl -SL https://github.com/docker/compose/releases/download/v2.9.0/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose && \
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose && \
rm containerd.io_1.6.6-1_amd64.deb  && \
rm docker-ce-cli_20.10.17~3-0~debian-bullseye_amd64.deb && \
rm docker-ce_20.10.17~3-0~debian-bullseye_amd64.deb && \
docker compose version && \
mkdir -m 777 -p ~/mosquitto/config && \
mkdir -m 777 -p ~/mosquitto/data && \
mkdir -m 777 -p ~/mosquitto/log && \
mkdir -m 777 -p ~/influxdb/data && \
mkdir -m 777 -p ~/influxdb/conf && \
mkdir -m 777 -p ~/telegraf/conf && \
mkdir -m 777 -p ~/grafana/data && \
mkdir -m 777 -p ~/grafana/conf && \
mkdir -m 777 -p ~/grafana/log && \
mkdir -m 777 -p ~/node-red/data && \
mkdir -m 777 -p ~/wireguard/config

Создадим конфигурацию для mosquitto:

cat > ~/mosquitto/config/mosquitto.conf <<EOF
listener 1883
#allow_anonymous false
#password_file /mosquitto/config/password.txt
EOF

Создадим конфигурацию для telegraf:

cat > ~/telegraf/conf/telegraf.conf <<EOF
[agent]
  interval = "3s"
  round_interval = true
  metric_batch_size = 1000
  metric_buffer_limit = 10000
  collection_jitter = "0s"
  flush_interval = "3s"
  flush_jitter = "0s"
  precision = ""
  hostname = ""
  omit_hostname = false

[[outputs.influxdb_v2]]
  urls = ["http://192.168.50.56:8086"]
  token = "a"
  organization = "IoT"
  bucket = "IoT"

[[inputs.mqtt_consumer]]
  servers = ["tcp://192.168.50.56:1883"]
  topics = ["#"]
  username = "IoT"
  password = "student"
  data_format = "value"
  data_type = "float"
EOF

Настроим Grafana на 80 порт:

cat > ~/grafana/conf/grafana.ini <<EOF
[server]
http_port = 80
EOF

Создаим docker-compose.yml:

cat > docker-compose.yml <<EOF
version: "2"
services:
  influxdb:
    container_name: influxdb
    image: influxdb
    environment:
      - TZ=Europe/Moscow
    ports:
      - "8086:8086"
    volumes:
      - ~/influxdb/data:/var/lib/influxdb
    networks:
      - influxdb-net
    restart: always

  wireguard:
    container_name: wireguard
    image: lscr.io/linuxserver/wireguard:latest
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Moscow
      - SERVERURL=auto #optional
      - SERVERPORT=51820 #optional
      - PEERS=5 #optional
      - PEERDNS=auto #optional
      - INTERNAL_SUBNET=10.13.13.0 #optional
      - ALLOWEDIPS=0.0.0.0/0 #optional
      - LOG_CONFS=false #optional
    volumes:
      - ~/wireguard/config:/config
      - /lib/modules:/lib/modules
    ports:
      - 51820:51820/udp
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
    restart: always

  telegraf:
    container_name: telegraf
    image: telegraf
    environment:
      - TZ=Europe/Moscow
    volumes:
      - ~/telegraf/conf/telegraf.conf:/etc/telegraf/telegraf.conf
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - telegraf-net
    restart: always
    
  grafana:
    container_name: grafana
    image: grafana/grafana
    environment:
      - TZ=Europe/Moscow
    ports:
      - "80:80"
    volumes:
      - ~/grafana/data:/var/lib/grafana
      - ~/grafana/log:/var/log/grafana
      - ~/grafana/conf/grafana.ini:/etc/grafana/grafana.ini
    links:
      - influxdb
    networks:
      - grafana-net
    restart: always

  mosquitto:
    container_name: mosquitto
    image: eclipse-mosquitto:latest
    environment:
      - TZ=Europe/Moscow
    volumes:
      - ~/mosquitto/:/mosquitto  
    ports:
      - 1883:1883
    networks:
      - mosquitto-net
    restart: always

  node-red:
    container_name: node-red
    image: nodered/node-red:latest
    environment:
      - TZ=Europe/Moscow
    ports:
      - "1880:1880"
    volumes:
      - ~/node-red/data:/data
    networks:
      - node-red-net
    restart: always

networks:
  node-red-net:
  influxdb-net:
  mosquitto-net:
  grafana-net:
  telegraf-net:
EOF

Запустим создание контейнеров (процесс займет какое-то время):

docker compose up -d

Далее, необходимо, как в основной части статьи, настроить mosquitto. От вас требуется только придумать пароль:

docker exec -it mosquitto mosquitto_passwd -c /mosquitto/config/password.txt IoT

Включить авторизацию в конфигурации:

cat > ~/mosquitto/config/mosquitto.conf <<EOF
listener 1883
allow_anonymous false
password_file /mosquitto/config/password.txt
EOF

И применить конфигурацию:

docker restart mosquitto

Настроить авторизацию в Node-red, сгенерировав пароль сперва для admin, потом для user, и скопировав хеши куда-нибудь:

docker exec -it node-red node-red-admin hash-pw

И указать их здесь:

nano +76,5 ~/node-red/data/settings.js

Должно быть примерно так:

adminAuth: {
        type: "credentials",
        users: [
                {
                        username: "admin",
                        password: "$2b$08$WhOtjRwX8Cd44vgryrOPue4rS8YkdOxS7DuuvUaUtotGRiSZ1bUny",
                        permissions: "*"
                },
                {
                        username: "user",
                        password: "$2b$08$sksoLeOB6EDecN3IZYLisO7mqNf/KSI519eioh7gtM0BpvAM3wA3q",
                        permissions: "read"
                }
        ]
},

Затем применяем конфигурацию:

docker restart node-red

Получаем токен Influx по шагам в основной статье. И указываем его здесь:

nano +15,12 ~/telegraf/conf/telegraf.conf

И применяем конфигурацию для Telegraf:

docker restart telegraf

Все контейнеры должны быть в статусе UP

docker ps
Выглядит примерно вот так
Выглядит примерно вот так

Конфиг для WireGuard можно получить командой:

docker exec -it wireguard /app/show-peer 1

Не забываем про настройку интеграции с Influx у Grafana и Node-RED (в части настроек все без изменений, как и в основной статье)

Вместо заключения

На этом все! Домашний сервер с системой визуализации и подключением по MQTT настроен. Остается только отправлять данные в топики по MQTT и настраивать визуализацию, как душе угодно.

На самом деле в статье рассмотрен лишь частный случай с MQTT. Что Telegraf, что Node-RED – позволяют получать и передавать данные в InfluxDB (и другие БД) по множеству других интерфейсов и протоколов. Но это уже совсем другая история.

Комментарии (11)


  1. alexesDev
    04.08.2022 23:31
    +7

    Зачем вы мучаетесь в influx... есть prometheus, уже почти стандарт в облаках, целиком открытый без "хотите надежность - заплатите". Все тоже самое, только лучше =)


    1. vlad_gatsenko Автор
      04.08.2022 23:34
      +1

      Изучу вопрос, спасибо :)


  1. Vassam
    05.08.2022 00:17
    +9

    Почему ставится не в контейнеры? У всего вышеперечисленного бывают проблемы с версиями используемого ПО, плюс контейнеризация изолирует, к примеру, Инфлюкс и Телеграф, которым явно не нужен выход из изолированной виртуальной сети Докера, и на свет Божий можно выпустить только те порты, которые нужно, да ещё и сделать их "красивыми", конечный ГУИ, я так понимаю, это Графана? Вот можно Графану на порт 80 выпускать, красоты ради. То, что такой стек в Докере живёт не напрягаясь на таком железе, проверено тысячами пользователей.

    Работа из-под рута? Линуксоидам не показывайте, забросают помидорами.

    Ну и наконец, где-то в сети валяется ансибл-скрипт, который поднимает всё вышеперечисленное в один приём, с вайргардом, судо-пользователем, запретом рута, установкой входа по ssh по ключу, а не по паролю. Конечно, давать студентам уже после поднятия ручками, дабы впечатлить магией.


    1. GrueneGespenst
      05.08.2022 15:10

      где-то в сети валяется ансибл-скрипт, который поднимает всё вышеперечисленное в один приём

      Ну почти все. Я этим пользовался: https://www.rs-online.com/designspark/raspberry-pi-4-personal-datacentre-part-3-a-self-hosted-iot-data-platform


    1. select26
      06.08.2022 11:03

      Потому что на non x86 miniPC с контейнерами могут быть проблемы?


    1. vlad_gatsenko Автор
      07.08.2022 00:17

      Вечер добрый) 

      Я в Docker’e не работал, но, спасибо, потратил вечерок и дополнил статью. Не берусь утверждать, что там все корректно в сетевой части, но работает :) Сделал через docker compose, одной командой все ставится.

      И Grafana на 80 порт в контейнерах я перенес. В основной статье оставил без изменений, чтобы была практика обращения с приложениями, а механику можно взять из конфига с контейнерами :)


  1. net_men
    05.08.2022 09:20

    Я запнулся на установке Node-RED... я так понимаю, нужно скрипт править?

    Running Node-RED update for user root at /root on debian

    Node-RED v3.x no longer supports Nodejs 12

    You can force an install of node 14, 16 or 18 by using the --node14, --node16 or --node18 parameter.
    However doing so may break some nodes that may need re-installing manually.
    Generally it is recommended to update all nodes to their latest versions before upgrading.

    If you wish to stay on nodejs 12 you can update to the latest Node-RED 1.x or 2.x version by adding
    --nodered-version="1.3.7" or --nodered-version="2.2.2" to that install command. If in doubt this is the safer option.
    Please backup your installation and flows before upgrading.

    Note: not all embedded hardware can be updated via this method - please check before proceeding.

    Exiting now.

    Предыдущая команда была выполнена успешно... хотя установка nodejs сказала, что уже установлена самая последняя версия (12.22.12~dfsg-1~deb11u1).

    Что я делаю не так?


    1. vlad_gatsenko Автор
      05.08.2022 09:40

      Похоже на то, что у вас уже ранее был установлен пакето Node.js версии 12.22.12. В статье установка на "чистую" систему, поэтому там исключены какие-либо варианты по несовместимости и т.д.

      Попробуйте получить список установленного ПО, командой

      apt list --installed

      Найти в списке весии пакетов nodejs с версией 12.22.12 (или похожие) и удалить командой:

      sudo apt remove -y nodejs nodejs_еще_какой-то_из_списка && \
      apt autoclean -y && apt autoremove -y

      Соответсвенно, полностью удалите nodejs, а затем начните установку Node-RED с начала, должно помочь :)


  1. rocket
    05.08.2022 10:08
    +1

    Очень радует функция автоматического включения в случае пропадания и восстановления питания

    Подскажите, а как называется данная функция в спецификации? Или вы об этом узнали по факту после покупки уже?

    Я выкручиваюсь нажатием кнопки WoL через мобильное приложение моего роутера когда поступает пуш о том, то роутер в сети после пропадания питания. Хотелось бы немного автоматизации.

    В БИОСе соответствующего пункта об автоматическом включении нет.


    1. vlad_gatsenko Автор
      05.08.2022 10:18
      +2

      Для того, чтобы активировать функцию автоматического включения питания после пропадания и подачи питания, необходимо в BIOS перейти в раздел Chipset и изменить параметр State After G3 -> S0 State


  1. select26
    06.08.2022 11:06
    +1

    Автор, тема интересная. Подход хоть и не промышленный, но весьма оригинальный. Для образования весьма полезный.

    Но заголовок! Заголовок то о чем?

    Какой Linux сервер? Визуализация чего?

    Представляете сколько заинтересованных людей просто прошли мимо?