Примеры скриптов
Приведенные примеры служат исключительно для демонстации построения тех или иных алгоритмов и не отмменяет необходимость в изучении языка программирования LUA.
Скрипт инициализации
-- init.lua --
-- Таймер. Ежеминутный запуск скрипта для отслеживания юзеров в сети
scripts.setTimer("personesTracker", 60)
-- Таймер. Запуск скрипта для каких-либо ежеминутных проверок/действий
scripts.setTimer("flush", 60, "bowl")
-- Уведомление в Telegram о старте шлюза --
telegram.settoken("51778***5:AAG0bvK***")
telegram.setchat("-3348***")
telegram.send("SLS загружен!!!")
--[[
Уведомление в Telegram о времени восхода и заката солнца.
Для правильной работы необходимо в системных настройках
заполнить данные о координатах шлюза в меню Settings -> Time & Location
--]]
local sunset_hour, sunset_min = os.sunset()
local sunrise_hour, sunrise_min = os.sunrise()
telegram.send("sunrise " .. sunset_hour .. ":" .. sunset_min)
-- Инициализация объектов для обмена между скриптами --
obj.setType("there.is.no.spoon", "BOOL")
obj.set("there.is.no.spoon", true, true)
-- Привязка скрипта btn_sw1.lua к событию нажатия аппаратной кнопки шлюза --
obj.onChange("io.input0.value", "btn_sw1.lua")
-- init.lua --
-- Таймер. Ежеминутный запуск скрипта для отслеживания юзеров в сети
scripts.setTimer("personesTracker", 60)
-- Таймер. Запуск скрипта для каких-либо ежеминутных проверок/действий
scripts.setTimer("flush", 60, "bowl")
-- Уведомление в Telegram о старте шлюза --
telegram.settoken("51778***5:AAG0bvK***")
telegram.setchat("-3348***")
telegram.send("SLS загружен!!!")
--[[
Уведомление в Telegram о времени восхода и заката солнца.
Для правильной работы необходимо в системных настройках
заполнить данные о координатах шлюза в меню Settings -> Time & Location
--]]
local sunset_hour, sunset_min = os.sunset()
local sunrise_hour, sunrise_min = os.sunrise()
telegram.send("sunrise " .. sunset_hour .. ":" .. sunset_min)
-- Инициализация объектов для обмена между скриптами --
obj.setType("there.is.no.spoon", "BOOL")
obj.set("there.is.no.spoon", true, true)
-- Привязка скрипта btn_sw1.lua к событию нажатия аппаратной кнопки шлюза --
obj.onChange("io.input0.value", "btn_sw1.lua")
События
Разбор всех свойств событий
При разработке сценариев, часто требуется получить все параметры, передаваемые в него через события. Но, не все свойства бывают описаны в документации. Особенно при добавлении в прошивку новых функций или доработке существующих. Для получения и разбора всех свойств, может помочь такой пример:
for key, val in pairs(Event) do
if type(val) == "table" then
for key2, val2 in pairs(val) do
print("Event." .. key .. "." .. key2, val2)
end
else
print("Event." .. key, val)
end
end
for key, val in pairs(Event) do
if type(val) == "table" then
for key2, val2 in pairs(val) do
print("Event." .. key .. "." .. key2, val2)
end
else
print("Event." .. key, val)
end
end
Пример вывода:
[22:28:49.552] [Scripts] Event.State.OldValue true
[22:28:49.558] [Scripts] Event.State.Name contact
[22:28:49.563] [Scripts] Event.State.Value false
[22:28:49.568] [Scripts] Event.Name tables.lua
[22:28:49.667] [Scripts] Event.Type 1
[22:28:49.672] [Scripts] Event.Param
[22:28:49.678] [Scripts] Event.nwkAddr 42108
[22:28:49.687] [Scripts] Event.Time.min 28
[22:28:49.694] [Scripts] Event.Time.month 12
[22:28:49.702] [Scripts] Event.Time.year 2022
[22:28:49.709] [Scripts] Event.Time.sec 49
[22:28:49.713] [Scripts] Event.Time.hour 22
[22:28:49.721] [Scripts] Event.Time.wday 5
[22:28:49.726] [Scripts] Event.Time.day 9
[22:28:49.733] [Scripts] Event.ModelId lumi.sensor_magnet
[22:28:49.738] [Scripts] Event.FriendlyName
[22:28:49.745] [Scripts] Event.ieeeAddr 0x0123456789ABCDEF
[22:28:49.552] [Scripts] Event.State.OldValue true
[22:28:49.558] [Scripts] Event.State.Name contact
[22:28:49.563] [Scripts] Event.State.Value false
[22:28:49.568] [Scripts] Event.Name tables.lua
[22:28:49.667] [Scripts] Event.Type 1
[22:28:49.672] [Scripts] Event.Param
[22:28:49.678] [Scripts] Event.nwkAddr 42108
[22:28:49.687] [Scripts] Event.Time.min 28
[22:28:49.694] [Scripts] Event.Time.month 12
[22:28:49.702] [Scripts] Event.Time.year 2022
[22:28:49.709] [Scripts] Event.Time.sec 49
[22:28:49.713] [Scripts] Event.Time.hour 22
[22:28:49.721] [Scripts] Event.Time.wday 5
[22:28:49.726] [Scripts] Event.Time.day 9
[22:28:49.733] [Scripts] Event.ModelId lumi.sensor_magnet
[22:28:49.738] [Scripts] Event.FriendlyName
[22:28:49.745] [Scripts] Event.ieeeAddr 0x0123456789ABCDEF
Включение режима сопряжения по нажатию на кнопку шлюза
По нажатию на аппаратную кнопку будет включаться режим сопряжения (Join) Zigbee устройств.
- в
init.lua
добавить код:
obj.onChange("io.input0.value", "btn_sw1.lua")
obj.onChange("io.input0.value", "btn_sw1.lua")
- создать
btn_sw1.lua
с кодом:
zigbee.join(255, "0x0000")
zigbee.join(255, "0x0000")
Обработка нажатий кнопки и управление светом
Переключение света через управление яркостью
-- однократное нажатие, включить свет (яркость max)
if Event.State.Value == "single" then
value = 255
-- двойное нажатие, выключить свет (яркость 0)
elseif Event.State.Value == "double" then
value = 0
-- другие нажатия - ничего не делать
else
return
end
-- непосредственно, отправка полученного значения в целевое устройство
zigbee.set("lamp_1", "brightness", value)
-- однократное нажатие, включить свет (яркость max)
if Event.State.Value == "single" then
value = 255
-- двойное нажатие, выключить свет (яркость 0)
elseif Event.State.Value == "double" then
value = 0
-- другие нажатия - ничего не делать
else
return
end
-- непосредственно, отправка полученного значения в целевое устройство
zigbee.set("lamp_1", "brightness", value)
Переключение света
if Event.State.Value == "single" then
value = "ON"
elseif Event.State.Value == "double" then
value = "OFF"
else
return
end
zigbee.set("lamp_1", "state", value)
if Event.State.Value == "single" then
value = "ON"
elseif Event.State.Value == "double" then
value = "OFF"
else
return
end
zigbee.set("lamp_1", "state", value)
Делаем управление кнопкой LED
Статья пользователя Сергей Кушеев
Управление светом Zigbee
Управление свойствами осветительных приборов: получить состояние, включить, выключить, изменить яркость/цвет/цветовую температуру, на примере лампы TS0505B
Получить яркость, цвет, температуру и статус
- статус вкл/выкл - state = ON/OFF
- яркость - brightness = 0..255
- текущий режим управления цветом - color_mode = xy (цвет) | color_temp (температура)
- цветовая температура - color_temp = 153..500 по шкале Mired
- цвет - color = значения XYHS в объекте JSON
- скорость нарастания значения при изменении - transition = 1..255 сек
local device = "0xA4C138FD68EAA226"
brightness = zigbee.value(device, "brightness")
color_mode = zigbee.value(device, "color_mode")
color = zigbee.value(device, "color")
color_temp = zigbee.value(device, "color_temp")
state = zigbee.value(device, "state")
transition = zigbee.value(device, "transition")
print("brightness\t", brightness)
print("color_mode\t", color_mode)
print("color\t\t", color)
print("color_temp\t", color_temp)
print("state\t\t", state)
print("transition\t", transition)
local device = "0xA4C138FD68EAA226"
brightness = zigbee.value(device, "brightness")
color_mode = zigbee.value(device, "color_mode")
color = zigbee.value(device, "color")
color_temp = zigbee.value(device, "color_temp")
state = zigbee.value(device, "state")
transition = zigbee.value(device, "transition")
print("brightness\t", brightness)
print("color_mode\t", color_mode)
print("color\t\t", color)
print("color_temp\t", color_temp)
print("state\t\t", state)
print("transition\t", transition)
Пример вывода
brightness 1
color_mode color_temp
color {"x":0.696955,"y":0.299588,"hue":328.8189,"saturation":0.716535}
color_temp 295
state ON
transition 0
brightness 1
color_mode color_temp
color {"x":0.696955,"y":0.299588,"hue":328.8189,"saturation":0.716535}
color_temp 295
state ON
transition 0
Включить, выключить, переключить
Для управления статусом отправить в состояние state
ON
- включитьOFF
- выключитьTOGGLE
- переключить
При этом устройство включится со значениями яркости, цвета и температуры, установленными ранее.
Также устройство включится, если отправить любое значение яркости > 0 и выключится если отправить яркость = 0.
local device = "0xA4C138FD68EAA226"
zigbee.set(device, "state", "ON") -- включить
zigbee.set(device, "state", "OFF") -- выключить
zigbee.set(device, "state", "TOGGLE") -- переключить
local device = "0xA4C138FD68EAA226"
zigbee.set(device, "state", "ON") -- включить
zigbee.set(device, "state", "OFF") -- выключить
zigbee.set(device, "state", "TOGGLE") -- переключить
Изменить яркость
local device = "0xA4C138FD68EAA226"
zigbee.set(device, "brightness", 25) -- установить яркость на 10%. Если лампа выключена - включится
zigbee.set(device, "brightness", 0) -- выключить
local device = "0xA4C138FD68EAA226"
zigbee.set(device, "brightness", 25) -- установить яркость на 10%. Если лампа выключена - включится
zigbee.set(device, "brightness", 0) -- выключить
Изменить цветовую температуру
Управление цветовой температурой осуществляется по шкале Mired. Для конвертации можно воспользоваться формулой:
color_temp_mired = 1000000 / color_temp_kelvin
local device = "0xA4C138FD68EAA226"
local color_temp = 1000000/4700
zigbee.set(device, "color_temp", color_temp) -- установить цветовую температуру 4700 Кельвин
local device = "0xA4C138FD68EAA226"
local color_temp = 1000000/4700
zigbee.set(device, "color_temp", color_temp) -- установить цветовую температуру 4700 Кельвин
Изменить цвет
Для изменения цвета можно отправлять значения в следующих форматах:
color
основные цвета, например "red"xy
, например '{"x":0.697,"y":0.3}'hue, saturation
, например '{"hue":328.82,"saturation":0.717}'hue
, например '{"hue":328.82}'saturation
, например '{"saturation":0.717}'hex
, например '{"hex": "#RRGGBB"}'rgb
, например '{"r":200,"g":0,"b":0}'
local device = "0xA4C138FD68EAA226"
local color_xy = '{"x":0.697,"y":0.3}'
zigbee.set(device, "color", color_xy)
local device = "0xA4C138FD68EAA226"
local color_xy = '{"x":0.697,"y":0.3}'
zigbee.set(device, "color", color_xy)
local device = "0xA4C138FD68EAA226"
local color_rgb = '{"r":200,"g":0,"b":0}'
zigbee.set(device, "color", color_rgb)
local device = "0xA4C138FD68EAA226"
local color_rgb = '{"r":200,"g":0,"b":0}'
zigbee.set(device, "color", color_rgb)
Изменить плавность управления
Плавность изменения режимов, например яркости, управляется состоянием transition
- время в секундах, в течение которого будет происходить изменение установленного значения
local device = "0xA4C138FD68EAA226"
zigbee.set(device, "transition", 3) -- при изменении значения, например яркости, последняя будет нарастать от текущего значения до установленного в течение 3 секунд
local device = "0xA4C138FD68EAA226"
zigbee.set(device, "transition", 3) -- при изменении значения, например яркости, последняя будет нарастать от текущего значения до установленного в течение 3 секунд
Zigbee
Включение режим сопряжения для подключения новых устройств, через роутер
-- включить JOIN через роутер "plug1", на 255 секунд
zigbee.join(255, "plug1")
-- включить JOIN через роутер "plug1", на 255 секунд
zigbee.join(255, "plug1")
Получение значения состояния устройства из кэша
-- Получаем значение температуры и округляем до целого
local device = "FriendlyName" -- также можно использовать ieeeAddr и nwkAddr
temp = zigbee.value(device, "temperature")
temp = math.floor(temp)
print("Текущая температура: " .. temp .. " C°")
-- Получаем значение температуры и округляем до целого
local device = "FriendlyName" -- также можно использовать ieeeAddr и nwkAddr
temp = zigbee.value(device, "temperature")
temp = math.floor(temp)
print("Текущая температура: " .. temp .. " C°")
Вызов команды GET в конвертере
-- Вызов команды GET в конвертере для состояния brightness, устройства с FriendlyName lamPochka
zigbee.get("lamPochka", "brightness")
-- Вызов команды GET в конвертере для состояния brightness, устройства с FriendlyName lamPochka
zigbee.get("lamPochka", "brightness")
Переключение лампочки при нажатии кнопки выключателя
- при нажатии кнопки выключателя переключает лампу lamp_1 через контроль яркости. Может выполняться как самостоятельно, например по таймеру, так и из правила Simple Bind
-- получаем значение состояния 'click' кнопки 'lumi.sensor_switch'
-- если значение = single
if zigbee.value("lumi.sensor_switch", "click") == "single" then
-- переключаем (toggle) лампу
-- получим текущее значение яркости лампы
current_brightness = zigbee.value("lamp_1", "brightness")
-- если лампа выключена (яркость = 0)
if current_brightness == 0 then
-- включим её
zigbee.set("lamp_1", "brightness", 255)
else -- если включена (значение яркости отлично от 0)
-- включим
zigbee.set("lamp_1", "brightness", 0)
end
end
-- получаем значение состояния 'click' кнопки 'lumi.sensor_switch'
-- если значение = single
if zigbee.value("lumi.sensor_switch", "click") == "single" then
-- переключаем (toggle) лампу
-- получим текущее значение яркости лампы
current_brightness = zigbee.value("lamp_1", "brightness")
-- если лампа выключена (яркость = 0)
if current_brightness == 0 then
-- включим её
zigbee.set("lamp_1", "brightness", 255)
else -- если включена (значение яркости отлично от 0)
-- включим
zigbee.set("lamp_1", "brightness", 0)
end
end
- при нажатии кнопки переключает лампу 0x00124B0009FE36FC, через установку состояния "State" в "TOGGLE". Должен выполняться из SB Rule
if Event.State.Value == "single" then
zigbee.set("0x00124B0009FE36FC", "state", "toggle")
end
if Event.State.Value == "single" then
zigbee.set("0x00124B0009FE36FC", "state", "toggle")
end
Создание виртуальных свойств устройства
Пример инициализации с сохранением данных
local res= zigbee.setState("0x00124B001F7CA144", "prop_float", floatVal, "FLOAT")
local res= zigbee.setState("0x00124B001F7CA144", "prop_bool", boolVal, "BOOL")
local res= zigbee.setState("0x00124B001F7CA144", "prop_int", intVal, "INT")
local res= zigbee.setState("0x00124B001F7CA144", "prop_int", "strVal", "STR")
os.save()
local res= zigbee.setState("0x00124B001F7CA144", "prop_float", floatVal, "FLOAT")
local res= zigbee.setState("0x00124B001F7CA144", "prop_bool", boolVal, "BOOL")
local res= zigbee.setState("0x00124B001F7CA144", "prop_int", intVal, "INT")
local res= zigbee.setState("0x00124B001F7CA144", "prop_int", "strVal", "STR")
os.save()
Преобразование показателей давления из kPa в mmhg
Необходимо создать lua скрипт и назначить его вызов при изменении pressure в правило SB:
-- kPa2mmhg.lua
local pressure = zigbee.value(tostring(Event.ieeeAddr), "pressure")
zigbee.setState(Event.ieeeAddr, "pressure_mm", pressure * 0.75, "FLOAT")
-- kPa2mmhg.lua
local pressure = zigbee.value(tostring(Event.ieeeAddr), "pressure")
zigbee.setState(Event.ieeeAddr, "pressure_mm", pressure * 0.75, "FLOAT")
Второй вариант. Сразу записать правило в такм виде:
#zigbee.setState(Event.ieeeAddr, "pressure_mm", zigbee.value(tostring(Event.ieeeAddr), "pressure") * 0.75, "FLOAT")
#zigbee.setState(Event.ieeeAddr, "pressure_mm", zigbee.value(tostring(Event.ieeeAddr), "pressure") * 0.75, "FLOAT")
Библиотека Yeelight
Управляет устройством Yeelight. Описание протокола
Получить текущий статус
result = yeelight.send("192.168.0.100", "get_prop", '["power","not_exist","bright"]')
result = yeelight.send("192.168.0.100", "get_prop", '["power","not_exist","bright"]')
Результат
{"id":18,"result":{"on","","100"}}
{"id":18,"result":{"on","","100"}}
Переключить
result = yeelight.send("192.168.0.100", "toggle", '[]')
result = yeelight.send("192.168.0.100", "toggle", '[]')
Результат
{ "method": "props", "params": { "power": "off" } }
{ "method": "props", "params": { "power": "off" } }
Установить яркость
result = yeelight.send("192.168.0.100", "set_bright", '[100,"smooth",500]')
result = yeelight.send("192.168.0.100", "set_bright", '[100,"smooth",500]')
Результат
{ "method": "props", "params": { "active_bright": 100, "bright": 100 } }
{ "method": "props", "params": { "active_bright": 100, "bright": 100 } }
Библиотека OS
Получение текущего часа, времени и секунд, например для планировщика в таймере
local gmt = 3 -- часовой пояс
local time = os.time() + gmt * 3600;
local t1 = math.modf(time/60);
local sec = time - t1*60;
local time = t1;
local t1 = math.modf(time/60);
local min = time - t1*60;
local time = t1;
local t1 = math.modf(time/24);
local hour = time - t1*24;
print(hour .. ":" .. min .. ":" .. sec)
local gmt = 3 -- часовой пояс
local time = os.time() + gmt * 3600;
local t1 = math.modf(time/60);
local sec = time - t1*60;
local time = t1;
local t1 = math.modf(time/60);
local min = time - t1*60;
local time = t1;
local t1 = math.modf(time/24);
local hour = time - t1*24;
print(hour .. ":" .. min .. ":" .. sec)
Включение освещения по датчику движения и выключение через определенное время
Такой сценарий легко решается без использования lua скриптов. Разберем пример из датчика движения Aqara lumi.sensor_motion и исполнительного реле на 8 каналов с modkam.
Вариант 1 с использованием команд SimpleBind
На вкладке датчика движения настраиваем при включении occupation=true будет включать освещение, при occupation=false соответственно выключать.
Пример команды SimpleBind для включения реле по датчику движения:
true,0x00124B001F7CA144,state_l1,ON;false,0x00124B001F7CA144,state_l1,OFF;
true,0x00124B001F7CA144,state_l1,ON;false,0x00124B001F7CA144,state_l1,OFF;
С помощью occupancy_timeout можно задать интервал, в течении которого будет сбрасываться значение датчика.
Вариант 2 с использованием значений датчика освещения и сценариев lua
В данном примере мы будем использовать датчик движения Aqara lumi.sensor_motion.aq2 со встроенным датчиком освещенности и исполнительное реле на 8 каналов с modkam.
Создаем сценарий occupancy.lua
local state = zigbee.value(tostring(Event.ieeeAddr), "occupancy")
local lightlevel = zigbee.value(tostring(Event.ieeeAddr), "illuminance")
local minlightlevel = 300 -- зададим минимальный уровень освещенности, когда необходимо включать освещение
if (state) then telegram.send("Датчик движения ".. Event.FriendlyName .." обнаружил активность")
if (lightlevel < minlightlevel) then
zigbee.set("0x00124B001F7CA144", "state_l2", "ON")
telegram.send("Свет в комнате ".. Event.FriendlyName .." включили")
else
telegram.send("Значение датчика движения ".. Event.FriendlyName .." нормализовалось")
if (lightlevel < minlightlevel) then
zigbee.set("0x00124B001F7CA144", "state_l2", "OFF")
telegram.send("Свет в комнате ".. Event.FriendlyName .." выключили")
end
end
local state = zigbee.value(tostring(Event.ieeeAddr), "occupancy")
local lightlevel = zigbee.value(tostring(Event.ieeeAddr), "illuminance")
local minlightlevel = 300 -- зададим минимальный уровень освещенности, когда необходимо включать освещение
if (state) then telegram.send("Датчик движения ".. Event.FriendlyName .." обнаружил активность")
if (lightlevel < minlightlevel) then
zigbee.set("0x00124B001F7CA144", "state_l2", "ON")
telegram.send("Свет в комнате ".. Event.FriendlyName .." включили")
else
telegram.send("Значение датчика движения ".. Event.FriendlyName .." нормализовалось")
if (lightlevel < minlightlevel) then
zigbee.set("0x00124B001F7CA144", "state_l2", "OFF")
telegram.send("Свет в комнате ".. Event.FriendlyName .." выключили")
end
end
На вкладке датчика движения привязываем сценарий
Вариант 3 с использованием астротаймера и сценариев lua
В данном примере мы будем использовать любой датчик движения, а в качестве определения необходимости включения освещения будем использовать астро-таймер, встроенный в SLS шлюз. Управлять будем реле на 8 каналов с modkam. Перед использованием астротаймера, не забудьте в настройках системы указать ваши координаты:
Создаем сценарий occupancy_astro.lua
local state = zigbee.value(tostring(Event.ieeeAddr), "occupancy")
local sunset_hour, sunset_min = os.sunset() --закат
local sunrise_hour, sunrise_min = os.sunrise() --рассвет
local str = Event.Param
local p = {}
for x in string.gmatch(str,'([^:]+)') do
table.insert(p, x)
end
local ieee=p[1]
local par=p[2]
zigbee.setState(ieee, par .. "_activate_on", "STR") --добавляем переменную для хранения информации, что управляемый сенсор включен датчиком движения
if (state) then -- следует учитывать, что если тип переменной STR, то проверяется ее наличие, а не булево значение
if Event.Time.hour >= sunset_hour or Event.Time.hour <= sunrise_hour then
--если выключен, мы его включаем и записываем, кто включил
if (zigbee.value(ieee, par) == "OFF") then
zigbee.set(ieee, par, "ON")
zigbee.set(ieee, par .. "_activate_on", "PIR")
end
end
else
if Event.Time.hour >= sunset_hour or Event.Time.hour <= sunrise_hour then
--проверяем, если включен не датчиком движений PIR, то не трогаем
if (zigbee.value(ieee, par .. "_activate_on")) == "PIR" then
zigbee.set(ieee, par, "OFF")
zigbee.set(ieee, par .. "_activate_on", "")
end
end
end
local state = zigbee.value(tostring(Event.ieeeAddr), "occupancy")
local sunset_hour, sunset_min = os.sunset() --закат
local sunrise_hour, sunrise_min = os.sunrise() --рассвет
local str = Event.Param
local p = {}
for x in string.gmatch(str,'([^:]+)') do
table.insert(p, x)
end
local ieee=p[1]
local par=p[2]
zigbee.setState(ieee, par .. "_activate_on", "STR") --добавляем переменную для хранения информации, что управляемый сенсор включен датчиком движения
if (state) then -- следует учитывать, что если тип переменной STR, то проверяется ее наличие, а не булево значение
if Event.Time.hour >= sunset_hour or Event.Time.hour <= sunrise_hour then
--если выключен, мы его включаем и записываем, кто включил
if (zigbee.value(ieee, par) == "OFF") then
zigbee.set(ieee, par, "ON")
zigbee.set(ieee, par .. "_activate_on", "PIR")
end
end
else
if Event.Time.hour >= sunset_hour or Event.Time.hour <= sunrise_hour then
--проверяем, если включен не датчиком движений PIR, то не трогаем
if (zigbee.value(ieee, par .. "_activate_on")) == "PIR" then
zigbee.set(ieee, par, "OFF")
zigbee.set(ieee, par .. "_activate_on", "")
end
end
end
Для корректной работы сценария, необходимо передать два параметра через двоеточие, например: occupancy_astro.lua,0x00124B001F7CA144:state_l1. Сценарий запоминает, что свет включен по датчику движения, и выключает только в том случае, если был включен по датчику движения.
Вариант 4. Привязка нескольких устройств с использованием астротаймера и сценариев lua
При вызове lua скрипта необходимо в виде параметров передать список привязываемых устройств. Пример параметров:
occupancy_astro2.lua,0x00124B001EC83D62:state_l4/0x00124B001EC83D62:state_l2
occupancy_astro2.lua,0x00124B001EC83D62:state_l4/0x00124B001EC83D62:state_l2
Пример сценария occupancy_astro2.lua
local state = zigbee.value(tostring(Event.ieeeAddr), "occupancy")
local sunset_hour, sunset_min = os.sunset() --закат
local sunrise_hour, sunrise_min = os.sunrise() --рассвет
local str=Event.Param
for x1 in string.gmatch(str,'([^/]+)') do
local p = {}
for x2 in string.gmatch(x1,'([^:]+)') do
table.insert(p, x2)
end
local ieee=p[1]
local par=p[2]
zigbee.setState(ieee, par .. "_activate_on", "STR") --добавляем переменную для хранения информации, что управляемый сенсор включен датчиком движения
if (state) then
if Event.Time.hour >= sunset_hour or Event.Time.hour <= sunrise_hour then
--если выключен, мы его включаем и записываем, кто включил
if (zigbee.value(ieee, par)=="OFF") then
zigbee.set(ieee, par, "ON")
zigbee.set(ieee, par.."_activate_on", "PIR")
--telegram.send("Свет в комнате ".. Event.FriendlyName .." включили ("..par..")")
end
end
else
if Event.Time.hour >= sunset_hour or Event.Time.hour <= sunrise_hour then
--проверяем, если включен не датчиком движений PIR, то не трогаем
if (zigbee.value(ieee, par.."_activate_on") )=="PIR" then
zigbee.set(ieee, par, "OFF")
zigbee.set(ieee, par.."_activate_on", "")
--telegram.send("Свет в комнате ".. Event.FriendlyName .." выключили")
end
end
end
local state = zigbee.value(tostring(Event.ieeeAddr), "occupancy")
local sunset_hour, sunset_min = os.sunset() --закат
local sunrise_hour, sunrise_min = os.sunrise() --рассвет
local str=Event.Param
for x1 in string.gmatch(str,'([^/]+)') do
local p = {}
for x2 in string.gmatch(x1,'([^:]+)') do
table.insert(p, x2)
end
local ieee=p[1]
local par=p[2]
zigbee.setState(ieee, par .. "_activate_on", "STR") --добавляем переменную для хранения информации, что управляемый сенсор включен датчиком движения
if (state) then
if Event.Time.hour >= sunset_hour or Event.Time.hour <= sunrise_hour then
--если выключен, мы его включаем и записываем, кто включил
if (zigbee.value(ieee, par)=="OFF") then
zigbee.set(ieee, par, "ON")
zigbee.set(ieee, par.."_activate_on", "PIR")
--telegram.send("Свет в комнате ".. Event.FriendlyName .." включили ("..par..")")
end
end
else
if Event.Time.hour >= sunset_hour or Event.Time.hour <= sunrise_hour then
--проверяем, если включен не датчиком движений PIR, то не трогаем
if (zigbee.value(ieee, par.."_activate_on") )=="PIR" then
zigbee.set(ieee, par, "OFF")
zigbee.set(ieee, par.."_activate_on", "")
--telegram.send("Свет в комнате ".. Event.FriendlyName .." выключили")
end
end
end
Уведомления в Телеграм
Контроль состояния важных датчиков с уведомлением в телеграм
Периодичность теста устанавливается периодичностью запуска скрипта по таймеру. Например Cron в 19:00 каждый день
scripts.setTimer("uptime_check", "0 19 * * *")
scripts.setTimer("uptime_check", "0 19 * * *")
-- uptime_check.lua
-- ieeeAddr, nwAddr, friendly_name устройств для контроля и допустимый период отвала
local devices = {
{name = "cnt_kitchen", uptime = 180}, -- 0x00124B0027AEBF18
{name = "cnt_toilet", uptime = 180} -- 0x00124B0027AEBF1C
}
for key, device in pairs(devices) do
--print(key, device)
if math.ceil((os.time() - zigbee.value(device['name'], 'last_seen'))/60) > device['uptime'] then
msg = 'Error: ' .. device['name'] .. ' is down!'
telegram.send(msg)
end
end
-- uptime_check.lua
-- ieeeAddr, nwAddr, friendly_name устройств для контроля и допустимый период отвала
local devices = {
{name = "cnt_kitchen", uptime = 180}, -- 0x00124B0027AEBF18
{name = "cnt_toilet", uptime = 180} -- 0x00124B0027AEBF1C
}
for key, device in pairs(devices) do
--print(key, device)
if math.ceil((os.time() - zigbee.value(device['name'], 'last_seen'))/60) > device['uptime'] then
msg = 'Error: ' .. device['name'] .. ' is down!'
telegram.send(msg)
end
end
Уведомление в телеграм об открытии двери
if (Event.State.Value ~= Event.State.OldValue) then
if (Event.State.Value) then
telegram.send("Дверь закрыта")
else
telegram.send("Дверь открыта")
end
end
if (Event.State.Value ~= Event.State.OldValue) then
if (Event.State.Value) then
telegram.send("Дверь закрыта")
else
telegram.send("Дверь открыта")
end
end
Оповещение в телеграм при сработке датчика движения
local state = zigbee.value(tostring(Event.ieeeAddr), "occupancy")
if (state) then
telegram.send("Датчик движения ".. Event.ieeeAddr .." обнаружил активность")
else
telegram.send("Значение датчика ".. Event.FriendlyName .." движения нормализовалось")
end
local state = zigbee.value(tostring(Event.ieeeAddr), "occupancy")
if (state) then
telegram.send("Датчик движения ".. Event.ieeeAddr .." обнаружил активность")
else
telegram.send("Значение датчика ".. Event.FriendlyName .." движения нормализовалось")
end
Оповещение об изменении значения датчика температуры/влажности
local temp = round2(zigbee.value(tostring(Event.ieeeAddr), "temperature"),1)
local hum = round2(zigbee.value(tostring(Event.ieeeAddr), "humidity"),1)
telegram.send("Значение ДТВ ".. Event.FriendlyName .. " ".. temp.."° / " .. hum .. "%")
local temp = round2(zigbee.value(tostring(Event.ieeeAddr), "temperature"),1)
local hum = round2(zigbee.value(tostring(Event.ieeeAddr), "humidity"),1)
telegram.send("Значение ДТВ ".. Event.FriendlyName .. " ".. temp.."° / " .. hum .. "%")
Подсветка шлюза по датчику движению только в ночное время с 22 до 6
Вариант через GPIO
local gmt = 3
local time = os.time()
local hour = (math.modf(time / 3600) + gmt) % 24
if hour >= 22 or hour < 6 then
if Event.State.Value then
gpio.pwm(0, 255)
gpio.pwm(1, 255)
gpio.pwm(2, 255)
else
gpio.pwm(0, 0)
gpio.pwm(1, 0)
gpio.pwm(2, 0)
end
end
local gmt = 3
local time = os.time()
local hour = (math.modf(time / 3600) + gmt) % 24
if hour >= 22 or hour < 6 then
if Event.State.Value then
gpio.pwm(0, 255)
gpio.pwm(1, 255)
gpio.pwm(2, 255)
else
gpio.pwm(0, 0)
gpio.pwm(1, 0)
gpio.pwm(2, 0)
end
end
Вариант через MQTT:
local gmt = 3
local time = os.time()
local hour = (math.modf(time / 3600) + gmt) % 24
if hour >= 22 or hour <6 then
if Event.State.Value then
mqtt.pub('ZigBeeSls/led', '{"mode":"manual","hex":"#FF0000"}')
else
mqtt.pub('ZigBeeSls/led', '{"mode": "off"}')
end
end
local gmt = 3
local time = os.time()
local hour = (math.modf(time / 3600) + gmt) % 24
if hour >= 22 or hour <6 then
if Event.State.Value then
mqtt.pub('ZigBeeSls/led', '{"mode":"manual","hex":"#FF0000"}')
else
mqtt.pub('ZigBeeSls/led', '{"mode": "off"}')
end
end
Создание режима охраны
Постановка
obj.set("security_status", "armed")
obj.set("security_status", "armed")
Проверка
if obj.get("security_status") == "armed" then
print("Объект на охране.")
else
print("Объект не на охране.")
end
if obj.get("security_status") == "armed" then
print("Объект на охране.")
else
print("Объект не на охране.")
end
Пример работы с астротаймером
Астротаймером называется обычный таймер, имеющий привязку к циклам захода\восхода солнца. Так как на разной широте время захода и восхода отличается, то в таких таймерах присутствует установка долготы/широты. Параметры долготы/широты задаются через Web на вкладке Settings->Location
Астротаймер вызывается скриптом OneMinTimer.lua
каждую минуту:
local sunrise_add_min <const> = 15
local sunrise_hour, sunrise_min = os.sunrise()
sunrise_min = sunrise_min + sunrise_add_min
if sunrise_min > 59 then
sunrise_hour = sunrise_hour + 1
sunrise_min = sunrise_min - 60
end
if Event.Time.hour == sunrise_hour and Event.Time.min == sunrise_min then
print(sunrise_hour .. ":" .. sunrise_min)
end
local sunrise_add_min <const> = 15
local sunrise_hour, sunrise_min = os.sunrise()
sunrise_min = sunrise_min + sunrise_add_min
if sunrise_min > 59 then
sunrise_hour = sunrise_hour + 1
sunrise_min = sunrise_min - 60
end
if Event.Time.hour == sunrise_hour and Event.Time.min == sunrise_min then
print(sunrise_hour .. ":" .. sunrise_min)
end
Данный скрипт напечатает время рассвета, через 15 минут после наступления, т.е. если 8:55 наступает рассвет, добавляем 15 минут, то скрипт сработает в 9:10. Можно задавать не более 60 минут.
Примеры использования астротаймера
local sunset_add_min <const> = 20
local sunset_hour, sunset_min = os.sunset()
sunset_min = sunset_min + sunset_add_min
if sunset_min > 59 then
sunset_hour = sunset_hour + 1
sunset_min = sunset_min - 60
end
if Event.Time.hour == sunset_hour and Event.Time.min == sunset_min then
-- Включает уличный свет через 20 минут после заката
telegram.send("Включено уличное освещение")
http.request("http://192.168.2.200:8888/objects/?object=MegaD3-8&op=m&m=extended")
end
local sunset_add_min <const> = 20
local sunset_hour, sunset_min = os.sunset()
sunset_min = sunset_min + sunset_add_min
if sunset_min > 59 then
sunset_hour = sunset_hour + 1
sunset_min = sunset_min - 60
end
if Event.Time.hour == sunset_hour and Event.Time.min == sunset_min then
-- Включает уличный свет через 20 минут после заката
telegram.send("Включено уличное освещение")
http.request("http://192.168.2.200:8888/objects/?object=MegaD3-8&op=m&m=extended")
end
local sunrise_add_min <const> = 1
local sunrise_hour, sunrise_min = os.sunrise()
sunrise_min = sunrise_min + sunrise_add_min
if sunrise_min > 59 then
sunrise_hour = sunrise_hour + 1
sunrise_min = sunrise_min - 60
end
if Event.Time.hour == sunrise_hour and Event.Time.min == sunrise_min then
-- Открывает шторы после рассвета
telegram.send("Шторы в гостиной открыты")
zigbee.set("0x5C0272FFFEC8A21B", "position", 0)
end
local sunrise_add_min <const> = 1
local sunrise_hour, sunrise_min = os.sunrise()
sunrise_min = sunrise_min + sunrise_add_min
if sunrise_min > 59 then
sunrise_hour = sunrise_hour + 1
sunrise_min = sunrise_min - 60
end
if Event.Time.hour == sunrise_hour and Event.Time.min == sunrise_min then
-- Открывает шторы после рассвета
telegram.send("Шторы в гостиной открыты")
zigbee.set("0x5C0272FFFEC8A21B", "position", 0)
end
Определение времени суток (светлое или темное)
sunrise_h, sunrise_m = os.sunrise()
sunset_h, sunset_m = os.sunset()
sunshine = (Event.Time.hour*60+Event.Time.min)>(sunrise_h*60+sunrise_m) and (Event.Time.hour*60+Event.Time.min)<(sunset_h*60+sunset_m)
-- sunshine - булева переменная, показывает время суток, дневное или вечернее.
sunrise_h, sunrise_m = os.sunrise()
sunset_h, sunset_m = os.sunset()
sunshine = (Event.Time.hour*60+Event.Time.min)>(sunrise_h*60+sunrise_m) and (Event.Time.hour*60+Event.Time.min)<(sunset_h*60+sunset_m)
-- sunshine - булева переменная, показывает время суток, дневное или вечернее.
Включение звука дверного звонка по событию (звуковой файл лежит в открытой сети)
192.168.1.5 - адрес другого шлюза. Нельзя запускать на самом себе таким образом, используйте объект audio.
http.request("http://192.168.1.5/audio?action=setvolume&value=100")
http.request("http://192.168.1.5/audio?action=play&url=http://funny-dog.surge.sh/door_bell.mp3")
http.request("http://192.168.1.5/audio?action=setvolume&value=100")
http.request("http://192.168.1.5/audio?action=play&url=http://funny-dog.surge.sh/door_bell.mp3")
Воспроизведение звука при нажатии кнопки (звонок)
--zvonok.lua скрипт ставим на датчик открытия двери если кнопка ON меняем на Single (одиночное нажатие)
if Event.State.Value == "ON" then
audio.setvolume(100)
audio.playurl("http://funny-dog.surge.sh/door_bell.mp3")
end
--zvonok.lua скрипт ставим на датчик открытия двери если кнопка ON меняем на Single (одиночное нажатие)
if Event.State.Value == "ON" then
audio.setvolume(100)
audio.playurl("http://funny-dog.surge.sh/door_bell.mp3")
end
Управляем открытием/закрытием привода штор Tuya с помощью zigbee кнопки WXKG01LM
Создаем сценарий curtian.lua:
local str = Event.Param
local p = {}
for x in string.gmatch(str,'([^:]+)') do
table.insert(p, x)
end
local remoteieee = p[1] -- ieee адрес привода для штор
local minlevel = p[2] --зададим минимальный уровень
local maxlevel = p[3] --зададим максимальный уровень
local btn=zigbee.value(tostring(Event.ieeeAddr), "action")
if (btn == "single") then --при однократном нажатии переключим шторы в противоположный режим
zigbee.get(remoteieee, "running")
local running = zigbee.value(remoteieee, "running")
if (running == true) then
zigbee.set(remoteieee, "state", "STOP")
else
local position = zigbee.value(remoteieee, "position")
if (tonumber(position)<=tonumber(maxlevel)-10) then
zigbee.set(remoteieee, "position", maxlevel)
else
zigbee.set(remoteieee, "position", minlevel)
end
end
end
if (btn=="double") then --при двукратном нажатии откроем шторы
zigbee.set(remoteieee, "position", maxlevel)
end
if (btn=="triple") then --при трехкратном нажатии закроем шторы
zigbee.set(remoteieee, "position", minlevel)
end
if (btn=="long_release") then --при длительном нажатии остановим привод
zigbee.set(remoteieee, "state", "STOP")
end
local str = Event.Param
local p = {}
for x in string.gmatch(str,'([^:]+)') do
table.insert(p, x)
end
local remoteieee = p[1] -- ieee адрес привода для штор
local minlevel = p[2] --зададим минимальный уровень
local maxlevel = p[3] --зададим максимальный уровень
local btn=zigbee.value(tostring(Event.ieeeAddr), "action")
if (btn == "single") then --при однократном нажатии переключим шторы в противоположный режим
zigbee.get(remoteieee, "running")
local running = zigbee.value(remoteieee, "running")
if (running == true) then
zigbee.set(remoteieee, "state", "STOP")
else
local position = zigbee.value(remoteieee, "position")
if (tonumber(position)<=tonumber(maxlevel)-10) then
zigbee.set(remoteieee, "position", maxlevel)
else
zigbee.set(remoteieee, "position", minlevel)
end
end
end
if (btn=="double") then --при двукратном нажатии откроем шторы
zigbee.set(remoteieee, "position", maxlevel)
end
if (btn=="triple") then --при трехкратном нажатии закроем шторы
zigbee.set(remoteieee, "position", minlevel)
end
if (btn=="long_release") then --при длительном нажатии остановим привод
zigbee.set(remoteieee, "state", "STOP")
end
В разделе SB выключателя WXKG01LM в метрике action прописываем вызов сценария curtain.lua, ieee адрес привода Tuya, значение position при открытии и значение при закрытии.
curtain.lua,0x5C0272FFFECAAC69:0:75
curtain.lua,0x5C0272FFFECAAC69:0:75
Теперь при однократном нажатии кнопки осуществляется переключение в противоположный режим, при двукратном - открытие, трёхкратном - закрытие.
Периодическое включение/отключение циркуляционного насоса по таймеру
onemintimer.lua:
--включаем циркуляцию ГВС каждые 10 минут
if (Event.Time.min == 0) or (Event.Time.min == 20) or (Event.Time.min == 40) then
zigbee.set("0x00124B001EC823EC", "state_l1", "OFF")
telegram.send("Циркуляция ГВС выключена")
end
if (Event.Time.min == 10) or (Event.Time.min == 30) or (Event.Time.min == 50) then
zigbee.set("0x00124B001EC823EC", "state_l1", "ON")
telegram.send("Циркуляция ГВС включена") end
--включаем циркуляцию ГВС каждые 10 минут
if (Event.Time.min == 0) or (Event.Time.min == 20) or (Event.Time.min == 40) then
zigbee.set("0x00124B001EC823EC", "state_l1", "OFF")
telegram.send("Циркуляция ГВС выключена")
end
if (Event.Time.min == 10) or (Event.Time.min == 30) or (Event.Time.min == 50) then
zigbee.set("0x00124B001EC823EC", "state_l1", "ON")
telegram.send("Циркуляция ГВС включена") end
Управление адресными светодиодами, подключенными к контроллеру WLED
WLED поддерживает множество вариантов управления, в том числе mqtt. Ниже собраны примеры кода на lua для управления через mqtt.
Управление и переключение режимов можно легко "повесить" на zigbee-кнопку, поддерживающие многократные нажатия.
Включение, переключение режима
mqtt.pub('wled/f6dafd', 'toggle')
mqtt.pub('wled/f6dafd', 'on')
mqtt.pub('wled/f6dafd', 'off')
mqtt.pub('wled/f6dafd', 'toggle')
mqtt.pub('wled/f6dafd', 'on')
mqtt.pub('wled/f6dafd', 'off')
Установка заданного цвета
mqtt.pub('wled/f6dafd/col', '#36A615DD')
mqtt.pub('wled/f6dafd/col', '#36A615DD')
Установка произвольного цвета
mqtt.pub('wled/f6dafd/col', '#'..math.random(0,16777215))
mqtt.pub('wled/f6dafd/col', '#'..math.random(0,16777215))
Установка произвольного эффекта и отключение эффектов
mqtt.pub('wled/f6dafd/api', 'win&A=128&FX='..math.random(0, 50)) -- установка произвольного эффекта
mqtt.pub('wled/f6dafd/api', 'win&A=128&FX=0') -- отключение эффектов
mqtt.pub('wled/f6dafd/api', 'win&A=128&FX='..math.random(0, 50)) -- установка произвольного эффекта
mqtt.pub('wled/f6dafd/api', 'win&A=128&FX=0') -- отключение эффектов
Оповещение в telegram о сработке датчика протечки
local state = zigbee.value(tostring(Event.ieeeAddr), "water_leak")
if (state) then
telegram.send("Внимание!!! Сработал датчик протечки " .. Event.FriendlyName)
zigbee.set("0x000D6F001314C316", "warning", 2)
else
telegram.send("Протечка на датчике " .. Event.FriendlyName .. " устранена")
end
local state = zigbee.value(tostring(Event.ieeeAddr), "water_leak")
if (state) then
telegram.send("Внимание!!! Сработал датчик протечки " .. Event.FriendlyName)
zigbee.set("0x000D6F001314C316", "warning", 2)
else
telegram.send("Протечка на датчике " .. Event.FriendlyName .. " устранена")
end
Обработка двойного, тройного и тд нажатия на выключателях, которые не поддерживают такие режимы
Данный сценарий тестировался для выключателей, которые подключены к 8-ми канальному реле modkam и привода для штор от Aqara. При первом нажатии создается таймер на 3 секунды, который инициирует действия.
callback.lua (привязывается в интерфейсе к каналу, который будем считать)
function search_value (tbl, val)
for i = 1, #tbl do
if tbl[i][1] == val then
return i
end
end
return nil
end
if (Event.State.Value ~= Event.State.OldValue) then
local ar = {
{"0x00124B001EC84F3C.state_l8","0x00158D0002EE1285", 'cover'}, --спальня
{"0x00124B001F7CA144.state_l2","0x50325FFFFEA65978", 'cover'}, --Анюта
{"0x00124B001F7CA144.state_l8","0x50325FFFFEA457C4", 'cover'}, --Софа
{"0x00124B001EC80F20.state_l7","0x5C0272FFFECAAC69", 'cover'}, --Гостиная
{"0x00124B001EC84F3C.state_l7","hello",'telega'}}
myevent = Event.ieeeAddr .. "." .. Event.State.Name
remotedev = ar[search_value(ar, myevent)][2]
remotetype =ar[search_value(ar, myevent)][3]
obj.setType(remotedev .. "_cnt", "INT")
obj.setType(remotedev .. "_timer", "BOOL")
obj.setShare(remotedev .. "_cnt", true)
obj.setShare(remotedev .. "_timer", true)
timer=obj.get(remotedev .. "_timer")
obj.set(remotedev .."_cnt", obj.get(remotedev .. "_cnt") + 1)
--проверяем, если скрипт был запущен давно и не сбросился
curr, prev = obj.getTime(remotedev.. "_timer")
if (timer == true and os.time() - curr > 60) then
obj.set(remotedev .. "_timer", false)
obj.set(remotedev .. "_cnt" , 0)
end
--запускам таймер сброса на 3 сек
if (timer == false) then
scripts.setTimer("clear_cnt", os.time() + 3,remotedev)
obj.set(remotedev .. "_timer",true)
end
end
function search_value (tbl, val)
for i = 1, #tbl do
if tbl[i][1] == val then
return i
end
end
return nil
end
if (Event.State.Value ~= Event.State.OldValue) then
local ar = {
{"0x00124B001EC84F3C.state_l8","0x00158D0002EE1285", 'cover'}, --спальня
{"0x00124B001F7CA144.state_l2","0x50325FFFFEA65978", 'cover'}, --Анюта
{"0x00124B001F7CA144.state_l8","0x50325FFFFEA457C4", 'cover'}, --Софа
{"0x00124B001EC80F20.state_l7","0x5C0272FFFECAAC69", 'cover'}, --Гостиная
{"0x00124B001EC84F3C.state_l7","hello",'telega'}}
myevent = Event.ieeeAddr .. "." .. Event.State.Name
remotedev = ar[search_value(ar, myevent)][2]
remotetype =ar[search_value(ar, myevent)][3]
obj.setType(remotedev .. "_cnt", "INT")
obj.setType(remotedev .. "_timer", "BOOL")
obj.setShare(remotedev .. "_cnt", true)
obj.setShare(remotedev .. "_timer", true)
timer=obj.get(remotedev .. "_timer")
obj.set(remotedev .."_cnt", obj.get(remotedev .. "_cnt") + 1)
--проверяем, если скрипт был запущен давно и не сбросился
curr, prev = obj.getTime(remotedev.. "_timer")
if (timer == true and os.time() - curr > 60) then
obj.set(remotedev .. "_timer", false)
obj.set(remotedev .. "_cnt" , 0)
end
--запускам таймер сброса на 3 сек
if (timer == false) then
scripts.setTimer("clear_cnt", os.time() + 3,remotedev)
obj.set(remotedev .. "_timer",true)
end
end
Сценарий, который выполняет сами действия clear_cnt.lua
remotedev = Event.Param
val = obj.get(remotedev .. "_cnt")
if (val > 1) then
obj.set(remotedev .. "_cnt" , 0)
obj.set(remotedev .. "_timer", false)
--telegram.send(val..", счетчик сброшен,"..remotedev)
scripts.setTimer("clear_cnt", 0)
end
if (val == 4) then
-- telegram.send("val:"..val)
position=zigbee.value(remotedev, "position")
-- telegram.send("position:"..position)
if (position > 6) then
-- telegram.send("закрываю шторы")
zigbee.set(remotedev, "position", 0)
else
-- telegram.send("открываю шторы")
zigbee.set(remotedev, "position", 100)
end
end
remotedev = Event.Param
val = obj.get(remotedev .. "_cnt")
if (val > 1) then
obj.set(remotedev .. "_cnt" , 0)
obj.set(remotedev .. "_timer", false)
--telegram.send(val..", счетчик сброшен,"..remotedev)
scripts.setTimer("clear_cnt", 0)
end
if (val == 4) then
-- telegram.send("val:"..val)
position=zigbee.value(remotedev, "position")
-- telegram.send("position:"..position)
if (position > 6) then
-- telegram.send("закрываю шторы")
zigbee.set(remotedev, "position", 0)
else
-- telegram.send("открываю шторы")
zigbee.set(remotedev, "position", 100)
end
end
Отключение света через 15 минут после включения
Данный сценарий тестировался для выключателей, которые подключены к 8-ми канальному реле modkam. Сценарий удобно применять в помещениях, где пребывание обычно недолгое, например гардеробная комната, прихожая и т.д., где дети всегда часто забывают выключать свет. На всякий случай предусмотрим передачу параметров (если тригером будет не сам объект), для этого привяжем к управляемой линии вызов сценария toggle_timer
Сценарий toggle_timer.lua:
local p = {}
local waittime = 900
for x in string.gmatch(Event.Param ,'([^:]+)') do
table.insert(p, x)
end
local ieee = p[1]
local parname = p[2]
local state = zigbee.value(ieee, parname)
local timer = obj.get(ieee .. "_" .. parname .. "_timer")
local curr, prev = obj.getTime(ieee .. "_" .. parname .. "_timer")
obj.setType(ieee .. "_" .. parname .. "_timer", "BOOL")
obj.setShare(ieee .. "_" .. parname .. "_timer", true)
--сброс таймера, если по какойто причине таймер просрочен
if (state == "ON" and timer == true and os.time() - curr > waittime + 10) then
obj.set(ieee .. "_" .. parname .. "_timer", false)
end
--запускам таймер выключения
if (state == "ON" and timer == false) then
scripts.setTimer("toggle_timer2", os.time() + waittime, ieee .. ":" .. parname)
obj.set(ieee .. "_" .. parname .. "_timer", true)
end
local p = {}
local waittime = 900
for x in string.gmatch(Event.Param ,'([^:]+)') do
table.insert(p, x)
end
local ieee = p[1]
local parname = p[2]
local state = zigbee.value(ieee, parname)
local timer = obj.get(ieee .. "_" .. parname .. "_timer")
local curr, prev = obj.getTime(ieee .. "_" .. parname .. "_timer")
obj.setType(ieee .. "_" .. parname .. "_timer", "BOOL")
obj.setShare(ieee .. "_" .. parname .. "_timer", true)
--сброс таймера, если по какойто причине таймер просрочен
if (state == "ON" and timer == true and os.time() - curr > waittime + 10) then
obj.set(ieee .. "_" .. parname .. "_timer", false)
end
--запускам таймер выключения
if (state == "ON" and timer == false) then
scripts.setTimer("toggle_timer2", os.time() + waittime, ieee .. ":" .. parname)
obj.set(ieee .. "_" .. parname .. "_timer", true)
end
сценарий, который будет вызываться по таймеру (выключение света) toggle_timer2.lua:
local p = explode(":", Event.Param)
local ieee = p[1]
local parname = p[2]
zigbee.set(ieee, parname, "OFF")
obj.set(ieee.. "_" .. parname .. "_timer", false)
--telegram.send(ieee.."."..parname.." выключен по таймеру")
scripts.setTimer("toggle_timer2", 0)
local p = explode(":", Event.Param)
local ieee = p[1]
local parname = p[2]
zigbee.set(ieee, parname, "OFF")
obj.set(ieee.. "_" .. parname .. "_timer", false)
--telegram.send(ieee.."."..parname.." выключен по таймеру")
scripts.setTimer("toggle_timer2", 0)
Отправка показаний счетчиков в управляющую компанию
Здесь описан способ отправки показаний в УК, не имеющей API для этого
Контроль присутствия людей на основе сетевых устройств
Контроль регистрации устройств в сети роутеров Keenetic
Статья пользователя Алексей Цуркан
Контроль устройств посредством команды ping роутеров Mikrotik
Статья пользователя Alexander Posazhennikov
Автоматизации в умном доме 2. SLS, MQTT, Mikrotik
Контроль устройств в сети роутеров Mikrotik на базе DHCP
Решение пользователя Nekto Ivanov
. Ищите его в основной группе Telegram. Контакт у него засекречен)
Решение позволяет контролировать регистрацию устройств на DHCP сервере роутера Mikrotik. RouterOS позволяет вызывать скрипт при регистрации и при удалении регистрации вызывать скрипт, который передаст данный об отключенном или подключенном устройстве в SLS посредством HTTP API. Скрипт:
:if ($leaseBound = 1) do={
/tool fetch url="http://192.168.0.2/api/scripts?action=evalFile&path=presense.lua¶m=Online+$leaseActIP+$leaseActMAC" keep-result=no
} else={
/tool fetch url="http://192.168.0.2/api/scripts?action=evalFile&path=presense.lua¶m=Offline+$leaseActIP+$leaseActMAC" keep-result=no
}
:if ($leaseBound = 1) do={
/tool fetch url="http://192.168.0.2/api/scripts?action=evalFile&path=presense.lua¶m=Online+$leaseActIP+$leaseActMAC" keep-result=no
} else={
/tool fetch url="http://192.168.0.2/api/scripts?action=evalFile&path=presense.lua¶m=Offline+$leaseActIP+$leaseActMAC" keep-result=no
}
необходимо вставить в окно Lease Script в свойствах DHCP сервера Mikrotik. Таким образом, при каждой регистрации и её удалении в SLS будет вызываться скрипт presense.lua
, в который будет передан параметр вида
Online+IP+MAC
при подключении устройстваOffline+IP+MAC
при отключении устройства
Внутри скрипта LUA этот параметр можно принять посредством переменной события Event.Param
и обработать по своему усмотрению. Например отправить в Telegram:
telegram.send(Event.Param)
telegram.send(Event.Param)
Для того чтобы в SLS прилетали регистрации только нужных устройство можно добавить их выборку посредством регулярного выражения. Например, так мы выделим IP адреса из диапазона 10-19:
^192\\.168\\.0\\.[1].\$
^192\\.168\\.0\\.[1].\$
:if ($leaseActIP~"^192\\.168\\.0\\.[1].\$") do={
:if ($leaseBound = 1) do={
/tool fetch url="http://192.168.0.2/api/scripts?action=evalFile&path=presense.lua¶m=Online+$leaseActIP+$leaseActMAC" keep-result=no
} else={
/tool fetch url="http://192.168.0.2/api/scripts?action=evalFile&path=presense.lua¶m=Offline+$leaseActIP+$leaseActMAC" keep-result=no
}
}
:if ($leaseActIP~"^192\\.168\\.0\\.[1].\$") do={
:if ($leaseBound = 1) do={
/tool fetch url="http://192.168.0.2/api/scripts?action=evalFile&path=presense.lua¶m=Online+$leaseActIP+$leaseActMAC" keep-result=no
} else={
/tool fetch url="http://192.168.0.2/api/scripts?action=evalFile&path=presense.lua¶m=Offline+$leaseActIP+$leaseActMAC" keep-result=no
}
}
Следует отметить, что событие регистрации возникает сразу при подключении, а событие удаления регистрации в пределах времени TTL записи DHCP (10 мин). Для "важных" устройств это время можно уменьшить. Для этого нужно открыть запись аренды (Lease), сделать её статической (Make static), закрыть/открыть и тогда появится возможность для этой записи установить TTL отличный от заданного на уровне сервера:
При этом, устройство с данным MAC адресом, будет всегда получать зафиксированный IP адрес.
Также, замечено, что некоторые устройства могут некорректно продлевать аренду адреса. При этом могут возникать ложные срабатывания скрипта. В таком случае воспользуйтесь решением выше.
Вариант функций для автоматизаций SimpleBind
Статья пользователя Сергей Кушеев
SLS шлюз. Автоматизация. Пишем управление устройствами.
Сохранение значений в json через lua
Пример сценария для записи значений в локальное хранилище (int или sd), сценарий сохраняет файл с именем файла, равным дате. В виду того, что для преобразования записанного файла в json используется память SLS, не рекомендуется запускать часто. В случае переполнения памяти, запись готового json не будет выполнена. Пример отображения графиков через ui.html.
local new_ust, prev_ust = obj.get('thermo.boiler.target_temperature') --получение текущего значения уставки
local ul_ot, prev_ul_ot = obj.get('thermo.boiler.temperature_outside')--получение уличной темпетуры с котла по ОТ
local new_ds18, prev_ds18 = obj.get('1w.28-96A907D6013C/temperature') --получение значения датчика температуры
local ul_bt, prev_bt = obj.get('thermo.boiler.temperature')--получение температуры теплоносителя (отопления)
local new_dhwt, prev_dhwt = obj.get('thermo.dhw.temperature') --получение температуры бойлера
local dhwst, prev_dhwst = obj.get('thermo.dhw.status') --нагрев воды
local flame, prev_flame = obj.get('thermo.boiler.flame') --нагрев отопления
local avr_temp, avr_temp = obj.get('average_temp') --средняя температура в доме
if (flame=="true") then flame_status=100 else flame_status=0 end --переназнчаем, так как почему-то значения хранятся в STRING
if (dhwst=="true") then dhwst_status=100 else dhwst_status=0 end --переназнчаем, так как почему-то значения хранятся в STRING
local cdate=string.format("%02d", Event.Time.day).."/"..string.format("%02d", Event.Time.month).."/"..Event.Time.year --приводим дату в нужный формат
local ctime=string.format("%02d", Event.Time.hour)..":"..string.format("%02d", Event.Time.min)..":"..string.format("%02d", Event.Time.sec) --приводим время в нужный формат
local ctimesh=string.format("%02d", Event.Time.hour)..":"..string.format("%02d", Event.Time.min) --приводим время в краткий формат
--local storage='int' --для записи во внутренню память
local storage='sd' --для записи на карту памяти
local fn="/"..storage.."/!log_"..string.gsub(cdate, '/', '_')..".txt"
local fnjs="/"..storage.."/!log_"..string.gsub(cdate, '/', '_')..".json"
os.fileWrite(fn,'{"new_ust":'..new_ust..',"ul_ot":'.. ul_ot.. ',"new_ds18":'..new_ds18..',"ul_bt":'..ul_bt..',"new_dhwt":'.. new_dhwt .. ',"unixtime":'..os.time()..
',"datetime":"'..cdate.." "..ctime..'","dhwt_status":'.. dhwst_status..',"flame_status":'.. flame_status..',"average_temp":'.. avr_temp..',"ctimesh":"'.. ctimesh.. '"},\n',true)
value = os.fileRead(fn)
local js='{"temp":['..value..']}'
js=string.gsub(js, ',\n]}', '\n]}')
os.fileWrite(fnjs,js)
print("Список файлов доступен тут http://"..net.localIP().."/api/storage?path=/"..storage.."/")
local free=http.request2("http://"..net.localIP().."/api/storage/info")
print("http://"..net.localIP().."/api/storage?path="..fnjs)
local new_ust, prev_ust = obj.get('thermo.boiler.target_temperature') --получение текущего значения уставки
local ul_ot, prev_ul_ot = obj.get('thermo.boiler.temperature_outside')--получение уличной темпетуры с котла по ОТ
local new_ds18, prev_ds18 = obj.get('1w.28-96A907D6013C/temperature') --получение значения датчика температуры
local ul_bt, prev_bt = obj.get('thermo.boiler.temperature')--получение температуры теплоносителя (отопления)
local new_dhwt, prev_dhwt = obj.get('thermo.dhw.temperature') --получение температуры бойлера
local dhwst, prev_dhwst = obj.get('thermo.dhw.status') --нагрев воды
local flame, prev_flame = obj.get('thermo.boiler.flame') --нагрев отопления
local avr_temp, avr_temp = obj.get('average_temp') --средняя температура в доме
if (flame=="true") then flame_status=100 else flame_status=0 end --переназнчаем, так как почему-то значения хранятся в STRING
if (dhwst=="true") then dhwst_status=100 else dhwst_status=0 end --переназнчаем, так как почему-то значения хранятся в STRING
local cdate=string.format("%02d", Event.Time.day).."/"..string.format("%02d", Event.Time.month).."/"..Event.Time.year --приводим дату в нужный формат
local ctime=string.format("%02d", Event.Time.hour)..":"..string.format("%02d", Event.Time.min)..":"..string.format("%02d", Event.Time.sec) --приводим время в нужный формат
local ctimesh=string.format("%02d", Event.Time.hour)..":"..string.format("%02d", Event.Time.min) --приводим время в краткий формат
--local storage='int' --для записи во внутренню память
local storage='sd' --для записи на карту памяти
local fn="/"..storage.."/!log_"..string.gsub(cdate, '/', '_')..".txt"
local fnjs="/"..storage.."/!log_"..string.gsub(cdate, '/', '_')..".json"
os.fileWrite(fn,'{"new_ust":'..new_ust..',"ul_ot":'.. ul_ot.. ',"new_ds18":'..new_ds18..',"ul_bt":'..ul_bt..',"new_dhwt":'.. new_dhwt .. ',"unixtime":'..os.time()..
',"datetime":"'..cdate.." "..ctime..'","dhwt_status":'.. dhwst_status..',"flame_status":'.. flame_status..',"average_temp":'.. avr_temp..',"ctimesh":"'.. ctimesh.. '"},\n',true)
value = os.fileRead(fn)
local js='{"temp":['..value..']}'
js=string.gsub(js, ',\n]}', '\n]}')
os.fileWrite(fnjs,js)
print("Список файлов доступен тут http://"..net.localIP().."/api/storage?path=/"..storage.."/")
local free=http.request2("http://"..net.localIP().."/api/storage/info")
print("http://"..net.localIP().."/api/storage?path="..fnjs)
PS. Документ в разработке