ИНструкция
Контроллер ODPLC-B
ODPLC-B - это небольшой контроллер, программируемый на Lua
Ключевые возможности
  • Входы-выходы
    10 релейных выходов 7A 240VAC, 5A 240VAC(TUV), 10A 120VAC/24VDC
    10 входов для подключения сигналов типа "сухой контакт"/кнопок. Напряжение подтяжки 3.3В.
    Ethernet RJ45 для сети с Passive PoE 7-24В
  • Программирование на Lua
    Вы можете посмотреть программу, которая работает в устройстве и самостоятельно ее поменять. Мы приготовили необходимые библиотеки и примеры кода для легкого погружения в материал.
  • WiFi интерфейс
    Контроллер создает WiFi сеть для конфигурации и настройки через Web-интерфейс.
    Вы можете подключить его к вашей существующей WiFi сети для доступа в Internet.
    Также WiFi может использоваться для опроса контролируемого ПК/терминала/роутера/сервера.
  • Bluetooth (Pro)
    Контроллер (в версии Pro) может отправлять BLE Eddystone beacons для индикации состояний с помощью Bluetooth.
  • Сохранение и отправка отчетов
    Контроллер может собирать логи работы: состояние температурных и дискретных датчиков, пропажу пинга, отправленные команды на перезагрузку и т.п. и сохранять это во встроенной памяти, либо отправлять на сервер по tcp/udp/mqtt или на почту (Pro).
  • Telegram
    Прямая интеграция с вашим телеграм ботом без использования сторонних сервисов.
    • Можно отправлять команды на перезагрузку и получать данные о работе, данные датчиков, статистику и т.д.
    • Можно написать свои действия на команды.
  • Обновления и пакетный менеджер
    Устройство может обновляться онлайн, а также имеет пакетный менеджер для установки библиотек по сети, либо обновления исполняемого кода.
  • Разные источники телеметрии
    Собирайте температуру, загрузку процесса и любые другие параметры. Используйте сетевой или usb интерфейс пк для передачи информации.
  • Вариант Arduino
    Мы можем поставить контроллер без прошивки, чтобы вы самостоятельно писали программу в инфраструктуре Arduino (без поддержки кода).
WIFI
Устройство обладает маленькой антенной и, будучи дополнительно установленным к какой-либо корпус, вероятно, сможет обеспечить небольшой радиус устойчивого беспроводного сигнала - порядка нескольких метров, учитывайте это при проектировании.
При включении устройство создаст WiFi-точку доступа вида odplc-[серийный номер].
Пароль сети - 8 последних цифр серийного номера.
Устройство запустит Web-сервер.
IP устройства: 192.168.4.1

Позже вы можете изменить настройки сети по своему вкусу.
Web-интерфейс
На момент написания этой заметки некоторые сборки Chrome могут блокировать часть функционала, т.к. устройство работает через http, а не https. Подробнее: https://itecnote.com/tecnote/websocket-connection-fails-on-chrome-without-ssl.
Если у вас возникает эта проблема, пожалуйста, используйте другой браузер.
Вы, как разработчик, можете реализовать другой web-интерфейс, уже адаптированный под задачи ваших клиентов.

Основной экран

На данном экране можно увидеть общую информацию об устройстве и сообщения из кода (отправленные из программы пользователя).


Экран настроек

Данный экран позволяет изменять основные настройки устройства.

Часть из настроек сделаны для обработки из пользовательской программы и устройством не обрабатываются.

В настройках можно закрыть паролем доступ к web-интерфейсу.

Параметры работы устройства
Данные параметры используются устройством.

Тип Адреса:
  • WIFI AP - устройство создает свою сеть с параметрами SSID и WiFi пароль
  • WIFI STA - устройство подключается к существующей сети с параметрами SSID и WiFi пароль.
