Перейти к содержимому
Главная страница » Статьи » Поддержка lua скриптов

Поддержка lua скриптов

«Самовар» поддерживает автоматизацию на скриптовом языке Lua. Скрипты управляют внешним оборудованием (клапаны, насосы, мешалка, нагреватели, реле), читают показания датчиков и меняют логику процесса под конкретную установку. Базовый функционал контроллера при этом не меняется.

Редактор скриптов встроен в веб-интерфейс: Настройки → Редактор. Поддерживается подсветка синтаксиса Lua, JS, CSS, HTML и JSON, проверка баланса скобок и блоков function … end, автодополнение по клавише Tab.

Интерпретатор: Lua 5.4.4. Базовый API из встроенной в ESP32 Arduino-библиотеки расширен функциями доступа к датчикам, нагреву, насосам, мешалке и реле.

Как включить

По умолчанию поддержка Lua в прошивке отключена. Чтобы включить, откройте файл Samovar_ini.h в каталоге прошивки и замените строку

//#define USE_LUA

на

#define USE_LUA

После этого пересоберите прошивку и загрузите её в контроллер.

Архитектура

При старте контроллера выполняется файл init.lua. Его задача — инициализировать переменные, которые будут использоваться в других скриптах, и включить или выключить ежесекундный цикл выполнения (setNumVariable("loop_lua_fl", 1)).

Если цикл включён, каждую секунду подряд выполняются два скрипта:

  1. Общий script.lua — работает во всех режимах.
  2. Скрипт текущего режима: beer.lua (пиво), bk.lua (бражная колонна), nbk.lua (непрерывная бражная колонна), dist.lua (дистилляция), rectificat.lua (ректификация), cheese.lua (сыроварение) или suvid.lua (сувид).

Если до следующего запуска скрипт не успел отработать, текущий запуск пропускается: уже работающий скрипт не прерывается.

Разовый запуск всех скриптов доступен по адресу http://samovar.local/lua.

Кроме основных скриптов поддерживаются дополнительные кнопки режима — файлы вида btn_<режим>_buttonN.lua, например btn_rect_button1.lua. Они отображаются в веб-интерфейсе и позволяют вызывать пользовательский код по нажатию.

Важно. При обновлении прошивки веб-интерфейс загружает с сервера эталонные версии init.lua, script.lua, файлов режимов и btn_*.lua, но только если такого файла ещё нет в памяти контроллера. Пользовательские скрипты не затираются. Тем не менее храните собственные версии на компьютере — после сброса к заводским настройкам или переустановки веб-интерфейса они будут потеряны.

Внешнее оборудование

К скриптам можно подключить расширители портов по I²C:

  • PCF8575 — расширитель на 16 цифровых портов (определяется флагом USE_EXPANDER). К каждому порту подключается любое исполнительное устройство или «кнопочный» датчик. Все порты доступны и для чтения, и для записи.
  • PCF8591 — расширитель аналоговых портов (определяется флагом USE_ANALOG_EXPANDER). Используется для аналоговых датчиков — например, pH-электрода в режиме сыроварения.

Сценариев работы с расширителями много: можно реализовать собственный датчик безопасности, который при срабатывании выключает «Самовар» из скрипта, или управлять дополнительным ТЭНом по температуре пара. Конкретная логика определяется оборудованием.

Функции

GPIO и Arduino-совместимые

pinMode(pin, mode) — режим работы входа/выхода. Доступны только пины RELE_CHANNEL1, RELE_CHANNEL2, RELE_CHANNEL3, RELE_CHANNEL4 и LUA_PIN. Числовые значения пинов зависят от пиновой карты и приведены в описании GPIO.

digitalWrite(pin, value) — подать HIGH (1) или LOW (0) на пин.

digitalRead(pin) — считать текущее значение пина (HIGH или LOW).

analogRead() — считать аналоговое значение пина LUA_PIN в диапазоне 0–4095. На этом пине висит pH-электрод или датчик давления MPX5010DP, поэтому не подавайте на него больше 3,3 В: это выведет ESP32 из строя.

delay(ms) — пауза в миллисекундах.

millis() — миллисекунды с момента запуска контроллера.

Расширители портов

exp_pinMode(pin, mode), exp_digitalWrite(pin, value), exp_digitalRead(pin) — то же самое, что GPIO-функции, но для портов PCF8575 (0–15).

exp_analogRead(), exp_analogWrite(value) — аналоговые операции на PCF8591. Доступны только при включённом USE_ANALOG_EXPANDER.

Управление процессом

setPower(power) — включить (1) или выключить (0) нагрев.

setCurrentPower(value) — задать напряжение на регуляторе мощности. Если регулятор управляется по мощности, аргумент задаёт мощность. Доступно только при SAMOVAR_USE_POWER.

setBodyTemp(temp) — установить температуру тела при ректификации. В других режимах функция только выводит сообщение в консоль и в Blynk.

