Ситуация нечастая, но если происходит, то выбешивает зверски.
Устройства на даче «висят» на брокере, находящемся в городской квартире. За последние лет десять, если и были сбои в этой связке, то на стороне дачного интернета.
Поскольку исповедуемая мной религия умного дома отрицает наличие единого центра управления, потеря Интернет, да даже — wifi, не влияет на работоспособность конечных устройств.
Вместе с тем, дома отсутствует информация о происходящем. И еще грустнее, когда «ломается» домашний Интернет. Таки это случилось, с 14 февраля и по сей день(19 февраля) Интернета нет и … есть уже три обещания починить «21 февраля(!!!!! Медвежий угол!) до 12 часов.» Провайдер — Алмател.
Дачные устройства живут своей жизнью и только сигнализация по своему каналу подтверждает, что жизнь эта вполне нормальная.
А что бы сделать с этой несправедливостью? Почему бы не предложить каждому устройству, в зависимости от доступности, на выбор штуки три брокера? Первый, главный — квартира. К нему прицеплен Домотикз. Второй — поставить брокер на даче, благо старых роутеров и малин хватает. Третий — общедоступный брокер, типа mqtt.eclipse.org. Устройство переключается между брокерами и периодически проверяет доступность своего, главного. Связи нет — возвращается к доступному.
Если «валится» основная система — ничто не мешает подключиться к запасным и в ручном режиме, через MqttSpy или MqttFX поинтересоваться делами.
И скажу честнее — несмотря на декларации о суверенитете каждого устройства, есть некоторые, что все таки требуют сторонней информации — выключатели света должны знать об уровне освещенности, управление отоплением мастерской входит в аварийный режим (Оно работает, но без обратной связи. Греет мастерскую на среднюю мощность), если не имеет данных о температуре в помещении.
Ок, как будем действовать.
Напрашивается первый шаг — создать таблицу с адресами брокеров. Шаг разумный, но затратный по памяти. Поход выбрал такой — делаю список брокеров в отдельном файле и читаю его, при необходимости.
Файл brklist.lua очень прост:
мой.брокер.ru,8883
192.168.1.84,1883
mqtt.eclipse.org,1883
Добывать строки из списка будет файл brkget.lua так:
-- возвращаем функцию, что принимает номер строки
return function(n)
local dt
-- открываем файл с перечнем брокеров и читаем построчно до нужной
if file.open("brklist.lua", "r") then
for i = 1, n do
dt = file.readline()
end
file.close()
end
if not dt then print('Lost List'); return end
-- через захваты выделяем брокер и порт
local brk, port = string.match(dt, "(.+),(%d+)")
return brk, port
end
Применять связку вышеименованных файлов надо так:
brk, port = dofile('brkget.lua')(номерстроки)
Теперь несколько мыслей. Объект mqtt будет периодически «изготавливаться» неким куском кода и возвращаться в оперативную память, ибо он там обязан висеть постоянно. Этот код может быть изготовлен отдельным файлом, ибо постоянно в памяти он сам не нужен.
Объект этот, также, обязан иметь (тоже в оперативной памяти) две реакции на события «потеря связи с брокером» и «пришло сообщение от брокера». Последнее важно даже для одиночного датчика температуры, потому что нынче я привык вызывать онлайн редактор для любого устройства и править там код.
Таким образом, для создания объекта MQTT потребуется еще два файла — один вызываемый периодически для конструирования mqtt а другой — единожды, для заготовки событий «offline» и «message».
mqttset.lua, вызывается один раз и укладывает в память типовые реакции на события mqtt:
do
-- Строка в списке брокеров
dat.nobrk = 1
-- Количество ошибок подключения к основному брокеру
-- ибо любая случайная ошибка должна приводить к попытке восстановления
-- связи, а не к пререключению на запасной брокер
dat.erhome = 0
-- Резервируем переменные для реакций, одинаковых для
-- любого брокера
local subscribe, merror, mconnect, msg
-- Что делаем после соединения с брокером
function subscribe(con)
dat.broker = true
con:subscribe(dat.clnt.."/com/#", 0)
con:publish(dat.clnt..'/state', "ON", 0, 1)
print("Subscribed to "..dat.clnt.."/com/# Heap: "..node.heap())
dat.erhome = 0
-- Если это не первая строка (не главный брокер), то будет попытка
-- пересоединения, вызывается соответствующий таймер
if dat.nobrk ~= 1 then dofile('brkkill.lua')(mconnect) end
end
-- Реакция на ошибку одинакова для всех брокеров
-- уничтожение соединения, объекта и повторное его создание
function merror(con, reason)
con, reason, m = nil,nil,nil
tmr.create():alarm(10000, tmr.ALARM_SINGLE, mconnect)
collectgarbage()
end
-- Приход сообщения
function msg(con, top, dt)
-- Таблица для вставки и передачи топика и даты на обработку
if not killtop then killtop = {} end
-- Захват топика из всей подписки
top = string.match(top, "/(%w+)$")
print('Got', top, dt)
if dt then
-- Вставляем данные в глобльную таблицу и вызываем обработчик
table.insert(killtop, {top, dt})
if not dat.analiz then
dofile("mqttanalize.lua")
end
end
end
-- Функция создания соединения и соединение
function mconnect()
-- Вызываем файл создания соединения и передаем ему ссылки
-- на общие реакции или функцию обработки ошибки, если нет wifi
if (wifi.sta.getip()) then
return dofile('mqttmake.lua')(subscribe, merror, msg)
else
return merror()
end
end
-- Первый вызов
mconnect()
end
Файл mqttmake.lua вызывается многократно, создает новый mqtt и вызывает соединение:
-- Возвращает функцию с аргументами типовых событий
return function(subscribe, merror, msg)
-- Небольшой счетчик для обеспечения трех попыток соединения с
-- домашним сервером
if dat.erhome > 2 then
dat.nobrk = dat.nobrk == dat.brkn and 1 or dat.nobrk + 1
else dat.erhome = dat.erhome + 1 end
-- Получаем очередного брокера
local brk, port = dofile('brkget.lua')(dat.nobrk)
-- Создаем соединение и вызываем его
m = mqtt.Client(dat.clnt, 25, dat.clnt, 'pass22')
m:lwt(dat.clnt..'/state', "Off", 0, 1)
m:on("offline", merror)
m:on("message", msg)
print('Connect to', brk, 'Heap', node.heap())
m:connect(brk, port, false, subscribe, merror)
end
Для обеспечения работы всего выше указанного, заранее должна быть создана таблица dat с таким содержимым:
dat = {}
-- Номер строки брокера
dat.nobrk = 1
-- Имя клиента MQTT
dat.clnt = 'test8266/'-- ..node.chipid()
-- Количество строк в файле списка брокеров
dat.brkn = 3
dofile'mqttset.lua'
Общий типовой шаблон запуска скриптов с init.lua, ide.lua, etc., со всем перечисленным ранее и кое-какими изменениями (ибо выше описана только логика) — по ссылке ниже.
Игорь, a ты здесь есть или нет?
http://arduino.ru/forum/otvlechennye-temy/starikam-na-porazmyshlyat
НравитсяНравится
Что я там забыл. У меня сейчас столярка на первом месте, переделка подсветки и еще туча туча дел разного калибра. Нет времени что-то читать.
НравитсяНравится
Понятно.а то ник igorkkk, а стилистика на тебя не похожа.
Филин там все возмущается, что ты никак не успокоишься.
НравитсяНравится
Безразлично. Это прошлое.
НравитсяНравится