Привет, хомасистенты! 👋 Если вы читали мою первую статью (там старый код) о том, как я построил свой собственный IoT-ассистент на Raspberry Pi без Home Assistant, то знаете — мы уже умеем слушать MQTT, записывать показания датчиков и запускать действия по простым правилам вроде:
Если температура > 25 → включить вентилятор
Но… что если нужно что-то сложнее? Например:
Стандартные операторы >
, ==
— это как молоток. А нам нужен фрезерный станок.
Я решил: «Почему бы не позволить пользователю писать условие как маленькое JavaScript-выражение?»
Теперь в интерфейсе управления автоматизациями появился новый режим:
temperature > 25
sensor.temperature > 24 && sensor.humidity < 60 && sensor.window === 'closed'
Пользователь выбирает тип — и либо вводит стандартное сравнение, либо пишет выражение, которое вычисляется на сервере.
Вот фрагмент формы в PHP-админке:
<select name="condition_type" onchange="toggleConditionType(this.value)">
<option value="simple">Простое (A > B)</option>
<option value="script">Скрипт (JS-выражение)</option>
</select>
<div id="scriptCondition" style="display:none;">
<textarea name="condition_script" rows="4" placeholder="
// Примеры:
sensor.temperature > 24 && sensor.humidity < 60
Object.values(sensor).filter(v => v > 20).length >= 3
sensor.motion_1 || sensor.motion_2
"></textarea>
</div>
Интерфейс переключается динамически — всё просто, без JS-фреймворков.
Первое, что приходит в голову — eval()
. Но это смертельно опасно в веб-интерфейсе. Даже один неверный символ — и кто-то может удалить всю систему.
Мой подход: не исполнять код, а безопасно вычислять выражение.
eval()
в чистом виде, а файл-интерпретатор, который автоматически удаляется. Это гораздо безопаснее, чем eval().
Вот как я реализовал это в PHP (внутри /admin/logic.php
):
// Безопасный интерпретатор условий
function evaluateScriptCondition($script, $sensorData) {
// Заменяем sensor.xxx на массив
$script = preg_replace('/\bsensor\.([a-zA-Z0-9_]+)\b/', '$sensorData[\'$1\']', $script);
$script = str_replace('data', '$data', $script);
// Проверка на допустимые символы (защита от инъекций)
if (!preg_match('/^[a-zA-Z0-9_\[\]\.\(\)\+\-\*\/\!\&\|\s\=\>\<\,\{\}\'\"]+$/', $script)) {
throw new Exception("Недопустимые символы");
}
// Запрещённые слова
$forbidden = ['eval', 'exec', 'system', 'shell_exec', 'include', 'require'];
foreach ($forbidden as $word) {
if (stripos($script, $word) !== false) {
throw new Exception("Запрещённая функция: " . $word);
}
}
// Создаём временный файл для безопасного выполнения
$tmpFile = sys_get_temp_dir() . '/eval_' . uniqid() . '.php';
file_put_contents($tmpFile, "getMessage());
}
unlink($tmpFile); // Автоматическое удаление!
return (bool)$result;
}
Это работает так:
sensor.temperature > 24 && sensor.humidity < 60
sensor.temperature
на $sensorData['temperature']
return ($sensorData['temperature'] > 24 && $sensorData['humidity'] < 60);
include
— это безопасно, потому что он генерируется только из проверенных символовНикаких внешних вызовов. Ни одного eval()
. Только математика и логика.
Вот что можно написать прямо в поле скрипта:
// Условие 1: Все три датчика должны быть активны
sensor.movement_kitchen || sensor.movement_hall || sensor.movement_bedroom
// Условие 2: Средняя температура за 3 датчика > 22
(Object.values(sensor).filter(v => typeof v === 'number').reduce((a,b) => a + b, 0) / Object.values(sensor).filter(v => typeof v === 'number').length) > 22
// Условие 3: Температура > 25 ИЛИ влажность > 70 И окно открыто
sensor.temperature > 25 || (sensor.humidity > 70 && sensor.window === 'open')
// Условие 4: За последние 5 минут было больше 3 событий движения (если есть история)
sensor.motion_count_5m > 3
Да, это почти полноценный язык. И всё это — в одной строке, без Python, без Node.js, без Docker.
Сейчас система работает, но я уже думаю о расширениях:
history.get('temperature', '10m')
— доступ к последним даннымMath.max()
, Math.min()
, Array.filter()
rule.light_on.enabled
)Всё это — в рамках одного файла PHP. Никаких сторонних зависимостей. Только мой Raspberry Pi, MQTT и немного креатива.
Многие говорят: «Зачем самому делать, когда есть Home Assistant?»
А я отвечаю: потому что я хочу понимать, как всё работает внутри.
Когда я добавляю новое условие — я не кликаю в UI, я пишу выражение. Когда оно работает — я знаю, почему. Когда не работает — я могу отладить его за 2 минуты, потому что я создал эту систему с нуля.
Это не просто «умный дом». Это мой дом, мой код, моя логика.
И да — это круто.
Внимание: Cтатьи здесь сгенерированны через нейросеть, не правил ошибки, да и не до этого пока. Блог только запустил. Просто чтобы вы знали и не запускали ядерный реактор по моим статьям ))
НО!
Каждый кейс я делал минимум один раз. Сервера стоят, клиенты довольны, дата-центры не горят.
Если у вас есть вопросы, или Нашли неточность? пишите в коментах —
вместе поправим и сделаем статью более качественной. Я лично объясню нюансы из практики.
Комментарии
Пока нет комментариев. Будьте первым!