setMixer(value) — включить (1) или выключить (0) мешалку.

openValve(value) — открыть (1) или закрыть (0) клапан подачи воды.

setAlarm() — аварийный режим: контроллер выключает нагрев, закрывает клапан и отключает насос воды.

setNextProgram() — перейти к следующей строке программы (аналог кнопки в интерфейсе).

setPauseWithdrawal(value) — поставить (1) или снять (0) отбор на паузу.

setCapacity(num) — переключить текущую ёмкость отбора. Допустимый диапазон: 0…CAPACITY_NUM.

setLuaStatus(value) — установить статус Lua-режима. В случае занятости выбрасывает ошибку «Lua_status busy».

setPumpPwm(pwm) — ШИМ-управление производительностью насоса воды (0…1023). Доступно при USE_WATER_PUMP.

setServoAngle(angle) — задать угол сервопривода (0…SERVO_ANGLE). Доступно при SERVO_PIN.

setTimer(num, sec) — установить таймер num (1…10) на sec секунд. Всего 10 таймеров.

getTimer(num) — оставшееся время таймера в миллисекундах. Если таймер не установлен или уже истёк, вернётся 0.

getState() — числовой статус контроллера.

Переменные контроллера

getNumVariable(name) и setNumVariable(name, value) — чтение и запись числовых переменных. Запись возможна только для тех переменных, которые явно помечены как доступные для изменения (см. таблицу ниже). Пример: setNumVariable("TankTemp", 85) установит температуру куба 85 °C. Без понимания логики «Самовара» менять переменные рискованно — это может нарушить работу алгоритмов.

getStrVariable(name) и setStrVariable(name, value) — то же самое для строковых переменных.

Имена переменных, доступных из скрипта, приведены в таблице в следующем разделе.

Объекты — постоянное хранилище

Обычные переменные Lua живут только в момент выполнения скрипта и при следующем запуске теряются. Чтобы передать значение между запусками, используйте setObject и getObject:

setObject("name", value)     -- сохранить
getObject("name")            -- прочитать (вернёт "" если нет)
getObject("name", "NUMERIC") -- прочитать как число (вернёт 0 если нет)

Максимум 32 ключа (LUA_OBJECT_STORE_MAX_KEYS). Значения сохраняются до перезагрузки контроллера.

Лог, отладка, HTTP

sendMsg(msg, level) — вывести сообщение. При level = -1 — в com-порт и консоль браузера (для отладки). При level = 0, 1, 2 — в консоль и в Blynk.

http_request(url [, method, headers, body]) — HTTP-запрос. Удобно для интеграции с внешними сервисами: отправки уведомлений в Telegram, логирования, вебхуков. Таймаут короче, чем у обычной загрузки, и работает под общим мьютексом, поэтому одновременные вызовы из разных скриптов не конфликтуют.

I²C-устройства

check_I2C_device(address) — проверить наличие устройства на I²C-шине по адресу. Возвращает 1, если устройство ответило, иначе 0.

get_i2c_rele_state(relay) и set_i2c_rele_state(relay, state) — состояние и переключение I²C-реле. Допустимые номера: 1…4.

Шаговый модуль

set_stepper_by_time(speed, direction, seconds) — запустить шаговый двигатель на заданной скорости (0…65535) и направлении (0 или 1) на указанное время. Возвращает 1, если запуск выполнен.

set_stepper_target(speed, direction, target) — отработать заданное число шагов. Возвращает 1, если запуск выполнен.

get_stepper_status() — текущее состояние шагового модуля.

set_mixer_pump_target(target) и get_mixer_pump_status() — управление мешалкой-насосом (0 или 1).

I²C-насос

Доступны при use_I2C_dev = 2:

i2cpump_start(rate, ml)     -- запустить насос с заданной скоростью и объёмом
i2cpump_stop()              -- остановить
i2cpump_get_speed()         -- текущая скорость
i2cpump_get_target_ml()     -- целевой объём
i2cpump_get_remaining_ml()  -- осталось прокачать
i2cpump_get_running()       -- 1 если крутится, иначе 0

Плохие числа (NaN, Inf, ≤ 0) молча игнорируются, без ошибки.

Сторож корутин

В ESP32-версии лимит вложенных C-вызовов Lua снижен с 200 до 60 (LUAI_MAXCCALLS = 60), потому что на стеке задачи do_lua_script размером 8 КБ исходный лимит недосягаем. Если в скрипте используются coroutine.create / wrap / resume, обязательно вызовите armCoroutineWatchdog() в init.lua: иначе корутина съест стек раньше, чем сработает лимит.

Переменные

В таблице ниже перечислены переменные, доступные из скрипта. RO — только чтение, RW — можно менять через setNumVariable.

