Сигнализация на ESP32 - PullRequest
       39

Сигнализация на ESP32

1 голос
/ 03 июня 2019

Я использую ESP32, подключенный к Google Cloud IoT Core, для управления источниками света с Raspberry Pi в качестве концентратора для отправки сообщений на esp32 через ядро ​​IoT, чтобы включать и выключать их в установленное время дня.

Что я хочу сделать сейчас, так это просто устранить Raspberry Pi и настроить esp32, когда нужно включить или выключить их, но я не могу найти способ установить будильник или что-то вроде будильника, который срабатывает в определенное время дней.

Временное значение в миллисекундах от UTC

Существует ли что-то подобное или как я могу выполнить сигнализацию на esp32?

Ответы [ 2 ]

1 голос
/ 04 июня 2019

Я не знаю, используете ли вы ESP IDF или какую-то платформу Arduino для ESP32 (с которой я не знаком). Этот ответ для ESP IDF. Если вы не используете ESP-IDF и не имеете доступа к соответствующим заголовочным файлам и библиотекам, некоторые идеи все еще могут быть актуальны.

Активировать SNTP

Убедитесь, что часы на контроллере обновлены, следуя примеру SNTP на https://github.com/espressif/esp-idf/tree/master/examples/protocols/sntp.

Использование localtime()

Если вы используете ESP-IDF, у вас будет доступ к функции localtime_r(). Передайте это (указатель на) число «секунд с начала эпохи», которое возвращается time(NULL), и оно заполнит struct tm днем ​​недели, днем ​​месяца, часом, минутой и секундой.

Общая процедура (обработка ошибок пропущена) ...

#include <time.h>
// ...

struct tm now = {};
time_t tnow = time(NULL);
localtime_r(&tnow, &now);
// Compare current day, hour, minute, etc. against pre-defined alarms.

Примечание: вы можете использовать gmtime_r() вместо localtime_r(), если вы предпочитаете использовать UTC.

Вы можете периодически вызывать это из основного цикла while(), как описано ниже.

Сигнальные сооружения

Определите структуру для вашей информации о тревоге. Вы можете использовать что-то вроде следующего - настройка в соответствии с уровнем детализации, который вам нужен. Обратите внимание, что он включает элемент callback - для указания того, что программа должна делать при срабатывании тревоги.

typedef struct {
    int week_day;  // -1 for every day of week
    int hour;      // -1 for every hour
    int minute;    // -1 for every minute
    void (*callback)(void);
    void *callback_arg;
} alarm_t;

Определение сигналов тревоги и обратных вызовов

Определите ваш массив аварийных сигналов, функций обратного вызова и аргументов.

static void trigger_relay(const void *arg) {
    uint32_t num = *(uint32_t *)arg;
    printf("Activating relay %u ...\n", num);
    // Handle GPIO etc.
}

static uint32_t relay_1 = 0;
static uint32_t relay_2 = 1;

static alarm_t alarms[] = {
    // Trigger relay 1 at 9:00 on Sunday
    {0, 9, 0, trigger_relay, (void *)&relay_1},
    // Relay 2 at 7:30 every day
    {-1, 7, 30, trigger_relay, (void *)&relay_2},
};

Периодическое сканирование

Определите подпрограмму check_alarms(), которая загружает структуру struct tm с текущим временем и сравнивает ее с каждой из заданных вами аварийных сигналов. Если текущее время соответствует сигналу тревоги, вызывается обратный вызов.

static void check_alarms(void) {
    time_t tnow = time(NULL);
    struct tm now = {};
    localtime_r(&tnow, &now);
    ESP_LOGI(TAG, "Time: %u:%u:%u", now.tm_hour, now.tm_min, now.tm_sec);
    size_t n_alarms = sizeof(alarms) / sizeof(alarms[0]);
    for (int i = 0; i < n_alarms; i++) {
        alarm_t *alrm = &alarms[i];
        if (alrm->week_day != -1 && alrm->week_day != now.tm_wday) {
            continue;
        }
        if (alrm->hour != -1 && alrm->hour != now.tm_hour) {
            continue;
        }
        if (alrm->minute != -1 && alrm->minute != now.tm_min) {
            continue;
        }
        alrm->callback(alrm->callback_arg);
    }
}

Затем он будет вызываться из вашего основного while() контура с частотой, зависящей от степени детализации вашего сигнала тревоги. Поскольку alarm_t, определенный выше, имеет гранулярность 1 минуту, именно так я буду звонить check_alarms(). Этот пример предназначен для FreeRTOS, но может быть адаптирован при необходимости.

while (1) {
   TickType_t tick = xTaskGetTickCount();
   if (tick - g_time_last_check > pdMS_TO_TICKS(60000)) {
       g_time_last_check = tick;
       check_alarms();
   }
}

Эффективность * * тысяча пятьдесят-одна Вышеупомянутое не очень эффективно, если у вас много сигналов тревоги и / или каждый сигнал должен срабатывать с высокой частотой. В таком случае вы могли бы рассмотреть алгоритмы, которые сортируют сигналы тревоги по времени до истечения времени, и - вместо того, чтобы каждый раз перебирать весь массив, - вместо этого использовать программный таймер однократного запуска для вызова соответствующего обратного вызова. Это, вероятно, не стоит хлопот, если у вас очень много таймеров. Альтернативы

И FreeRTOS, и ESP-IDF включают API для программных таймеров - но их нельзя (легко) использовать для аварийных сигналов в определенное время дня - которое вы заявляете как требование С другой стороны, как вы, возможно, уже знаете, система ESP32 на кристалле имеет встроенный RTC, но я думаю, что лучше использовать интерфейс более высокого уровня, чем напрямую общаться с ним.

0 голосов
/ 04 июня 2019

A часы реального времени - это то, что вы ищете. Я никогда не работал с ESP32, но, видимо, у он есть, и он плохо . Тем не менее, 5% ошибка может быть достаточно для вас. Если это вариант, я бы использовал внешний.

...