Электроника плотно укоренилась в нашей жизни. И речь идёт не о повседневном пользовании благами цивилизации. Мы говорим о тех моментах, когда устройства, созданные на аломощных и недорогих компонентах, решают довольно большой спектр повседневных задач. Они омогают нам с бытом, следят за безопасностью и контролируют наше жилое пространство.

С чего началось

 Решил я с приближением зимнего периода, понаблюдать за температурными параметрами в своей квартире и определить качество отопления, если можно так сказать. Если рассмотреть идею с точки зрения АСУ, то нижний уровень будут занимать датчики температуры, средний уровень - Arduino UNO. И верхний - это два варианта SCADA

Два температурных датчика, которые уже были у меня в наличии, оказались как нельзя кстати. Приведенный пример построен на одном датчике DS18B20 (1-wire) — показать основной принцип. В дальнейшем, без труда можно добавлять любое количество датчиков. Крепить их в необходимых точках и считывать этот физический мир ????. Задача на самом деле довольно тривиальна с учетом наличия большого числа IoT платформ. Но лично мне хотелось получить от процесса больше свободы. Иметь возможность не только получать данные на готовый UI, но и сделать этот интерфейс, что называется, с нуля. Но все же, простой вариант я тоже опишу.

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

  • устанавливать Ethernet соединение

  • опрашивать датчики 

  • отправлять данные по протоколу MQTT брокеру

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

. Протокол создавался как  способ поддержания связи между машинами в сетях с ограниченной пропускной способностью или с непредсказуемой связью. [1]

Более подробно техническую сторону MQTT можно почитать тут:

  1. https://habr.com/ru/articles/463 669/

MQTT хорошо себя зарекомендовал как раз в сфере домашней автоматизации и систем IoT. 

Моя панель Дома с Алисой после добавления точек
Моя панель Дома с Алисой после добавления точек

  Данные будут поступать или на IoT платформу или на любого клиента. Я в качестве таковых использовал «Дом с Алисой» и одну из платформ для облачных решений в области IoT, MQTT-брокер «wqtt.ru». Он предоставляет возможность легкой интеграции с «Дом с Алисой». Достаточно прост авторизоваться в системе через аккаунт Яндекса. Далее в приложении
выбрать сервис WQTT. https://rightech.io/ - версия верхнего уровня представляет собой уже готовое решение - облачный сервис для интернета вещей. Имеется дружелюбный мануал по настройке связи с нижним уровнем, добавлению сущностей и обработки событий.

Второй вариант более сложный, с точки зрения клиент-серверной части, но, так как я сам занимаюсь Javascript и NodeJS, мне он показался интереснее как для примера, так и для повышения моего скила, как разработчика IoT.

  • Набор датчиков и скетч - тот же.

  • На любом арендованном сервере разворачиваем NodeJs.

  • Устанавливаем фреймворк Express, который позволит создать гибко настраиваемую клиентскую часть и даст нам полную свободу действий по написанию нашего веб-интерфейса (у хостера есть хорошая документация по установке).
    Данные мы будем передавать также по протоколу MQTT, а на серверной стороне использовать JSON, чтоб AJAX-запросами тянуть данные на страничку.

Заветный JSON файл.
Заветный JSON файл.

По умолчанию, Express работает с шаблонизатором PUG. Вообще, шаблон это такой крутой инструмент, который, при правильном использовании, весомо освобождает время разработчика. Зачем повторять кусочки кода, если можно их превратить в некий паттерн и "дергать" по мере необходимости. После установки Express у нас автоматически создалась структура папок, шаблонов и статических директив.

Основное волшебство происходит на серверах...

Стоит хотя бы в каком-то понятном виде получить данные с Arduino. Напомню, что протокол MQTT устроен по принципу подписок и топиков. Для Node JS имеется множество библиотек и MQTT - не исключение. К библиотекам, как правило, прилагаются понятные мануалы и примеры использования. Недостающая информация легко гуглится. Создаем файл библиотеки в папке /lib и экспортируем его в основной файл NodeJS. В основном файле app. js вызываем библиотеку mq.js. После всех манипуляций, в консоли вы должны получить данные с Arduino. Если все получилось, это пол пути, причем успешного!). ????

Код на сервере:

// подключаем необходимые библеотеки и модули
var createError = require("http-errors");
var express = require("express");
var path = require("path");
var cookieParser = require("cookie-parser");
var logger = require("morgan");
var indexRouter = require("./routes/index");
var usersRouter = require("./routes/users");
var testRouter = require("./routes/test");
var mq = require("./lib/mq.js");

mq.mq();

