Newer
Older
smart-home-server / docs / control-scripts-guide.md

Руководство по написанию Control Scripts

Control Scripts — это PHP-классы автоматизации. Базовый класс находится в server/SHServ/Middleware/ControlScripts.php, интерфейс — в server/SHServ/Implements/ControlScriptsInterface.php.

Scope-классы располагаются в server/ControlScripts/Scopes/ (или другом месте, если настроено иначе). Все Scope-файлы загружаются автоматически при старте сервера.


Базовый класс

Все Scope-классы наследуют \SHServ\Middleware\ControlScripts и реализуют \SHServ\Implements\ControlScriptsInterface:

<?php

namespace ControlScripts\Scopes;

class MyScope extends \SHServ\Middleware\ControlScripts 
              implements \SHServ\Implements\ControlScriptsInterface {
    // ...
}

Автоматическая загрузка:
При старте сервера каждый Scope-класс:

  1. Проверяет состояние в БД (таблица scripts, тип scope, имя = название класса)
  2. Если scope включён (или это первый запуск) — вызывает 4 регистрационных метода
  3. Методы регистрируют обработчики в статические коллекции Fury Events


Четыре регистрационных метода

Каждый Scope-класс обязан реализовать 4 метода. Они вызываются при старте сервера (если scope включён в БД).

1. register_sync_map(): void

Регистрирует связи «реле ↔ кнопки» для синхронизации индикаторов.

public function register_sync_map(): void {
    $this->add_sync_connection([
        // Первый элемент — источник состояния (обычно реле)
        ["type" => "relay",  "alias" => "kitchen_relay", "channel" => 0],
        // Остальные — кнопки, чьи индикаторы синхронизируются
        ["type" => "button", "alias" => "kitchen_btns",  "channel" => 1],
        ["type" => "button", "alias" => "hall_btns",     "channel" => 0],
    ]);
}

Sync map хранится в статической переменной ControlScripts::$sync_map_storage.


2. register_events_handlers(): void

Подписывается на события от устройств. Обработчик вызывается асинхронно после ответа устройству (fastcgi_finish_request).

public function register_events_handlers(): void {
    // Нажатие кнопки (канал 1) конкретного устройства
    $this->add_event_handler("button@kitchen_btns(1).press", function(Device $device, array $data) {
        $relay = $this->devices()->by_alias("kitchen_relay");
        $relay->device_api()->toggle_channel(0);
        $this->helper()->sync_relay_to_btns($this->sync_map(), "kitchen_relay");
    });

    // Устройство вышло в сеть (после перезагрузки)
    $this->add_event_handler("button@kitchen_btns.online", function(Device $device, array $data) {
        $this->helper()->sync_btn_channels($this->sync_map(), $device->alias);
    });
}

Паттерны имён событий:

Паттерн Пример Описание
{event_name} press Любое устройство, любое событие
{type}.{event_name} button.press Все устройства типа button
{type}@{alias}.{event_name} button@kitchen_btns.press Конкретное устройство (все каналы)
{type}({ch}).{event_name} button(1).press Все устройства типа, канал 1
{type}@{alias}({ch}).{event_name} button@kitchen_btns(1).press Конкретное устройство, канал 1

Полное описание: docs/events-from-devices.md.


3. register_actions_scripts(): void

Регистрирует action-скрипты (ручной запуск через UI/API).

public function register_actions_scripts(): void {
    $this->add_action_script([
        "alias"       => "kitchen_light_toggle",
        "name"        => "Свет на кухне",
        "icon"        => '<i class="ph ph-lightbulb"></i>',
        "description" => "Включить/выключить основной свет",
        "author"      => "Eugene Sukhodolskiy"
    ], function($params) {
        $relay = $this->devices()->by_alias("kitchen_relay");
        $relay->device_api()->toggle_channel(0);
        $this->helper()->sync_relay_to_btns($this->sync_map(), "kitchen_relay");
        return ["result" => true];
    });
}

