- TypeScript 48%
- Go 29.1%
- CSS 11.1%
- Python 9.7%
- Makefile 1.8%
- Other 0.3%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| go-emu | ||
| web | ||
| .gitignore | ||
| GLOSSARY.md | ||
| Makefile | ||
| README.md | ||
KEBA IO-Board Emulator
Эмулятор модуля ввода-вывода (IO-board) для промышленных панелей Engel/KEBA (платформа eMove).
История
На промышленной панели Engel/KEBA вышли из строя физические кнопки управления. Эмулятор заменяет поведение этих кнопок, позволяя управлять панелью через веб-интерфейс или HTTP API.
Архитектура
┌─────────────────────────────────────────────────────────────┐
│ Панель KEBA │
│ ┌──────────────────┐ RS-485 ┌──────────────────┐ │
│ │ multicpumaster │◄────────────►│ go-emu (PTY) │ │
│ │ │ │ simple/cyclic │ │
│ └──────────────────┘ │ protocols │ │
│ └────────▲─────────┘ │
│ │ read │
│ ┌────────┴─────────┐ │
│ │ button file │ │
│ │ (mask в hex) │ │
│ └────────▲─────────┘ │
│ │ write │
│ ┌────────┴─────────┐ │
│ │ web panel │ │
│ │ (React + API) │ │
│ └──────────────────┘ │
└─────────────────────────────────────────────────────────────┘
multicpumaster опрашивает IO-board по RS-485 (через PTY). Главный цикл эмулятора
читает маску кнопок из button file и отдаёт её в каждом cyclic-ответе. Веб-панель
меняет состояние через HTTP API эмулятора (запись в тот же файл); можно и напрямую —
echo 0x0002 > <BUTTON_FILE> (debug-канал, lease не затрагивается).
Компоненты
| Компонент | Описание |
|---|---|
go-emu/ |
Go-сервер: PTY-эмуляция, протоколы обмена, HTTP API |
web/ |
React-интерфейс для ручного управления кнопками |
Интерфейс
Веб-панель позволяет управлять состоянием кнопок и просматривать лог операций.
Desktop (1200×800)
Tablet (1024×768)
Mobile (375×667)
Кнопки
| Маска | Имя | Описание |
|---|---|---|
0x0001 |
POWER | Открывает shutdown-диалог на экране (одиночное нажатие панель не выключает) |
0x0002 |
MOVE_OUT | Выдвинуть рабочий стол |
0x0004 |
MOVE_IN | Задвинуть рабочий стол |
0x0100 |
ACK | Подтверждение |
0x0200 |
PU | Подъёмник (Pick-Up) |
Комбинация POWER + ACK (0x0101) инициирует штатное выключение панели — примерно 11 секунд
do нажатия до shutdown -h; пока маска удерживается, shutdown инициируется повторно —
как на реальной железке.
Требования
- ОС: Linux (эмулятор использует PTY)
- Go 1.25+
- Node.js 20.19+ или 22.12+ (для сборки веб-панели)
Сборка
Go-эмулятор
cd go-emu
go build -o ioboard-emu .
Веб-панель
cd web
npm install
npm run build
Сборка и разработка через Make
Все типовые операции покрыты целями Makefile в корне репозитория. Цели Go требуют Linux/macOS (PTY); на Windows используйте WSL.
| Команда | Что делает |
|---|---|
make или make all |
Собрать всё: Go-эмулятор + веб-панель |
make build-go |
Собрать bin/ioboard-emu |
make run-go |
Собрать и запустить эмулятор |
make test-go |
Юнит-тесты Go |
make test-python |
Интеграционный тест (Python, сам собирает бинарь) |
make web-install |
npm install для веб-панели |
make web-build |
Собрать веб-панель в web/dist |
make web-test |
Тесты веб-панели (vitest) |
make web-dev |
Dev-сервер Vite с hot-reload |
make clean |
Удалить bin/, web/dist, node_modules |
make help |
Список всех целей |
Заметки:
- Цели
web-*сначала выполняютweb-install(npm-зависимости ставятся при необходимости). test-pythonиrun-goнеявно пересобирают бинарь (build-go).
Запуск
1. Настройка
Скопируйте пример конфигурации и отредактируйте пути:
cd go-emu
cp .env.example .env
Основные параметры в .env:
LINK_PATH=/tmp/hhs-emu-demo/ttyIOBOARD # симлинк для multicpumaster
BUTTON_FILE=/tmp/hhs-emu-demo/emulated_buttons
LOG_FILE=/tmp/hhs-emu-demo/ioboard_emu_debug.log
HTTP_ADDR=0.0.0.0:8080
WEB_DIR=../web/dist
API_TOKEN= # оставьте пустым для dev
Создайте директорию для файлов:
mkdir -p /tmp/hhs-emu-demo
2. Запуск
./ioboard-emu
Эмулятор:
- создаёт пару PTY и симлинк по
LINK_PATH - запускает HTTP-сервер на
HTTP_ADDR - обнуляет состояние кнопок при старте
- при остановке сбрасывает кнопки и удаляет симлинк
HTTP API
Получить состояние кнопок
curl http://localhost:8080/api/buttons
Ответ:
{"mask": 5}
Установить состояние кнопок
curl -X PUT http://localhost:8080/api/buttons \
-H "Content-Type: application/json" \
-d '{"mask": 5}'
Авторизация
Если API_TOKEN задан, используйте Bearer-токен:
curl http://localhost:8080/api/buttons \
-H "Authorization: Bearer ваш_токен"
Механизм Lease
После записи ненулевой маски через API создаётся lease на 2 секунды. Любой
аутентифицированный запрос к API продлевает его; веб-панель шлёт heartbeat каждые
500 мс. Если lease истёк — эмулятор сбрасывает кнопки в 0x0000, но только если
в файле всё ещё лежит арендованная маска: изменения, внесённые напрямую через
echo (debug-канал), не затираются. Это защита от зависших клиентов.
Протоколы
Эмулятор поддерживает два протокола обмена с панелью:
Simple Protocol
Используется при инициализации — запрос версии, состояния кнопок, управление цифровыми выходами.
Cyclic Protocol
Основной режим — высокочастотный обмен (запросы панели каждые ~20–55 мс). Передаёт текущее состояние кнопок и rotating ID для синхронизации.
Cyclic-кадры защищены byte-stuffing (экранирование STX=0x02 и ESC=0x1b) и контрольной суммой BCC (XOR). Simple-кадры — фиксированный формат 0x96 … 0x8d без stuffing/BCC.
Разработка
Веб-панель: dev-сервер
Для разработки с hot-reload:
cd web
cp .env.example .env.development
npm run dev
Vite автоматически проксирует запросы /api на адрес эмулятора.
Тесты
Go-эмулятор:
cd go-emu
go test ./...
Интеграционный black-box тест (сам собирает бинарь; проверяет simple/cyclic-протоколы,
динамику кнопок и graceful shutdown; нужны go и python3):
python3 go-emu/test_ioboard_emu_go.py
Веб-панель:
cd web
npm run test
Безопасность
- В production всегда задавайте
API_TOKENв.env - HTTP-сервер по умолчанию слушает на
0.0.0.0:8080— учитывайте это при развёртывании - Lease-механизм защищает от забытых нажатых кнопок
См. также
- GLOSSARY.md — глоссарий терминов