var {tempHot}=require('./lib/mq.js');
app.listen(80); 
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "pug");
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, "public")));
app.use(express.static(path.join(__dirname, "lib")));
//обработка GET-запроса
app.use("/", indexRouter);
app.use("/users", usersRouter);
app.use("/test", testRouter);
app.get('/data', (req, res) => {
  res.setHeader('Content-Type', 'text/html');
    res.write('<!DOCTYPE html>');
    res.write('<html>');
    res.write('<head>');
    res.write('<title>Hello Node.js</title>');
    res.write('<meta charset="utf-8" />');
    res.write('</head>');
    res.write(tempHot, ()=>{
      console.log(tempHot)
    });
    res.write('</html>');
    res.end();
 })
// перехват ошибки 404
app.use(function (req, res, next) {
  next(createError(404));
});
 handler
app.use(function (err, req, res, next) {
  res.locals.message = err.message;
  res.locals.error = req.app.get("env") === "development" ? err : {};
  // формирование странички с ошибкой
  res.status(err.status || 500);
  res.render("error");
});
module.exports = app;

Модуль MQTT:

//подтягиваем библеотеки и переменные
console.log("Script is RUN!");
const mqtt = require("mqtt");
const host = "m3.wqtt.ru";
const port = "9309";
const connectUrl = `mqtt://${host}:${port}`;
const fs = require("fs");
var tempRoom;
var obj;
var data;
//экспортируем модуль 
exports.mq = () => {
    const client = mqtt.connect(connectUrl, {
        clean: true,
        connectTimeout: 4000,
        username: "YOUR USERNAME",
        password: "YOUR PASSWORD",
        reconnectPeriod: 1000,
    });
    Error.stackTraceLimit = 10;
    const topic = "base/state/temperature_room";
    client.on("connect", () => {
        console.log("Connected");
        client.subscribe([topic], () => {
            console.log(`Subscribe to topic '${topic}'`);
            client.on("message", (topic, payload) => {
                tempRoom = payload.toString();
                console.log("Temp room from module", +tempRoom);
                data = {
                    room: tempRoom,
                    hot: "wait"
                };
                data = JSON.stringify(data);
                fs.writeFile('/home/a0888254/domains/a0888254.xsph.ru/public_html/myapp/lib/data.json', data, (err) => {
                    if (err) {
                        console.error(err)
                        return
                    }
                    console.log("File is writed!)");
                })
            });
          
        });
    });
};

Клиентская сторона


Затем я хочу использовать возможности JavaScript по записи и считыванию файлов, таким образом создав некий буферный файл, в котором текущие параметры перезаписываются при следующем обновлении. Именно отсюда я буду вытягивать AJAXом значения на клиентскую сторону. Для начала надо создать и подключить необходимый скрипт. Для этого в папке Public создадим файл app.js. Листинг можно найти в тут: /public/javascript/app.js Его задача получать данные из JSON, парсить их и выводить на страничку в режиме реального времени.

/*Когда сформировался DOM - начинается исполнение кода. 
Функция readFile принимает в квачестве параметргов два аргумента. 
А в  качестве обратного вызова передает ответ на запрос.*/

document.addEventListener("DOMContentLoaded", function () {
  var data;
  var outputs = document.getElementsByTagName("output");

  function readFile(file, callback) {
    var rawFile = new XMLHttpRequest();
    rawFile.overrideMimeType("application/json");
    rawFile.open("POST", file, true);
    rawFile.onreadystatechange = function () {
      if (rawFile.readyState == 4 && rawFile.status == "200") {
        callback(rawFile.responseText);
      }
    }
    rawFile.send()
  }
  function rd() {
    readFile("myapp/lib/data.json", function (text) {
      data = JSON.parse(text);
      outputs[0].innerHTML = '<h2 id="data" style="color=#ff6347">' + data.hot + '°C' + '</h2>';
      outputs[1].innerHTML = '<h2 id="data">' + data.room + '°C' + '</h2>';
    });
  };
  setInterval(rd, 5000)
});

На клиентской стороне размещаются элементы, с которыми взаимодействует конечный пользователь. Будь то простое визуальное взаимодействие (визуальный контроль) или
непосредственные инструменты влияния на процесс. Тут речь идет о всевозможных регуляторах, кнопках, ползунках, слайдерах. В нашем случае мы просто мониторим процесс. Потому нам достаточно будет вывести схематичное отображения измеряемого параметра. и само значение. В дальнейшем, эта страничка может обрасти массой элементов управления и может даже получить звание полноценной SCADA системы. Кто знает ????

Я просто написал страничку на HTML и перевел ее в PUG для шаблонизатора. Обращайте внимание на то, какой шаблон нам надо использовать. Layot - это общий шаблон. В нем можно ничего не править. А вот index.pug - наш малец. В нем мы и работаем в контексте этого абзаца.

После стыковки серверной части и фронтенд получаем мини систему мониторинга.

Ссылка на мой репозиторий github c исходниками тут.

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