Электроника плотно укоренилась в нашей жизни. И речь идёт не о повседневном пользовании благами цивилизации. Мы говорим о тех моментах, когда устройства, созданные на аломощных и недорогих компонентах, решают довольно большой спектр повседневных задач. Они омогают нам с бытом, следят за безопасностью и контролируют наше жилое пространство.
С чего началось
Решил я с приближением зимнего периода, понаблюдать за температурными параметрами в своей квартире и определить качество отопления, если можно так сказать. Если рассмотреть идею с точки зрения АСУ, то нижний уровень будут занимать датчики температуры, средний уровень - Arduino UNO. И верхний - это два варианта SCADA.
Два температурных датчика, которые уже были у меня в наличии, оказались как нельзя кстати. Приведенный пример построен на одном датчике DS18B20 (1-wire) — показать основной принцип. В дальнейшем, без труда можно добавлять любое количество датчиков. Крепить их в необходимых точках и считывать этот физический мир ????. Задача на самом деле довольно тривиальна с учетом наличия большого числа IoT платформ. Но лично мне хотелось получить от процесса больше свободы. Иметь возможность не только получать данные на готовый UI, но и сделать этот интерфейс, что называется, с нуля. Но все же, простой вариант я тоже опишу.
В любом случае для нижнего уровня оба варианта предполагают написание скетча, который будет выполнять сразу несколько задач:
устанавливать Ethernet соединение
опрашивать датчики
-
отправлять данные по протоколу MQTT брокеру
MQTT как нельзя лучше подходит для таких задач. В названии статьи сама суть его работы.
. Протокол создавался как способ поддержания связи между машинами в сетях с ограниченной пропускной способностью или с непредсказуемой связью. [1]
Более подробно техническую сторону MQTT можно почитать тут:
MQTT хорошо себя зарекомендовал как раз в сфере домашней автоматизации и систем IoT.
Данные будут поступать или на IoT платформу или на любого клиента. Я в качестве таковых использовал «Дом с Алисой» и одну из платформ для облачных решений в области IoT, MQTT-брокер «wqtt.ru». Он предоставляет возможность легкой интеграции с «Дом с Алисой». Достаточно прост авторизоваться в системе через аккаунт Яндекса. Далее в приложении
выбрать сервис WQTT. https://rightech.io/ - версия верхнего уровня представляет собой уже готовое решение - облачный сервис для интернета вещей. Имеется дружелюбный мануал по настройке связи с нижним уровнем, добавлению сущностей и обработки событий.
Второй вариант более сложный, с точки зрения клиент-серверной части, но, так как я сам занимаюсь Javascript и NodeJS, мне он показался интереснее как для примера, так и для повышения моего скила, как разработчика IoT.
Набор датчиков и скетч - тот же.
На любом арендованном сервере разворачиваем NodeJs.
Устанавливаем фреймворк Express, который позволит создать гибко настраиваемую клиентскую часть и даст нам полную свободу действий по написанию нашего веб-интерфейса (у хостера есть хорошая документация по установке).
Данные мы будем передавать также по протоколу MQTT, а на серверной стороне использовать JSON, чтоб AJAX-запросами тянуть данные на страничку.
По умолчанию, 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 исходниками тут.