API:

  • POST /api/v1/scripts/actions/run — запустить скрипт
  • GET /api/v1/scripts/actions/alias/{alias}/enable — включить
  • GET /api/v1/scripts/actions/alias/{alias}/disable — выключить

4. register_regular_scripts(): void

Регистрирует regular-скрипты (периодический запуск по cron).

public function register_regular_scripts(): void {
    $this->add_regular_script([
        "alias" => "check_door_sensor",
        "name"  => "Проверка датчика двери",
    ], function() {
        $sensor = $this->devices()->by_alias("door_sensor");
        // ...
    });
}

API:

  • GET /cron/regular-scripts — запустить все enabled regular-скрипты (cron)
  • GET /api/v1/scripts/regular/alias/{alias}/enable — включить
  • GET /api/v1/scripts/regular/alias/{alias}/disable — выключить

Доступные методы базового класса

Метод Возвращает Описание
$this->devices() \SHServ\Models\Devices Поиск устройств по alias, id, hard_id
$this->helper() \SHServ\Helpers\DeviceScriptsHelper Хелперы синхронизации реле/кнопок
$this->sync_map() array Текущий sync_map (статическое хранилище)
$this->add_event_handler($name, $cb) void Подписаться на событие
$this->add_action_script($attrs, $cb) bool Зарегистрировать action-скрипт
$this->add_regular_script($attrs, $cb) bool Зарегистрировать regular-скрипт
$this->add_sync_connection($entries) void Добавить связь в sync_map

DeviceScriptsHelper

Класс \SHServ\Helpers\DeviceScriptsHelper предоставляет методы для синхронизации индикаторов кнопок с состоянием реле.

Методы

Метод Описание
sync_relay_to_btn_channel($relay_api, $btn_api, $relay_ch, $btn_ch) Синхронизировать один канал реле с одним каналом кнопки
sync_relay_to_btns($sync_map, $relay_alias) Синхронизировать все кнопки из sync_map с указанным реле
sync_btn_channels($sync_map, $btn_alias) Синхронизировать индикаторы указанной кнопки с реле из sync_map
get_sync_entries_by_type($sync_map, $type) Получить все записи указанного типа из sync_map
prepare_sync_map_by_alias($sync_map, $alias) Подготовить sync_map для указанного устройства

Пример использования

// В event-хендлере: переключить реле и синхронизировать кнопки
$relay = $this->devices()->by_alias("kitchen_relay");
$relay_api = $relay->device_api();
$relay_api->toggle_channel(0);

// Синхронизировать все кнопки, связанные с этим реле
$this->helper()->sync_relay_to_btns($this->sync_map(), "kitchen_relay");

// Или: синхронизировать конкретную кнопку с реле
$this->helper()->sync_btn_channels($this->sync_map(), "kitchen_btns");

Управление Scope через API

Endpoint Описание
GET /api/v1/scripts/actions/scope/{name}/enable Включить Scope (в БД)
GET /api/v1/scripts/actions/scope/{name}/disable Выключить Scope (в БД)
GET /api/v1/scripts/scopes/list Список всех Scope с состоянием
GET /api/v1/scripts/scopes/name/{name} Исходный код PHP-файла Scope
POST /api/v1/scripts/scopes/update Обновить код Scope

Важно: Scope отключается через БД — при следующем запуске сервера его скрипты не зарегистрируются.


Trait Common (опционально)

Некоторые проекты используют trait \ControlScripts\Common с готовыми хелперами:

use \ControlScripts\Common;

class MyScope extends \SHServ\Middleware\ControlScripts {
    use Common;
    
    public function register_sync_map(): void {
        // Зарегистрировать глобальный sync_map (все реле и кнопки системы)
        $this->register_global_device_sync_map();
    }
    
    public function register_events_handlers(): void {
        // Установить обработчики нажатий для кнопок из sync_map
        $this->set_btns_click_handlers("kitchen_btns");
    }
}

Проверьте наличие trait в вашем проекте: server/ControlScripts/Common.php.