Показания датчиков (RO)

  • SteamTemp — температура датчика пара.
  • PipeTemp — температура датчика царги.
  • WaterTemp — температура датчика воды.
  • TankTemp — температура датчика куба.
  • ACPTemp — температура датчика ТСА.
  • pressure_value — давление в системе.
  • alcohol — расчётная крепость в реальном времени.
  • alcohol_s — крепость в стабилизированном состоянии.

Состояние и статусы (RO)

  • PowerOn — 0/1, признак включённого нагрева.
  • PauseOn — 0/1, признак паузы отбора.
  • pump_started — 0/1, насос воды работает.
  • valve_status — 0/1, клапан воды.
  • water_pump_speed — текущая скорость насоса.
  • program_Wait — 0/1, программа стоит на паузе.
  • SamSetup_Mode — режим работы «Самовара».
  • Samovar_Mode — текущий режим процесса.
  • Samovar_CR_Mode — текущий режим по внутренней классификации.
  • target_power_volt — заданное напряжение регулятора.
  • WFpulseCount, WFflowRate, WFtotalMilliLitres — показания расходомера (при наличии).

Параметры текущей строки программы (program_volume, program_speed, program_temp, program_power, program_time, program_capacity_num) и текущая ёмкость отбора (capacity_num) тоже доступны только для чтения.

Параметры, которые можно менять (RW)

  • acceleration_temp — температура разгонного ТЭНа.
  • boil_temp — температура кипения.
  • loop_lua_fl — 0/1, выключает или включает ежесекундный запуск скриптов.
  • SetScriptOff — 0/1, принудительное отключение скриптов.
  • show_lua_script — 0/1, выводить тело скрипта и значения переменных в com-порт и консоль (для отладки).
  • test_num_val — числовая переменная для отладки.
  • wp_count — количество импульсов расходомера (при USE_WATER_PUMP).

Строковые переменные

  • SamovarStatus (RW) — текущий статус, отображаемый в интерфейсе.
  • program_type (RO) — тип выполняемой программы.
  • test_str_val (RW) — строковая переменная для отладки.
  • Msg (спец.) — чтение продвигает курсор по кольцу событий; запись — через setStrVariable.

Виртуальные датчики (SAMOVAR_LUA_SIMULATION)

При включённой симуляции доступны VirtualSteamTemp, VirtualPipeTemp, VirtualWaterTemp, VirtualTankTemp, VirtualACPTemp (все RW). Используются для отладки скриптов без железа.

Часы (RO)

YY, MM, DD, HH, MI, SS — текущие год, месяц, день, час, минута, секунда по RTC контроллера.

Примеры

setObject и getObject

n = 156
setObject("MyObject", n)
print(n)            -- 156
n = n + 5
print(n)            -- 161
n = getObject("MyObject")
print(n)            -- 156 (прочитали сохранённое)

Отправка температуры куба в Telegram

local function urlencode(url)
  if url == nil then return end
  url = url:gsub("\n", "\r\n")
  url = url:gsub("([^%w ])", function(c)
    return string.format("%%%02X", string.byte(c))
  end)
  url = url:gsub(" ", "+")
  return url
end

function SendTelegram(text)
  local token = "5177...:AAG0b...."
  local chat_id = "38806....."
  http_request("http://api.telegram.org/bot" .. token
    .. "/sendMessage?chat_id=" .. chat_id
    .. "&text=" .. urlencode(text))
end

local text = "Текущая температура куба = "
  .. getNumVariable("TankTemp")
SendTelegram(text)

Аналоговый датчик уровня и насос воды

Пример читает аналоговый датчик уровня и включает насос, когда уровень попадает в заданный диапазон. Состояние насоса сохраняется между запусками через setObject.

start_pump = getObject("start_pump", "NUMERIC") + 0

sensor = analogRead()
if sensor >= 1000 and sensor <= 2000 and start_pump == 0 then
  setObject("start_pump", 1)
  digitalWrite(4, 1)
  print("Start pump")
elseif sensor == 0 then
  setObject("start_pump", 0)
  if start_pump == 1 then
    digitalWrite(4, 0)
    print("Finish pump")
  end
end

Безопасность и ограничения

  • 10 таймеров одновременно.
  • 32 ключа в хранилище объектов (LUA_OBJECT_STORE_MAX_KEYS).
  • Лимит вложенных C-вызовов Lua: 60 (LUAI_MAXCCALLS). Если используете coroutine.*, обязательно вызовите armCoroutineWatchdog().
  • Пины для pinMode: только RELE_CHANNEL1RELE_CHANNEL4 и LUA_PIN. Пин, занятый pH-электродом сыра, использовать нельзя — функция вернёт ошибку.
  • На analogRead() подавайте не больше 3,3 В.
  • setBodyTemp работает только в режиме ректификации; в остальных режимах выводит предупреждение.
  • При вызове setAlarm() контроллер прекращает нагрев, закрывает клапан и отключает насос.
  • Числовые аргументы i2cpump_start должны быть конечными положительными числами; NaN/Inf/≤0 молча игнорируются.

Дополнительные материалы

Добавить комментарий