Категории

Сделал возможность редактирования правил автоматизации в веб-интерфейсе IoT на Raspberry Pi

2025-12-13 12:47:01 | Статья из категории: IOT умный дом

Если вы строите свой умный дом на Raspberry Pi с MQTT и PHP, рано или поздно вам понадобится не просто создавать правила автоматизации, а редактировать их из браузера. Кажется, что достаточно добавить ссылку «Редактировать» и подставить данные в форму — но на практике всё ломается: скрипты не запускаются, данные не сохраняются, а JS выдаёт «Unexpected token».

Рассказываю, как сделать это надёжно, без костылей и с поддержкой сложных условий (включая JS-скрипты и расписания).

1. Структура данных: не забудьте все поля

Правило автоматизации — это не просто «если температура > 25, включи свет». Это:

Поэтому таблица в MySQL должна включать все поля:

CREATE TABLE automations (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    condition_type ENUM('simple','script') NOT NULL DEFAULT 'simple',
    trigger_topic VARCHAR(255) NOT NULL,
    condition_operator ENUM('>', '<', '==', ...) NOT NULL,
    condition_value VARCHAR(50) NOT NULL,
    condition_script TEXT NULL,  -- ← КЛЮЧЕВОЕ ПОЛЕ!
    condition_duration INT DEFAULT 0,
    action_topic VARCHAR(255) NOT NULL,
    action_payload TEXT NOT NULL,
    schedule_type ENUM('none','daily','weekly') DEFAULT 'none',
    schedule_time TIME NULL,
    schedule_days SET('mon','tue',...) DEFAULT NULL,
    dependency_topic VARCHAR(255) NULL,
    dependency_value VARCHAR(50) NULL,
    enabled TINYINT(1) DEFAULT 1,
    persistent TINYINT(1) DEFAULT 0,
    ...
) ENGINE=InnoDB;

Ошибка №1: забыли condition_script. Тогда при INSERT/UPDATE — ошибка «Unknown column».

2. Почему редактирование не работало: 3 причины

Причина 1: смещение аргументов в JS

Вы добавили condition_type, но не добавили condition_script в вызов fillForm(). Результат: action_topic получает значение condition_duration (число), а action_payload — вообще что-то не то.

Причина 2: кавычки в JSON ломают HTML

Если в action_payload есть {"state": "ON"}, то при вставке в onclick без экранирования получается:

<a onclick="fillForm(..., "{\"state\": \"ON\"}", ...)">Ред.</a>

Браузер видит "{\" — и думает, что строка закончилась. Ошибка: Unexpected string.

Решение:

<?= htmlspecialchars(json_encode($value), ENT_QUOTES, 'UTF-8') ?>

Причина 3: функция fillForm() не загружается

Если PHP выдаёт ошибку до тега <script>, страница обрывается — и fillForm не определена.

Включайте отладку:

error_reporting(E_ALL);
ini_set('display_errors', 1);

И смотрите логи: tail -f /var/log/apache2/error.log.

3. Рабочий код: безопасная передача данных в JS

В цикле вывода правил:

<a href="#" onclick="fillForm(
    <?= htmlspecialchars(json_encode($rule['name']), ENT_QUOTES, 'UTF-8') ?>,
    <?= htmlspecialchars(json_encode($rule['condition_type']), ENT_QUOTES, 'UTF-8') ?>,
    <?= htmlspecialchars(json_encode($rule['trigger_topic']), ENT_QUOTES, 'UTF-8') ?>,
    <?= htmlspecialchars(json_encode($rule['condition_operator']), ENT_QUOTES, 'UTF-8') ?>,
    <?= htmlspecialchars(json_encode($rule['condition_value']), ENT_QUOTES, 'UTF-8') ?>,
    <?= htmlspecialchars(json_encode($rule['condition_script'] ?? ''), ENT_QUOTES, 'UTF-8') ?>,
    <?= (int)$rule['condition_duration'] ?>,
    <?= htmlspecialchars(json_encode($rule['action_topic']), ENT_QUOTES, 'UTF-8') ?>,
    <?= htmlspecialchars(json_encode($rule['action_payload']), ENT_QUOTES, 'UTF-8') ?>,
    /* ... остальные поля ... */
    <?= (int)$rule['id'] ?>
)">✏️ Ред.</a>

А в JS — чёткое соответствие аргументов:

function fillForm(
    name, condition_type, trigger_topic, condition_operator, condition_value, condition_script,
    condition_duration,
    action_topic, action_payload, confirmation_topic, confirmation_timeout, max_retries, retry_delay,
    delay_seconds, schedule_type, schedule_time, schedule_days_str, time_restriction_start, time_restriction_end,
    dependency_topic, dependency_value, enabled, id
) {
    document.querySelector("[name='name']").value = name;
    document.querySelector("[name='condition_type']").value = condition_type;
    document.querySelector("[name='condition_script']").value = condition_script;
    // ... и так далее ...
    document.getElementById('rule_id').value = id;
}

4. Альтернатива: отдельная страница редактирования

Если вам не нравится возиться с JS — сделайте edit_rule.php?id=123. Там:

$rule = $pdo->prepare("SELECT * FROM automations WHERE id = ?");
$rule->execute([$_GET['id']]);
$rule = $rule->fetch();
// Подставляете $rule['name'] прямо в value="" — никаких JSON/JS!

Это проще, безопаснее и не ломается при спецсимволах.

Заключение

Редактирование — это не «просто форма». Это баланс между:

Теперь ваши правила можно не только создавать, но и менять на лету — без перезагрузки сервера и без SSH.

Удачи в автоматизации! 🏠⚡

Обновленный скрипт добавления правил для автоматизации logic.php

Комментарии

Пока нет комментариев. Будьте первым!

Оставить комментарий

← Назад к списку статей

Важно: Блог-эксперимент

Блог только запустил, все статьи генерирую через нейросеть т.к. лень, возможны ошибки. Просто чтобы вы знали и не запускали ядерный реактор по моим статьям ))
Если у вас есть вопросы, или Нашли неточность? пишите в коментах — вместе поправим и сделаем статью более качественной. Я лично объясню нюансы из практики.

Посетителей сегодня: 0


кто я | книга | контакты

© Digital Specialist | Не являемся сотрудниками Google, Яндекса и NASA