Осциллограф в браузере
Отрисовка графиков в реальном времени
Одно время я работал в компании, которая разрабатывала бесконтактные датчики, как на фото. И при установке этих датчиков, надо было правильно сориентировать антенну (белая штука на фото). И выглядело это так: один человек на объекте, где-то в Сибири, на морозе крутит антенну, а другой в Питере, в офисе, не видит того человека, но видит графики на мониторе. И вот они как слепой с глухим пытаются поставить антенну, один по графикам, по телефону говорит, что надо антенну повернуть, а другой пытается понять в какую сторону её крутить. Звучит как бред, правда? Но так и было.
Когда я это всё увидел, понял, что получать графики надо локально и прямо здесь и сейчас наблюдать всю картину, чтобы один и тот же человек видел сигнал и крутил антенну. И понял: надо пилить веб-интерфейс для этой железки. Опыта веб-разработки ноль, значит за одно и поучимся.
Техническое задание
Хоть NDA в той компании я не подписывал, всё же считаю, что разглашать какую-либо информации составляющую коммерческую тайну не имею права. Поэтому постараюсь рассказать в общих чертах.
Как видно на фото выше, мы устанавливали температурные датчики, на высоковольтные шины. Датчики пассивные, работают на фазовом сдвиге обучающей частоты (2,4 ГГц), и пассивно переизлучают эту частоту. Сдвиг частот мы фиксируем и улавливаем. К сожалению, у меня не осталось сырых данных того времени, но выглядят это как некоторые такие «горбы».
Приёмник подключен к промышленному ПК по интерфейсу RS-485, и уже в нём идёт обсчёт и передача данных по интернету на центральный сервер. В целом, приёмник мог бы делать всё сам, но решили для надёжности реализовать таким образом.
Шкаф приёмного оборудования. ПромПК, блок питания, модем и антенна lte.
Таким образом, у нас есть точка входа: промышленный ПК, на котором стоит Linux. В качестве ПК было много различных вариантов использования: как обычные х86+Ubuntu, так и ARM-роутер на OpenWRT. Поэтому решение должно было быть максимально простым универсальным.
Данные со считывателя получала моя программа, которая работала на ПромПК и сохраняла их в csv-файл разделённых табуляциями, где каждый столбец был сигналом с отдельного канала.
Таким образом, надо было просто сделать WEB-интерфейс, и строить график в реальном времени по этому CSV-файлу. Эпизодически пиная считыватель на новую порцию данных.
Реализация
Основа всего алгоритма CGI-bash скрипт (о боже, CGI на bash), который очень прост:
#!/bin/bash
echo "Content-type: text/html;charset=utf-8"
echo
программа_дающая_данные > /var/www/html/result.dat
echo "true"
exit 0
Следует помнить о том, что все операции происходят от пользователя и группы www-data: www-data (если для апача). Этот момент у меня попил много крови, вообще помните про свои права и права других пользователей, а также про обязанности.
Вызывая этот CGI-скрипт, я каждый раз получаю свежую порцию данных в файле result.dat, которые можем отобразить. Данные выглядят примерно таким образом:
2019 2010 2160 2006
2023 2052 2041 1992
2053 2048 2181 1991
2019 2054 2147 1968
2003 1977 2189 1982
2052 1987 2101 1961
....
Дальше, мне нужно было этот сsv-файл превратить в json. Сделал это с помощью фреймворка Papa Parse, который парсит csv-файл. Построение графика я реализовал на фреймфорке Chart.js. Там громадное количество примеров на вкус и цвет, каждый сможет подобрать подходящее под свою задачу.
Один важный момент: не забывайте очищать массивы, перед внесением новой порции данных. Иначе начинает уплывать память. В момент отладки, на ночь оставил всё, без очищения. Утром пришёл на работу, а мышка уже не в состоянии ползать.
Соберём всё в кучку
Вроде всё просто, осталось всё собрать в единую кучку. Чтобы вам не тратить времени, этот проект я выложил на github github.com/dlinyj/realtime_graph_on_js
Поскольку хочу вам дать рабочий пример, а программа составляет коммерческую тайну, то сделал простенький питоновский скрипт, который генерирует случайные данные для отображения.
#!/usr/bin/env python3
import random
f = open("/var/www/html/result.dat", "w")
for i in range (20):
f.write("%d\t%d\t%d\t%d\t\n" % (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
f.close()
Основа всего — это CGI на bash, о котором писал выше, который вызывает этот питоновский скрипт.
#!/bin/bash
echo "Content-type: text/html;charset=utf-8"
echo
/usr/bin/python3 /usr/lib/cgi-bin/test.py > /dev/null 2&>1
echo "true"
exit 0
Исходный код всей веб-страницы можно посмотреть вот тут.
Вначале я конфигурирую параметры самого графика. Это всё взято из готовых примеров фреймворка Chart.js.
Обновление графика делается по таймеру. Каждые 2000 мс идёт вызов функции gen_graph (), которая вызывает CGI-скрипт, описанный выше.
var gen_graphUrl = "cgi-bin/gen_graph.sh";
function gen_graph() {
$.ajax({
url: gen_graphUrl,
success: function(result) {
parseData();
}
});
}
parseData();
var timerId = setInterval(function() {
gen_graph();
}, 2000);
function stop_reload () {
clearInterval(timerId);
};
Функция parseData () осуществляет парсинг CSV-данных и преобразование из форматт json:
function parseData() {
Papa.parse("result.dat", {
download: true,
complete: function(results) {
createGraph(results.data);
}
});
}
В результате, работа нашего тестового примера выглядит следующим образом:
Заключение
Конечно, весь этот WEB-интерфейс задумывался не только для установки одной антенны. Там было достаточно много другого функционала (прошивка, отладка, добавление коэффициентов), и благодаря этому научился хоть немного программированию на js (хоть понюхал, что это такое). В результате теперь для настройки оборудования нужен только кроссовый кабель и ноутбук. Подключаешь и работаешь в веб-интерфейсе как на обычном роутере. Так же, данный веб-интерфейс доступен по сети, и каждый объект можно отдельно конфигурировать через него, что стало весьма удобно даже людям, далёким от программирования.
Ну и напоследок видео реальных данных с устройства и то, как удобно пользоваться данными графиками.
Ссылки
- Репозиторий проекта github.com/dlinyj/realtime_graph_on_js
- Фреймворк для построения графиков www.chartjs.org
- Фреймворк для парсинга CSV www.papaparse.com