Что в итоге получилось можно увидеть на видео:
А теперь подробности.
Чтобы решить это недоразумение, я написал скрипт на Node.JS, который при запуске выполняет функцию моста между MQTT-брокером и 1С сервером.
Схема взаимодействия такая:
Для работы скрипта требуется установить Node.js. Писать инструкцию по установке я не буду, в интернете их полно, кроме самого Node.js понадобиться ещё и менеджер пакетов npm для установки дополнительных библиотек.
Создаём каталог, где будут лежать все файлы для скрипта, например: "c:\mqtt_over_http"
Далее установим необходимые библиотеки, для это в командной строке (cmd.exe), находясь в созданном каталоге, выполним следующие команды:
npm install mqtt --save
npm install express --save
npm install request --save
npm install dotenv --save
Теперь приступим к самому скрипту. Сохраняем его в файл, например: "c:\mqtt_over_http\server.js"
require('dotenv').config();
const config = {
mqtt : {
server : process.env.MQTT_SERVER,
options : {
clientId : process.env.MQTT_CLIENTID,
username : process.env.MQTT_USERNAME,
password : process.env.MQTT_PASSWORD,
keepalive : 60,
reconnectPeriod : 1000,
clean : true
}
},
http : {
serverport : parseInt(process.env.HTTP_SERVERPORT),
url : process.env.HTTP_REQUESTURL,
username : process.env.HTTP_USERNAME,
password : process.env.HTTP_PASSWORD
}
}
const mqtt = require('mqtt');
const express = require('express')
const app = express()
const bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
const client = mqtt.connect(config.mqtt.server, config.mqtt.options);
//handle incoming messages
client.on('message',function(topic, msg, packet){
var req = require('request');
req.post({
url: config.http.url,
headers: {
"Content-Type": "application/json"
},
auth : {
username: config.http.username,
password: config.http.password
},
body: {
"topic": topic,
"msg": msg.toString('utf8'),
"qos": packet.qos
},
json: true
});
});
client.on("connect",function(){
console.log("connected "+ client.connected);
})
//handle errors
client.on("error",function(error){
console.log("Can't connect" + error);
process.exit(1)
})
//publish
function publish(topic,msg,options){
if (client.connected == true){
client.publish(topic,msg,options);
}
}
app.post('/subscribe', (request, response) => {
var topic = request.body.topic;
var qos = request.body.qos;
if (typeof topic == "undefined") {
response.status(400).send('topic not specified');
} else if (typeof qos == "undefined") {
response.status(400).send('qos not specified');
} else {
client.subscribe(topic,{qos:qos});
response.status(200).send();
}
})
app.post('/publish', (request, response) => {
var topic = request.body.topic;
var msg = request.body.msg;
var retain = request.body.retain;
var qos = request.body.qos;
if (typeof topic == "undefined") {
response.status(400).send('topic not specified');
} else if (typeof msg == "undefined") {
response.status(400).send('msg not specified');
} else if (typeof retain == "undefined") {
response.status(400).send('retain not specified');
} else if (typeof qos == "undefined") {
response.status(400).send('qos not specified');
} else {
publish(topic, msg, {retain:retain,qos:qos});
response.status(200).send();
}
})
app.listen(config.http.serverport)
Рядом с ним необходимо создать файл ".env" (прям с таким названием, как-будто только расширение) со следующим содержимым:
MQTT_SERVER=mqtt://srv2.mqtt.4api.ru:9991 // адрес mqtt-брокера, я в примере использовал бесплатный сервер
MQTT_CLIENTID=mqqt_over_http // тут указывается Client ID, который должен быть уникальным для каждого клиента
MQTT_USERNAME=myuser // логин для подключения
MQTT_PASSWORD=mypassword // пароль для подключения
HTTP_SERVERPORT=3000 // порт, который будет слушать скрипт для входящих от 1С запросов
HTTP_REQUESTURL=http://127.0.0.1:8080/iot/hs/mqtt/publish // адрес HTTP-сервиса сервера 1С, куда будут отправляться полченные по подписке сообщения. Выполняется POST запрос с JSON-телом {topic, msg, qos}
HTTP_USERNAME=mqtt_user // имя пользователя 1С
HTTP_PASSWORD=mqtt_password // пароль пользователя 1С
Таким должен получиться каталог со скриптом:
Готово, теперь можно запускать.
node c:\mqtt_over_http\server.js
Скрипт работает и может принять запрос на подписку.
В качестве примера устройств, которые будет обмениваться информацией с 1С, были выбраны ESP32 с WiFi на борту.
На платы установлена RTOS (Mongoose-OS) в ней уже есть библиотеки для работы с MQTT-брокером и для примера я буду управлять вcтроенным синим светодиодом.
В архив к этой статье я прикреплю прошивку, которую можно прошить. Алгоритм прошивки следующий:
В программе mos.exe переходим в каталог с прошивкой (в примере C:/mos/app1)
- Выбираем порт для подключения (в примере COM3)
- Выбираем плату (в примере ESP32)
- Запускаем сборку прошивки: mos build
- Запускаем прошивку платы: mos flash
- Настраиваем подключение к WiFi: mos wifi mywifi 012345467 (где mywifi - имя сети, а 01234567 - пароль)
- Настраиваем подключение к MQTT-брокеру: mos config-set mqtt.enable=true mqtt.server=srv2.mqtt.4api.ru:9991 mqtt.user=myuser mqtt.pass=mypassword (Client ID - это серийный номер платы)
- И указываем, что диод, которым мы будем управлять находится на ноге 2: mos config-set board.led1.pin=2
- Всё
Сделаем конфигурацию, которая будет демонстрировать пример взаимодействия.
Для этого в конфигурации создадим и опубликуем HTTP-сервис c функцией принимающей сообщения и регистр сведений, который будет хранить последнее сообщение в топике:
И панель управления нашими платами:
Теперь всё готово.
Задержка между событиями возникает из-за того, что обмен происходит через сервер, а клиент получает ответы только по "таймеру", но события на сервере возникают моментально, так-что реагировать на них можно оперативно.
Материал из статьи не претендует на использование его в продуктивных средах "из коробки", но для возможного варианта архитектуры очень может пригодиться.