Согласовано 13 апреля 2026. Рабочий документ для реализации.
Все чувствительные данные хранятся только на телефоне. Часть из них владелец по желанию может пропустить через сервер — с явным предупреждением.
| Данные | По умолчанию | По желанию через сервер |
|---|---|---|
| Координаты (lat, lon) | Только на телефоне | Можно поделиться с гостями (с предупреждением) |
| Отпечаток Wi-Fi (BSSID[]) | Только на телефоне | Не передаётся никогда |
| Адрес и секрет webhook | Только на телефоне | Можно хранить на сервере (с предупреждением) |
| Радиус, время, уровень подтверждения | Через сервер | — |
При добавлении объекта владелец выбирает тип связи. Дальше открывается окно настроек этого типа.
| Icon | Название | Как это работает | Feedback | Example |
|---|---|---|---|---|
| 📞 | Call | Телефонный звонок с телефона владельца | Нет (звонок либо ушёл, либо нет) | Шлагбаум, домофон |
| 🌐 | URL (webhook) | HTTP-запрос на адрес устройства — с телефона или с сервера Entrixy | Да — JSON-ответ со статусом | Умный замок с API, Tasmota, Shelly Cloud |
| 📟 | Интернет-контроллер (WS) | Команда по WebSocket подключённому контроллеру | Да — ответ по WebSocket | Самодельные ESP32 / ESP8266, Shelly Plus 1, NodeMCU |
| 📶 | BLE-контроллер | Прямой канал Bluetooth между телефоном и контроллером, без интернета | Да — ответ по BLE (notify) | Контроллер на батарейках у ворот без Wi-Fi |
Конфигуратор прошивки для двух последних типов: /controller/ (BLE и Интернет, в браузере).
Для пользователя все типы выглядят одинаково: карточка, кнопка Позвонить, статус. Отличается только механизм доставки.
В окне настроек webhook есть переключатель, а плюсы и минусы расписаны прямо на экране:
| Mode | Где адрес и секрет | Знает ли сервер адрес? |
|---|---|---|
| С телефона | Prefs на телефоне владельца | No |
| С сервера | Таблица numbers в базе данных | Yes |
Безопасность: подпись HMAC. У устройства и Entrixy общий webhook_secret.
POST https://device-url.com/open
Content-Type: application/json
{
"action": "open",
"object_id": 42,
"timestamp": 1713020000,
"nonce": "a1b2c3",
"signature": "hmac-sha256(secret, timestamp + nonce + action)"
}
Устройство проверяет, что подпись верна, отметка времени моложе 30 секунд, а nonce не повторный. Если всё в порядке — срабатывает и отвечает:
{"status": "ok", "message": "Door opened"}
or
{"status": "error", "message": "Lock jammed"}
Статус показывается пользователю в приложении.
The guest presses Call
→ the server receives the request
→ sends it to the owner over the WebSocket: {type: "do_webhook", ...}
→ the owner's phone makes the HTTP call to the device
→ receives the JSON response
→ sends it to the server: {type: "webhook_result", status, message}
→ the server passes it to the guest
→ both see the status in the log
В обоих режимах журнал на телефоне владельца и гостя записывает, кто, когда, какой объект и с каким статусом.
У контроллера — поддерживаются ESP32, ESP32-S3, ESP32-C3 и ESP8266 — нет публичного IP. Он держит исходящее соединение WebSocket с сервером Entrixy, ровно как телефон владельца.
Прошивка и конфигуратор живут по адресу /esp/socket/. Исходники: ESP32, ESP8266.
// Device → server: connect
{"type": "device_hello", "device_key": "xyz789", "device_secret": "..."}
// Server → device: OK
{"type": "device_ok"}
// Server → device: command
{"type": "device_command", "action": "open", "command_id": "abc123"}
// Device → server: result
{"type": "device_response", "command_id": "abc123", "status": "ok", "message": "Opened"}
Сервер передаёт статус клиентам — владельцу и гостю — по их соединениям WebSocket.
device_key + device_secretwss://entrixy.com/wsНа карточке объекта виден статус связи устройства — онлайн или офлайн, — так же как гости видят статус владельца.
Контроллеру на ESP32, S3, C3, C6 или H2 для срабатывания не нужны ни Wi-Fi, ни сервер. Он лежит в глубоком сне, раз в секунду просыпается примерно на 200 мс и передаёт BLE-объявление с подписанным счётчиком. Когда рядом оказывается телефон с действующим ключом, Android — или приложение, если оно на переднем плане — ловит объявление, подключается по GATT, шлёт команду fire с одноразовым nonce, и контроллер замыкает реле коротким импульсом. Для бистабильных приводов и замков есть режим с раздельными открыть и закрыть и отслеживанием положения, где открыто/закрыто едет зашифрованным байтом в объявлении.
Сервер Entrixy в этом канале не участвует. Он нужен только при создании гостевого ключа: владелец подписывает GuestToken и передаёт его гостю по сквозно зашифрованному каналу. Дальше гость работает офлайн.
Полная спецификация протокола, побитовая раскладка и тест-векторы — по адресу entrixy.com/ble. Модель угроз — в отдельном документе.
На один привод можно поставить и BLE, и WebSocket — в приложении они будут двумя отдельными объектами. BLE — открывать вблизи без интернета, WebSocket — когда вы далеко.
entrixy-pair)Прошивка и конфигуратор живут по адресу /esp/ble/. Исходник: /esp32-example/.
На карточке объекта: серый — в эфире не виден, далеко или выключен; оранжевый — виден, но автоматика не сработала; зелёный — сработало или срабатывает; серый с зелёной обводкой — недавно сработало, можно нажать и открыть снова.
CREATE TABLE devices ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, host_id INT UNSIGNED NOT NULL, device_key VARCHAR(64) NOT NULL UNIQUE, secret_hash VARCHAR(64) NOT NULL, label VARCHAR(128) DEFAULT '', last_seen DATETIME NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP );
In server.php добавляется третья роль WebSocket: device (рядом с host и guest).
GPS и Wi-Fi работают независимо. Если настроены оба, стреляет то условие, которое выполнилось первым. Общая пауза между срабатываниями — 20 секунд.
Режим 1: картина Wi-Fi (отпечаток)
Режим 2: подключение к сети
WifiManager.getScanResults() — кэшированные результаты без нового сканирования; вызываем на каждом обновлении GPS бесплатноNetworkCallback, вообще без сканирования
wifi_trigger_<actionKey> = {
"mode": "fingerprint" | "connect",
"bssids": ["AA:BB:CC:DD:EE:FF", ...],
"min_match": 5,
"connect_bssid": "AA:BB:CC:DD:EE:FF",
"connect_ssid": "TP-Link_5G",
"enabled": true
}
Владелец решает, требуется ли подтверждение. Как именно подтверждать личность, решает клиент — из того, что предлагает устройство.
| Level | Что видит пользователь | Example |
|---|---|---|
| Automatic | Ничего — объект открывается сам | Шлагбаумы, ворота |
| Confirm | Уведомление в шторке: Открыть [объект]? → одно нажатие | Гараж, калитка, защита от ложных срабатываний |
| Подтвердить личность | Биометрия, PIN-код телефона или PIN-код приложения | Входная дверь |
Подтвердить — не лишний шаг. Уведомление само появляется в шторке в нужный момент. Не надо искать приложение, разблокировать телефон и находить объект. Одно нажатие — и дверь открыта.
BiometricPromptKeyguardManagerВладелец задаёт Разрешённые часы: 07:00–23:00. Вне окна условие молча игнорируется. Ночной интервал тоже работает (22:00–06:00).
| Setting | Владелец (своё) | Владелец → гостям | Гость |
|---|---|---|---|
| Тип объекта | Chooses | Передаёт | Receives |
| Coordinates | Задаёт | По желанию (с предупреждением) | Задаёт или получает |
| Радиус GPS | Задаёт | Передаёт | Receives |
| Отпечаток Wi-Fi | Scans | Never | Сканирует сам |
| Минимум совпадений Wi-Fi | Задаёт | Передаёт | Receives |
| Временное окно | Задаёт | Передаёт | Receives |
| Подтверждение | Задаёт | Передаёт | Receives |
| GPS вкл/выкл | yes | — | yes |
| Wi-Fi вкл/выкл | yes | — | yes |
Первый шаг — выбор типа связи:
┌────────────────────────────┐ │ Connection type │ │ │ │ 📞 Call │ │ Opening with a phone │ │ call │ │ │ │ 🌐 URL │ │ Sending a command to │ │ a device address │ │ │ │ 📟 Device │ │ Connected through Entrixy │ │ (ESP32, Arduino) │ └────────────────────────────┘
После выбора открывается окно настроек этого типа.
┌──────────────────────────────────────────┐ │ Corner barrier 📶 3/5 312m │ │ Mine • ● │ ├──────────────────────────────────────────┤ │ [Edit] [Icon] │ │ ───────────────────────── │ │ [📍 Geo] [📶 Wi-Fi] │ └──────────────────────────────────────────┘
◉ По картине Wi-Fi
○ По подключению к сети
Ниже: временное окно и подтверждение — общие с Гео
| Trigger | Indicator |
|---|---|
| GPS | "312 m" |
| Отпечаток Wi-Fi | 📶 деления (0–4 по совпадениям) |
| Подключение Wi-Fi | 📶 зелёный или серый |
| Webhook/Device | ● зелёный (онлайн) или серый (офлайн) |
Внутренние тарифы. Пользователю не показываются, но лимиты действуют.
| Тариф по умолчанию | Limit |
|---|---|
| Объекты (numbers) | 10 |
| Гости (user_keys) | 10 |
При превышении — мягкое сообщение: Число объектов ограничено. Обратитесь в поддержку, чтобы его увеличить.
CREATE TABLE plans (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(64) NOT NULL,
max_numbers INT NOT NULL DEFAULT 10,
max_keys INT NOT NULL DEFAULT 10
);
INSERT INTO plans (name) VALUES ('default');
ALTER TABLE hosts ADD COLUMN plan_id INT UNSIGNED DEFAULT 1;
-- Plans
CREATE TABLE plans (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(64) NOT NULL,
max_numbers INT NOT NULL DEFAULT 10,
max_keys INT NOT NULL DEFAULT 10
);
INSERT INTO plans (name) VALUES ('default');
ALTER TABLE hosts ADD COLUMN plan_id INT UNSIGNED DEFAULT 1;
-- Object type and settings
ALTER TABLE numbers
ADD COLUMN type ENUM('call','webhook','device') DEFAULT 'call',
ADD COLUMN radius INT DEFAULT 80,
ADD COLUMN time_from TIME NULL,
ADD COLUMN time_to TIME NULL,
ADD COLUMN security_level ENUM('auto','confirm','identity') DEFAULT 'auto',
ADD COLUMN geo_available TINYINT(1) DEFAULT 1,
ADD COLUMN wifi_available TINYINT(1) DEFAULT 1,
ADD COLUMN wifi_min_match INT DEFAULT 5,
ADD COLUMN share_lat DOUBLE NULL,
ADD COLUMN share_lon DOUBLE NULL,
ADD COLUMN webhook_url VARCHAR(512) NULL,
ADD COLUMN webhook_secret VARCHAR(64) NULL,
ADD COLUMN webhook_mode ENUM('phone','server') DEFAULT 'phone',
ADD COLUMN device_id INT UNSIGNED NULL;
-- Devices (ESP32)
CREATE TABLE devices (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
host_id INT UNSIGNED NOT NULL,
device_key VARCHAR(64) NOT NULL UNIQUE,
secret_hash VARCHAR(64) NOT NULL,
label VARCHAR(128) DEFAULT '',
last_seen DATETIME NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
share_lat / share_lon — заполняются, только если владелец включил Делиться координатами с гостями.
webhook_url / webhook_secret — заполняются только в серверном режиме. В режиме телефона живут в Prefs.
Владелец ставит объекту свою иконку, и гость должен её видеть. Но иконка на сервере не хранится — сервер работает почтальоном: доставил и забыл.
При установке иконка сразу ужимается до 64×64 PNG (около 3–5 КБ) и хранится локально в Prefs или файлом.
1. The guest connects
→ guest_ok carries has_avatar: true for objects that have an icon
2. The guest client checks: has_avatar=true but no icon locally?
→ Yes → it asks the server
3. The server has no icon
→ it asks the owner over the WebSocket: {type: "avatar_request", number_id: 42}
4. The owner's phone
→ reads the local file
→ sends: {type: "avatar_data", number_id: 42, data: "base64..."}
5. The server passes it to the guest
→ {type: "avatar_data", number_id: 42, data: "base64..."}
6. The guest stores it locally and never asks again
7. The server stored nothing — the data merely passed through
| Situation | Behaviour |
|---|---|
| Владелец офлайн | Гость видит иконку по умолчанию, пока владелец не появится в сети. |
| 50 гостей спрашивают разом | 50 × 5 КБ = 250 КБ по WebSocket — пустяк. |
| Владелец меняет иконку | has_avatar_hash меняется, и гости запрашивают её заново |
| Владелец удаляет иконку | has_avatar: false, и гости показывают иконку по умолчанию |
| Subscribers | Одновременно в сети (~15%) | Соединений WebSocket | Server |
|---|---|---|---|
| 1 000 | ~150 | ~150 | Easy |
| 10 000 | ~1 500 | ~1 500 | Easy |
| 50 000 | ~7 500 | ~7 500 | один воркер на пределе |
| 100 000 | ~15 000 | ~15 000 | 2–3 воркера |
Workerman на одном воркере: 5000–10 000 одновременных соединений, примерно по 20 КБ каждое.
— MySQL, а не WebSocket. Но 250 000 вставок в сутки — 50 тысяч подписчиков × 5 вызовов — для MySQL на SSD пустяк.
Entrixy — итоговая архитектура v2, согласовано 13 апреля 2026