У нас на производстве уже несколько лет работает "самодельная" система контроля за простоями на производстве, реализованная на базе MS SQL, SQL Server Reporting Services и IIS. Вот пример отчета за некоторый период:
Принцип работы такой: агрегат каждую секунду (раньше это было через скрипт в SCADA системе, сейчас через PLC контроллер посредством UDP) передает в SQL базу свое состояние, и как только в таблице состояния появляется условие простоя (это обрабатывается триггером), то в другой таблице в графе "начало простоя" отбивается текущее время. При пропадании условия простоя в этой же таблице отбивается текущее время в графе "конец простоя", и вычисляется общая его продолжительность и отправляется в третью графу. На этом же сервере SQL крутится веб сервер IIS, который при запросе пользователя формирует и выдает ему таблицу простоев в браузере за заданный период. Я так понимаю ничего инновационного в таком подходе нет - MES системы, похоже, основаны на таком же принципе, разве что ПО более продвинутое и заточенное под конкретные задачи.
В данном случае мне такое решение показалось интересным, и одно из его достоинств это "бюджетность". Весь функционал был сделан своими силами инженерами АСУТП без привлечения высококлассных программистов, а я, столкнувшись по работе с этим, после небольшого экскурса в принцип работы, смог добавить еще парочку таблиц с простоями по аналогии с теми что были. Однако такое решение все же требует мало-мальский опыт в программировании и к тому же передача из UDP в SQL реализована через программу-прокладку, что тоже является костылями, но сейчас речь не об этом. Мне как пользователю самому приходится сталкиваться с этими отчетами простоев и поскольку все это решение заточено под использование продуктов Microsoft, то и для пользователе рекомендуется юзать Internet Explorer. То есть решение настолько древнее, что в современном браузере часть функционала уже недоступна, в частности выбор даты формирования отчета это не календарь, а обычное поле, куда нужно вводить даты вручную, что сильно раздражает. Собственно только этот момент и заставил меня ради эксперимента попробовать сделать что-то похожее, но чтобы шаблон отчета можно было редактировать как мне заблагорассудится и обязательно с нормальными полями выбора даты. Вот что получилось в результате у меня:
Очень классно, что для удобства использования (возможно и нет, это как посмотреть) программу можно сделать одним исполняемым файлом - это и веб-сервер, отдающий по запросу таблицу, и сама база данных в SQlite, и даже прием сигналов по UDP с последующим сохранением в базу данных тоже можно прикрутить. Запустил одну программу и все работает. На данный момент в программе реализован механизм получения данных из базы и отдача их по запросу по вебу. Код программы есть в моем репозитории ReportsFromDB. Сама программа заточена под таблицу с определенной структурой - это 3 столбца: Downtime_start - начало простоя, Downtime_stop - конец простоя, и Downtime_dur - продолжительность. В репозитории есть пример такой таблицы с ~55 тысячами записей. Выбор промежутка отчета реализован посредством html и js, что мне кажется тоже очень удобным, т.к. если нужно что-то менять в визуальном оформлении, то не нужно менять программу целиком, а только html файл. Таким же образом удалось добавить русифицированное представление даты и времени в таблице, не меняя и перекомпилируя программу.
Сама программа это, по сути, http Listener, который прослушивает порт 8880 и ожидает запрос, и в зависимости от его содержимого отправляет клиенту ту информацию которую он запросил. Чтобы сформировать таблицу за определенный период нужно подать на сервер запрос такой структуры: http://ip-addr:8880/;время_начала;время_окончания;clear_options Такой странный формат выбрал просто потому, что так проще сделать разделение RawUrl по точке с запятой в запросе, а так как на странице используется iframe, то пользователю не нужно запоминать формат запроса - он создается автоматически во фрейме, и в ответ приходит часть таблицы со 100 строками и несколькими такими страницами, если в запрашиваемый период больше 100 строк. Вот так это реализовано в коде:
try
{
string[] req = request.RawUrl.Split(';');
string reply = "";
if (req[3] == "clear")
{
SQLrows.Clear();
}
reply = connectToDb(req[1], req[2]);
if (reply == "ok" || reply == "full")
{
responseString = buildTable();
}
else
{
responseString = reply;
}
}
catch
{
try
{
responseString = System.IO.File.ReadAllText(System.IO.Path.Join(path, "/Resources/index.html"));
}
catch
{
responseString = "add index.html to generate page";
}
}
В начале функционал был такой что пользователю приходила таблица целиком - вся огромная строка с кодом таблицы отправлялась в браузер и он конкретно так зависал, особенно если попытаться вывести все 55 тысяч строк разом. Именно поэтому был добавлен постраничный вид, с реализацией в виде списка, но опять же довольно криво, поскольку если 2 человека одновременно запросят разные даты, то таблица будет каждый раз пересоздаваться, т.к. список с результирующим массивом таблицы общий для всех. Если добавить в строку запроса еще несколько опций, то можно легко реализовать, например, выбор базы данных или таблицы, что очень удобно, если будет несколько таблиц и баз. Запрос без структуры приведет к тому что страница index.html находящаяся в папке Resources передастся клиенту, но если такой страницы не существует, об этом сообщит браузер. Index.html как и говорил облегчает обращение к базе, за счет использования фрейма, который меняется через javascript.
Разработка велась на Windows и по идее .NET должен работать так же на Linux, поэтому установив .NET SDK на Убунту, я это проверил сам. Однако столкнулся с интересной особенностью - формирование и перелистывание отчета на Убунту срабатывает со второго раза, а в панели разработчика в браузере при перелистывании появляется такая картина:
Не совсем понятно что это такое и из-за чего это может быть, возможно кто-нибудь сможет подсказать в комментарии. А вообще, этот эксперимент я считаю для себя результативным: по крайней мере функцию выбора даты по календарю я все-таки сделал, и даже русификацию даты добавил. А для производственного использования это решение не предполагалось изначально, т.к. нынешняя система на IIS и MSSQL хоть и криво, но работает, по крайней мере пользователи не жалуются (возможно они и не знают что можно что-то улучшить, если хорошо попросить). Я же написал эту заметку для того, чтобы получить конструктивную критику и советы, как можно сделать что-то лучше или, возможно, вообще есть готовые решения такого же плана. Также это и возможность поделиться таким вот способом решения проблемы по созданию отчетов по простоям. Получилась своеобразная MES система на минималках по регистрации простоев, которая пока так и останется экспериментом, а мы так и будем юзать MS SQL и IIS :)