Язык: язык интерфейса
Watchdog: запуск сторожевого таймера устройства. если он включен, то программе нужно его сбрасывать не реже, чем 1 раз в 10 секунд. Отключите его на период разработки.
NTP сервер: сервер часов точного времени.
MDNS: позволят обращаться к устройству не зная его IP, по адресу типа odnc-[4-последние-цифры-серийного-номера].local. Например http://luaterm-ABCD.local (если позволяет роутер).
Telnet: запуск telnet-сервера - позволяет аварийно отредактировать программу или настройки, если у вас не осталось никакого другого интерфейса для взаимодействия с устройством.
SSH: включает ssh-сервер (для Pro-версии).
Web-интерфейс: включить/отключить web-сервер.
Web-пароль: установить Basic-Auth пароль на http-запросы.

Редактор кода

Простой редактор для модификации встроенной программы.
Позволяет изменять только в файле usercode.lua, который загружается автоматически.

Этого хватает для подавляющего большинства задач. Если у вас планируется разработка большого проекта, то вы можете работать с файлами, ходить по файловой системе на устройство через консоль, подключившись по usb.


Экран "об устройстве"

Экран для получения информации об устройстве, обновления устройства локально или через интернет.

Если вы перезагружаете устройство, то надо перезагружать и странцу (примерно через 5-10 секунд). Потому что у вас в браузере осталась страница, которая не знает, что устройство перезагружено и она будет вести себя непредсказуемо, исходя из времени жизни кеша, открытых соединений и т.п.
Телеметрия по HTTP
Забор данных по http с адреса http://<ip>/backend?action=get
Логи по HTTP
Забор данных по http с адреса http://<ip>/public
Логи rsyslog и другие способы
Варианты отправки логов вы можете посмотреть на отдельной странице
Технические характеристики
1. Габаритные размеры: 90х60х15мм.
2. Интерфейсы: USB/WiFi + Ble (для Pro)
3. Индикация: светодиоды x2, звуковой излучатель.
4. Выход оптоизолированный (транзисторная оптопара): 3 шт, до 35В 50мА.
5. Вход: 3 шт.
6. Вход-выход с подтяжкой 4.7КОм на +3.3В для подключения датчиков: 3 шт.
7. Питание: USB 5В.
8. Потребление: среднее 130 мА, пиковое - 700мА (зависит от подключенной периферии).
Внимание: корпус не герметичный (предназначен только для защиты платы) и предполагает применение устройства в закрытом помещении. Но мы можем покрыть плату лаком.
Модули расширения
Аккумулятор
Аккумулятор 300 mAh для работы устройства в моменты отсутствия питания
Релейный блок для управления питанием низковольтных устройств
Посмотреть
Кнопка включения с сохранением состояния
Посмотреть
Датчик температуры
Посмотреть
AM2302
Датчик температуры-влажности
Датчик геркон
Посмотреть
Почему Lua ?

Хотя Lua далеко не самый распространенный язык, он имеет ряд больших преимуществ:
  • предназначен для пользователей, не являющихся профессиональными программистами, вследствие чего большое внимание уделено простоте дизайна и лёгкости обучения;
  • скриптовый язык - не требует отдельной компиляции;
  • маленький размер - в контроллер умещается полная версия языка, а не урезанная;
  • простой паскалеподобный синтаксис, известный многим еще со школы;
  • минимум синтаксиса;
  • поддержка ООП;


Пример кода в устройстве
Небольшой пример, чтобы понять, как работает устройство и как можно изменять логику работы.
В данном коде находится вся программа, с которой идет устройство.
local cjson = require("cjson")
local base = require("base")
local pro2timer = require("pro2timer")
local logger = require("logger")
local utils = require("utils")

local atoi = tonumber
local settings = Settings.load()
local log = logger(nil, nil, nil, nil, atoi(settings.sys_ntp_off))
Temp = base.Temp({base.IO1pin, base.IO2pin, base.IO3pin})
Temp1, Temp2, Temp3 = -9997.0, -9997.0, -9997.0

-- Поток опроса температурных датчиков
thread.start(function()
    while true do
        local t = Temp:readAll()
        Temp1, Temp2, Temp3 = t[1], t[2], t[3]
        thread.sleep(30)
    end
end, nil, 21, nil, "Temp")

