О скриптовом языке программирования Lua.
Самовар поддерживает автоматизацию на основе скриптового языка программирования Lua. Редактор скриптов доступен на странице Настроек – Редактор. Логин и пароль - admin.
Текущая версия Lua 5.4.4
При запуске Самовара выполняется файл init.lua. Его назначение – включить/выключить секундный цикл выполнения скриптов, а также проинициализировать переменные, которые будут использоваться в других скриптах.
Если включен запуск скриптов в цикле, каждую секунду запускается два скрипта: сначала - script.lua, после него скрипт с именем, которое определяется в зависимости от режима работы: beer.lua (Пиво), bk.lua (Бражная колонна), dist.lua (Дистилляция), rectificat.lua (Ректификация). Так же их можно запустить разово, обратившись по адресу http://samovar.local/lua. Если до следующего запуска скрипт не успеет выполниться, продолжится выполнение текущего скрипта.
Так же есть возможность добавить кнопки в интерфейс для запуска нескольких файлов: btn_button1.lua, btn_button2.lua, btn_button3.lua, btn_button4.lua, btn_button5.lua. При наличии этих файлов в интерфейсе на вкладке "Дополнительно" будут создаваться кнопки LUA1, LUA2, etc.
Обратите внимание! Нумерация кнопок идет по порядку, то есть, если будут созданы файлы btn_button2.lua, btn_button5.lua, в интерфейсе будут созданы две кнопки: LUA1, LUA2.
У скриптов, выполняющихся в этих файлах, есть ряд ограничений: они не должны выполняться дольше секунды и не могут выполняться одновременно. Основное их назначение - запустить выполнение скриптов в цикле (например, установив значение переменной, которое потом можно считать в скрипте, выполняющемся в цикле), или включить/выключить управляющее устройство (например, насос).
Таким образом, архитектура использования кнопок выглядит следующим образом (как пример - для режима дистилляции):
1. Главный управляемый цикл: раз в секунду script.lua => dist.lua => script.lua => dist.lua =>...
(управляемый в том смысле, его можно запустить/остановить программно из любого скрипта через глобальную переменную)
2. Скрипт scrit.lua - единый для всех режимов, сюда можно поместить код, который должен выполняться при любом режиме (ректификация, пиво, су-вид и т.д.)
3. Скрипт dist.lua - будет использован только в режиме дистилляции, в него можно поместить всю логику, которая должна выполняться раз в секунду в зависимости от параметров, которые этот скрипт получает из глобальных переменных Самовара, например, getNumVariable("TankTemp") или переменных, сохранённых любым скриптом в общем пространстве имён, например, getObject("StartTankFilling"). То есть в коде этого скрипта, например, можно поместить условие:
if (StartTankFilling == "true" and TankFillingPercent < 80) then StartPump() else StopPump() end
и каждую секунду скрипт будет проверять, нет ли флага необходимости наполнить куб, а если есть - не заполнен ли он уже на 80%, и не нужно ли ранее запущенный насос уже остановить.
4. Скрипт кнопки btn_button1.lua, который, при нажатии кнопки, и установит флаг необходимости наполнить куб через setObject("StartTankFilling", "true"). При следующем цикле через секунду скрипт dist.lua прочтёт этот флаг и включит насос (если куб ещё не наполнен). Таким образом, все скрипты имеют общее пространство имён, доступное через setObject/getObject, что даёт им возможность обмениваться данными.
5. Скрипт кнопки btn_button2.lua, который, при нажатии кнопки, может остановить выполнение главного управляемого цикла через setNumVariable("loop_lua_fl", 0), например, если что-то пошло не так со скриптами.
Из скриптов можно получить доступ к внутренним переменным Самовара (часть из них менять нельзя, они доступны только на чтение), а также вызывать функции Самовара.
pinMode(pin, mode) – аналогично одноименной функции Arduino, устанавливает режим работы заданного входа/выхода(pin) как входа или как выхода. Изменение режима доступно только для этих портов: RELE_CHANNEL1, RELE_CHANNEL4, RELE_CHANNEL3, RELE_CHANNEL2 (описание пинов можно взять тут). Обратите внимание – здесь и далее нужно передавать их числовое значение. То есть, если нужно установить порт RELE_CHANNEL4 как вход – надо вызвать функцию pinMode(13, 1), как выход - pinMode(13, 0)
digitalWrite(pin, Value) – аналогично одноименной функции Arduino, подает HIGH или LOW значение на цифровой вход/выход (pin). То есть, если нужно установить на выходе RELE_CHANNEL4 высокое значение, надо вызвать digitalWrite(13, 1)
digitalRead(pin) – аналогично одноименной функции Arduino, считывает значение с заданного входа - HIGH или LOW. То есть, если нужно прочитать установленное на входе или выходе RELE_CHANNEL4 значение, надо вызвать digitalRead (13)
analogRead(pin) – аналогично одноименной функции Arduino, считывает значение с аналогового входа. Напряжение, поданное на аналоговый вход, будет преобразовано в значение от 0 до 4095. ВНИМАНИЕ! Подача напряжения на вход больше, чем 3.3 вольта может привести к выходу порта из строя, или всей ESP32. На данный момент эта функция работает только с портом LUA_PIN
exp_pinMode(pin) – аналогично pinMode(pin), но для управления расширителем портов PCF8575, pin – номер порта расширителя. Все порты расширителя доступны для выбора типа – чтение или вывод
exp_digitalWrite(pin, Value) – аналогично digitalWrite (pin, Value), но для управления расширителем портов PCF8575, pin – номер порта расширителя, Value 1 или 0. Все порты расширителя доступны для записи
exp_digitalRead(pin) – аналогично digitalRead (pin), но для управления расширителем портов PCF8575, pin – номер порта расширителя. Все порты расширителя доступны для чтения
exp_analogWrite(Value) – аналогично analogWrite (pin, Value), но для управления расширителем портов PCF8591, Value - значение от 0 до 255. У расширителя один порт, доступный для вывода.
exp_analogRead(pin) – аналогично analogRead (pin), но для управления расширителем портов PCF8591, pin – номер порта расширителя, доступны 4 порта.
delay(ms) – аналогично одноименной функции Arduino, останавливает выполнение программы на заданное в параметре количество миллисекунд (1000 миллисекунд в 1 секунде)
millis() – аналогично одноименной функции Arduino, Возвращает количество миллисекунд с момента начала работы Самовара
setTimer(Num, Sec) – установить таймер номер Num на Sec секунд. Доступно 10 таймеров с 1 по 10. То есть одновременно скрипты могут работать не больше, чем с 10 таймерами
getTimer(Num) – получить оставшееся время по таймеру номер Num. Если таймер не установлен, или время закончилось, функция вернет 0
sendMsg(Msg, Level) – Если Level = -1, сообщение Msg будет выведено в com-port и в консоль браузера, удобно для отладки. Если Level 0,1,2 - сообщение отправляется в консоль.
setPower(Power) – включает/выключает Самовар. setPower(0) – выключит, setPower(1) – включит
setCurrentPower(Value) – установить значение Value на регуляторе. Если используется регулятор с управленем по мощности, то тогда Value – это мощность, которую нужно установить, иначе - напряжение
setBodyTemp() – установить температуру тела в процессе ректификации. Работать будет только в режиме ректификации. В других режимах будет выводить сообщение в консоль о невозможности установить температуру тела
setMixer(Val) – включить/выключить мешалку. setMixer(0) – выключить, setMixer(1) – включить
openValve(Val) – открыть/закрыть клапан воды. openValve(0) – закрыть, openValve(1) – открыть
setAlarm() – установить режим тревоги. Самовар выключит питание, закроет клапан воды и отключит насос воды
setNextProgram() – перейти на следующую программу. Аналогично нажатию на кнопку в интерфейсе - Следующая программа
setPauseWithdrawal(Val) – поставить/снять отбор на паузу. setPauseWithdrawal(0) – снять с паузы, setPauseWithdrawal(1) – поставить на паузу
getState() – получить статус Самовара (число), удобно для определения, в каком статусе находится Самовар
setNumVariable("Variable", Val) – установить внутреннюю числовую переменную Самовара. Не все переменные доступны для установки значений. setNumVariable("TankTemp", 85) – установит температуру куба равной 85 градусам. Внимание! Если не понимаете, как работает Самовар, эту функцию лучше не использовать, так как потенциально можно нарушить работу Самовара
setStrVariable("Variable", Val) – установить внутреннюю строковую переменную Самовара. Не все переменные доступны для установки значений. setStrVariable("SamovarStatus", "Тестовый статус Самовара")
getNumVariable("Variable") – получить внутреннюю числовую переменную Самовара. TankTemp = getNumVariable("TankTemp") – присвоит переменной скрипта TankTemp значение температуры куба
getStrVariable("Variable") – получить внутреннюю строковую переменную Самовара
program_type = getStrVariable("program_type")– присвоит переменной скрипта program_type тип текущей выполняемой программы.
Переменные скрипта существуют только в момент выполнения скрипта. При следующем запуске их значения не сохранятся. Иногда бывает необходимо запомнить значение переменной в одном запуске скрипта и считать его в другом. Для этого есть две функции – setObject("Object",Val) и getObject("Object")/getObject("Object","NUMERIC"). Установленные значения переменных сохраняются до перезагрузки.
setLuaStatus(Status) - для отображения статуса работы скрипта в интерфейсе. Например, отслеживание выполнения скрипта:
i = getObject("cnt", "NUMERIC")
i = i + 1
setLuaStatus("Счетчик cnt = "..i)
setObject("cnt", i)
setObject("Object",Val) – запомнит объект Object со значением Val в памяти Самовара.
getObject("Object") – получит ранее сохраненное значение объекта Object. Если такой объект не был сохранен, вернется пустая строка. При попытке работать с пустой строкой как с числом, оно примет значение nil – не определено. Для того, чтобы было удобнее работать с числовыми значениями, и не проверять на nil, можно эту функцию вызвать с дополнительным параметром "NUMERIC", в этом случае, если объект еще был не инициализирован, вернется 0.
Пример работы с setObject/getObject:
n = 156
setObject("MyObject", n)
print (n)
n = n + 5
print (n)
n = getObject("MyObject")
print (n)
Если запустить этот скрипт, он в мониторе порта Arduino выведет
156
161
156
http_request(Url) – выполнить запрос по адресу Url. Например, можно отправить сообщение в Telegram. Функция поддерживается только в случае использования нового SDK. Так же можно отправить POST запрос:
http_request("http://test.com:80/post?foo1=bar1", "POST", "Content-Type: text/text; charset=utf-8\r\n", "body") для работы этого функционала необходимо отключить обновление по OTA
Пример скрипта, который отправит в чат Telegram температуру куба:
local char_to_hex = function(c)
return string.format("%%%02X", string.byte(c))
end
local function urlencode(url)
if url == nil then
return
end
url = url:gsub("\n", "\r\n")
url = url:gsub("([^%w ])", char_to_hex)
url = url:gsub(" ", "+")
return url
end
local hex_to_char = function(x)
return string.char(tonumber(x, 16))
end
function SendTelegram(text)
local token = "5177...:AAG0b...." --
local chat_id = "38806....."
http_request("http://212.237.16.93/bot" .. token .. "/sendMessage?chat_id=" .. chat_id .. "&text=" .. urlencode(text))
end
local text = "Текущая температура куба = ".. getNumVariable("TankTemp")
SendTelegram(text)
Пример скрипта, который получает значение от аналогового датчика уровня и управляем насосом воды (например, для перекачки браги в куб):
start_pump = getObject("start_pump", "NUMERIC") + 0 --получаем из ранее сохраненного объекта числовое значение и преобразуем в число
sensor = analogRead() --читаем аналоговое значение пина 34 (зарезервирован для lua)
--sensor = 1500
if sensor >= 1000 and sensor <= 2000 and start_pump == 0 then
setObject("start_pump", 1) --сохраняем значение в объекте в памяти Самовара, чтобы его можно было использовать в следующем цикле запуска скрипта
digitalWrite(4,1) --устанавливаем на 4 ноге высокий уровень
print("Start pump") --[=[пишем в com-port. Так-же можно использовать команду sendMsg("Msg", Level). Если Level = -1, сообщение будет выведено в com-port и в консоль браузера, удобно для отладки. Если Level 0,1,2 - сообщение отрпавляетя в консоль]=]
--sendMsg("Start pump",-1)
elseif sensor == 0 then
setObject("start_pump", 0) --сохраняем значение в объекте в памяти Самовара, чтобы его можно было использовать в следующем цикле запуска скрипта
if (start_pump == 1) then
digitalWrite(4,0) --устанавливаем на 4 ноге низкий уровень
print("Finish pump")
end
end
Список внутренних переменных, которые по умолчанию доступны в скрипте:
bme_pressure –текущее значение атмосферного давления
capacity_num – номер емкости, в которую идет отбор
SamovarStatusInt – статус работы Самовара
ProgramNum – текущий номер программы
ProgramLen – количество строк в программе
currentvolume – отобранный объем в текущей строке программы
ActualVolumePerHour – текущая скорость отбора в литрах
WthdrwlProgress - прогресс текущего отбора
PowerOn – признак включенного/выключенного нагрева. 0 – выключено, 1 - включено
PauseOn – признак паузы. 0 – нет, 1 – да
StepperMoving – признак работы перистальтического насоса. 0 – не работает, 1 – работает
program_Pause – признак запущенной программы паузы. 0 – нет, 1 – да
program_Wait – признак, что программа стоит на паузе. 0 – нет, 1 – да
program_Wait_Type – причина постановки на паузу – превышение по царге или пару. Значения "(пар)" или "(царга)"
WthdrwTimeAll – оставшееся время отбора
WthdrwTime – время отбора текущей строки программы
WthdrwTimeAllS – оставшееся время отбора строкой
WthdrwTimeS – время отбора текущей строки программы строкой
pump_started – статус работы насоса воды. 0 – нет, 1 – да
setautospeed – признак для однократного снижения скорости насоса при паузе. 0 – не снижать, 1 – снижать
heater_state – статус нагрева при затирке. 0 – не нагревается, 1 – нагревается
mixer_status – статус работы мешалки. 0 – не работает, 1 – работает
alarm_event – признак сработавшей кнопки тревоги. 0 – нет, 1 – да
acceleration_heater – признак включенного разгонного тэна. 0 – выключен, 1 – включен
valve_status – статус клапана подачи воды. 0 – закрыт, 1 – открыт
program_type – тип текущей программы (из описания программ ректификации и пива)
program_volume – объем отбора в мл
program_speed – скорость отбора в л/ч
program_temp – температура, при которой отбирается эта часть погона. 0 - определяется автоматически
program_power – напряжение/мощность, при которой отбирается эта часть погона
program_time – время, необходимое для работы этой строки программы
program_capacity_num – номер емкости для отбора
SamSetup_Mode – режим работы Самовара
test_num_val – числовая переменная для отладки
test_str_val – строковая переменная для отладки
SteamTemp – температура датчика пара
PipeTemp – температура датчика царги
WaterTemp – температура датчика воды
TankTemp – температура датчика куба
ACPTemp – температура датчика ТСА
current_power_mode – текущий режим работы регулятора
target_power_volt – заданное напряжение работы регулятора
wp_count
Переменные для управления скриптами:
loop_lua_fl – значения 0 или 1. Если 0 – не выполнять ежесекундный цикл скриптов, 1 – выполнять.
show_lua_script – значения 0 или 1. Если 0 – не показывать выполняемый скрипт в консоли и мониторе порта, 1 – показывать. Можно использоваться при отладке. Так же покажет значения всех переменных, установленных для этого скрипта.
Например, если в скрипте init.lua вызвать эти две функции, то ежесекундно будет запускаться два скрипта (script.lua и определяемый текущим режимом Самовара), и каждый скрипт будет выводиться в монитор порта и консоль браузера
setNumVariable("loop_lua_fl",1)
setNumVariable("show_lua_script",1)