Категории

Как я переделал логику расписания в своём IoT-движке, чтобы правила не пропускались

2025-12-08 09:35:51 | Статья из категории: IOT умный дом

У меня есть самописный движок автоматизации для IoT на PHP + MySQL + MQTT. Он умеет запускать действия по расписанию — например, включать фильтр в аквариуме в 8:00 и выключать в 23:00.

Раньше логика была простой: каждые 10 секунд скрипт проверял, совпадает ли текущее время (H:i) со временем в правиле. Потом я добавил поддержку секунд — стал сравнивать H:i:s — и стал создавать правила вроде:

Вроде всё логично. Но однажды ночью фильтр не выключился. Почему?

Проблема: точное совпадение по секунде — ненадёжно

Мой цикл работает с sleep(5) (а потом я уменьшил до sleep(1)). Но даже при проверке раз в секунду:

А так как условие было строгое — if (текущее_время === правило.время) — правило не срабатывало. Никогда.

Решение: «время настало или прошло» + защита от повторов

Я переделал логику. Теперь вместо точного совпадения используется условие:

«Если текущее время больше или равно заданному, и правило ещё не выполнялось сегодня — запустить его один раз».

Для этого я использую уже существующее поле в таблице automationslast_triggered (тип TIMESTAMP).

Алгоритм:

  1. Получаю текущее время в формате H:i:s и дату Y-m-d.
  2. Сравниваю: если (текущее_время >= правило.время)
  3. И проверяю: если дата(last_triggered) != сегодня
  4. Если оба условия верны — выполняю действие и обновляю last_triggered = NOW()

Теперь даже если скрипт проверит правило в 23:00:03 — условие '23:00:03' >= '23:00:00' истинно, и фильтр выключится. А повторного запуска не будет, потому что last_triggered уже обновлён на сегодняшнюю дату.

Плюсы такого подхода

Что делать, если у вас похожая система?

Если вы пишете свой IoT-планировщик на PHP (или любом другом языке) — никогда не полагайтесь на точное совпадение по секунде. Всегда используйте «окно срабатывания» и механизм защиты от повторов.

Это особенно критично для задач, которые должны выполниться один раз в сутки (выключение насосов, полив, обогрев и т.д.).

Вариант 1: использовать поле last_triggered (без изменения БД)

В таблице automations уже есть колонка:

last_triggered TIMESTAMP NULL COMMENT 'Когда последний раз сработало'

Её достаточно для отслеживания выполнения за день:

$lastDate = $rule['last_triggered']
  ? date('Y-m-d', strtotime($rule['last_triggered']))
  : null;
$today = date('Y-m-d');

if ($currentTime >= $ruleTime && $lastDate !== $today) {
    handleAction($rule);
    // last_triggered обновится автоматически в handleAction()
}

Плюсы: не требует ALTER TABLE, использует уже существующую логику обновления времени срабатывания.

Минусы: если last_triggered используется где-то ещё (например, для статистики), возможна коллизия по смыслу — но в вашем случае это маловероятно.

Вариант 2: добавить отдельное поле last_triggered_date

Можно создать специальную колонку только для даты:

ALTER TABLE automations ADD COLUMN last_triggered_date DATE NULL
  COMMENT 'Дата последнего срабатывания (для daily-правил)';

Тогда проверка становится проще и семантически чище:

$today = date('Y-m-d');
if ($currentTime >= $ruleTime &&
    ($rule['last_triggered_date'] !== $today || is_null($rule['last_triggered_date']))) {
    handleAction($rule);
    $pdo->prepare("UPDATE automations SET last_triggered_date = ? WHERE id = ?")
        ->execute([$today, $rule['id']]);
}

Плюсы: чёткое разделение ответственности — last_triggered для точного времени, last_triggered_date для защиты от повторов.

Минусы: нужно изменять структуру БД, что может быть нежелательно в продакшене без миграций.

Что дальше?

Позже я планирую добавить поддержку временных зон и более сложных расписаний (например, «каждые 30 минут с 8 до 22»), но базовая логика останется той же: «настало или прошло» + «ещё не делали сегодня».

Надёжность важнее эстетики точного времени.

Комментарии

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

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

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

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

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

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


кто я | книга | контакты без контактов

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