-- Callback для обработки http-запросов
function Http_get(params)
    if params.out1 then
        base.out1.set(params.out1 == "1")
    end
    if params.out2 then
        base.out2.set(params.out2 == "1")
    end
    if params.out3 then
        base.out3.set(params.out3 == "1")
    end
    return cjson.encode({ t1 = Temp1, t2 = Temp2, t3 = Temp3, uptime=os.uptime(2),
                        out1 = base.out1.get(), out2 = base.out2.get(), out3 = base.out3.get(),
                        in1 = base.in1.get(), in2 = base.in2.get(), in3 = base.in3.get() })
end

if settings.sys_sound then
    base.buzz.beep()
end

-- Алгоритм Watchdog
if settings.wdt_tim == "on" then
    local pusher = base.Pusher(base.out1, base.out2, settings.wdt_ch1, settings.wdt_ch2, atoi(settings.wdt_t2), atoi(settings.wdt_t3), atoi(settings.wdt_t4), atoi(settings.wdt_t5)) or nil
    local usb = settings.wdt_usb == "on"
    local url = #settings.wdt_url>0 and settings.wdt_url or false
    local btn = settings.wdt_in == "on" and base.wdt_in or false
    local usb_counter, usb_checker = 0, 0
    local timer 

    timer = pro2timer.new(tmr.TMR1, atoi(settings.wdt_t1), base.rled, function()
        pusher:push()
        timer:reload()
        if settings.wdt_log then 
            log("Trying to reload")
        end
        if settings.sys_sound then
            base.buzz.beep(100)
        end
    end)

    if usb then
        thread.start(function()
            while true do
                local cmd = io.read("*line")
                if cmd == "~U" then
                    usb_counter = (usb_counter+1) & 0xffff
                elseif cmd == "~I" then
                    local _, version, _, _ = os.version()
                    print("~I"..cpu.board().." "..version) 
                end
                thread.sleepms(100)
            end
        end)
    end

    local function check(usb, url, btn)
        local success, res = false, true
        if usb then
            res = (usb_checker ~= usb_counter)
            usb_checker = usb_counter
        end
        if url and res then
            success, tim = pcall(net.mping, url)
            if success then
                res = tim > 0
            else
                res = false
            end
        end
        if btn and res then
            res = btn.pressed()
        end
        return res
    end

    local tempRoutine = utils.routine(180, function ()
        if settings.wdt_log then 
            log(string.format("Temp1: %.1f, Temp2: %.1f, Temp3: %.1f", Temp1, Temp2, Temp3))
        end
    end)

    base.gled.on()

    while true do
        if check(usb, url, btn) then
            pusher:clear()
            timer:reload()
            base.gled.off()
            thread.sleep(1)
        end
        tempRoutine()
        base.gled.on()
        thread.sleep(2)
    end
end
Восстановление устройства
Порядок действий, если вы "закирпичили" устройство и не можете получить к нему доступ.
Самый простой вариант - подключить устройство к USB своего ПК и подключиться программой-терминалом (putty, minicom, miniterm и т.д.) в последовательному порту устройства.
Если нажать CTRL-C, то программа остановится и станет доступна консоль.
Если нажать при загрузке устройства CTRL-D, то пропустятся скрипты автозагрузки.

Если по какой-то причине у нас нет возможности (или желания) работать с консолью, то можно получить доступ к Web-интерфейсу:
  1. Выключить устройство.
  2. Зажать кнопку на устройстве.
  3. Включить устройство держа кнопку зажатой.
  4. Подождать несколько секунд (после кнопку можно отпустить).
  5. Устройство создаст WiFi-точку доступа вида Luaterm-[серийный номер].
  6. Пароль сети - последние 8 цифр серийного номера.
  7. Устройство запустит Web-сервер и telnet-сервер, чтобы вы могли исправить настройки/программу и восстановить доступ к устройству.
  8. IP устройства: 192.168.4.1
Дополнительные материалы
1
Консоль
Маленькая шпаргалка "как работать с консолью".
2
Библиотеки и RTOS
Большая документация на нашем отдельном сайте.
3
Справочник по Lua
Русскоязычная онлайн версия с поиском и перекрестными ссылками.
4
Справочник по LuaSocket
На оригинальном сайте.
5
Как программировать ODNFC на Lua
Большое количество примеров кода на другое наше устройство, большую часть которых можно использовать и тут.
6
Онлайн ИИ-генератор кода под устройство
Генератор кода, адаптированный под работу с устройством.