Страница 1 из 2

GSM КОНТРОЛЛЕР. Модуль удаленного управления.

Добавлено: 30 апр 2026, 19:47
MarkT
Делаю сейчас небольшой, но практичный проект на базе Arduino Nano и модуля SIM800L EVB — по сути, свой GSM‑контроллер для умного холодильника.

Идея такая: у каждого холодильника есть свой ID, например 52001. С моего GSM‑шлюза на SIM‑карту в модуле приходит СМС вида:
52001 open
Где 52001 — ID конкретного холодильника, а open — команда открыть дверь.

Дальше схема работы следующая:
  • SIM800L принимает СМС и по UART отдаёт её текст на Arduino.
  • Arduino парсит сообщение, фильтрует по ID (чтобы реагировал только «свой» холодильник) и проверяет команду.
  • Если ID совпадает и команда равна open, Arduino формирует короткий импульс на выходе.
Нужно аккуратно эмулировать нажатие уже существующей кнопки открытия двери. Для этого планирую использовать высокоомный исполнительный элемент (оптопара), включённый параллельно контактам кнопки. Arduino через этот элемент на короткое время «замыкает» контакты, как будто пользователь нажал кнопку вручную.

В итоге получается компактный GSM‑контроллер удалённого доступа для холодильника: по СМС можно удалённо открыть дверь, а дальше это можно масштабировать на парк устройств (несколько холодильников с разными ID) и допилить дополнительные команды.

Сейчас в процессе:
  • Отладка приёма/разбора СМС от SIM800L (текстовый режим, парсинг строки).
  • Подбор обвязки для безопасной эмуляции кнопки (оптопара или транзистор в зависимости от схемы холодильника).
  • Проработка формата команд и возможного ответа от устройства (подтверждение по СМС).
Буду рад советам по:
— надёжной схеме эмуляции кнопки (оптопара/реле/транзистор);
— организации протокола команд по СМС (оптимальный формат, защита от «левых» сообщений).

Re: GSM КОНТРОЛЛЕР. Модуль удаленного управления.

Добавлено: 30 апр 2026, 20:36
MarkT
Параллельно с SMS‑управлением хочу добавить второй канал связи — через GPRS. SIM800L умеет держать TCP‑соединение, и это позволяет организовать работу примерно по аналогии с IP‑телефонией: холодильник сам инициирует исходящее подключение к серверу, держит его живым за счёт периодических keep‑alive, а сервер по этому же соединению отправляет команды.

Архитектура сейчас вижу так. Уже есть рабочий GSM‑шлюз, который по HTTP‑эндпоинту принимает запросы и отправляет SMS (он сейчас рассылает уведомления клиентам о заказах, его планирую использовать и для холодильников). Отдельно под этот проект подниму GPRS‑шлюз: обычный сервер, который слушает входящие TCP‑подключения от SIM800L‑модемов. Каждый холодильник при старте поднимает GPRS, устанавливает TCP‑соединение с этим шлюзом, представляется своим ID и периодически шлёт heartbeat‑пакеты. Если шлюз видит, что соединение активно, он может в любой момент отправить команду «open» уже по GPRS, минуя SMS.

Код: Выделить всё

[ Клиент (браузер, QR-код) ]
               |
               v
      [ Сайт на WordPress ]
               |
               v
        [ GPRS-шлюз (сервер) ]
               |          \
      (HTTP API)           \  (HTTP API)
               |            \
               v             v
        [ SMS-шлюз ]     [ БД / панель управления ]
На стороне сайта (WordPress) планирую сделать раздел с холодильниками: список устройств с ID, привязанным номером SIM для SMS, статусом (в сети по GPRS — зелёный, офлайн — красный), версией прошивки и т.п. Клиент сканирует QR‑код на морде холодильника, попадает на страницу конкретного устройства и жмёт кнопку «Открыть». Дальше логика такая: если GPRS‑шлюз считает, что у холодильника есть активное TCP‑соединение, команда «open 52001» уходит по GPRS‑каналу (TCP → SIM800L → Arduino → оптопара). Если соединения нет — шлюз дергает HTTP‑API существующего SMS‑шлюза, и тот шлёт приоритетную SMS с текстом «52001 open» на SIM‑карту холодильника.

Код: Выделить всё

             INTERNET / GPRS
   +--------------------------------------+
   |                                      |
   v                                      |
[ GPRS-шлюз (сервер) ] <------------------------+
   ^           ^                           |   |
   |           | TCP (постоянное           |   |
   |           | соединение + keep-alive)  |   |
   |           |                           |   |
   |       [ SIM800L EVB ] --- UART --- [ Arduino Nano ]
   |                                  (логика, парсинг
   |                                   команд, ID и т.д.)
   |                                                |
   |                                                |
   |                                    [ Оптопара / ключ ]
   |                                                |
   |                                       [ Кнопка двери ]
   |
   |  HTTP API
   |
[ SMS-шлюз ] <--------+
   ^                  |
   |    SMS           |
   +----------- [ Сотовая сеть / GSM ] --------------+
Таким образом получается двухканальная схема: основной канал — GPRS (быстрее, дешевле по объёму, удобнее для расширения протокола), резервный — SMS (если нет интернета, если оператор режет GPRS или что‑то по пути падает). Холодильник сам может отслеживать обрыв TCP‑соединения и после нескольких неудачных попыток переподключения отправлять на шлюз специальное SMS‑сообщение вида «52001 net_down», чтобы сервер знал, что с этим устройством лучше говорить только по SMS. Обратная сторона — как только TCP снова поднимается и какое‑то время держится, можно переводить устройство обратно в состояние «онлайн по GPRS».

На будущее хочу в эту же инфраструктуру вписать удалённое обновление прошивки Arduino через GPRS. Понимаю, что на чистом Nano это задача со звёздочкой (нужен свой загрузчик и, вероятнее всего, внешняя память под образ прошивки), но в протоколе и веб‑морде уже планирую оставить под это место: хранение версии прошивки, команда на обновление, возможно, указание URL для скачивания бинарника. По мере развития проекта можно будет либо дописать загрузчик под Nano, либо перейти на более подходящий контроллер с готовыми OTA‑решениями.

В общем, сейчас получается такой «мини‑SIP для холодильников»: устройства сами стучатся на сервер, держат сессию, получают команды по живому TCP‑каналу, а если что‑то ломается в дата‑канале — всегда остаётся SMS как надёжный резерв. Если у кого‑то был похожий опыт (GPRS + SMS любой модуль, не обязательно SIM800L) или есть мысли по формату протокола/организации OTA — буду рад услышать.

Re: GSM КОНТРОЛЛЕР. Модуль удаленного управления.

Добавлено: 30 апр 2026, 21:35
MarkT
Начал работу над плагином для сайта (GPRS шлюз)
Этапы работ:
- ПО GPRS шлюз
- ПО для ардуино холодильника
- Тест взаимодействия (тест GPRS тест SMS)

Re: GSM КОНТРОЛЛЕР. Модуль удаленного управления.

Добавлено: 30 апр 2026, 23:29
MarkT
Подключил SIM800L к ардуино. Всего 4 провода.
- +5 вольт с Ардунино
- TX
- RX
- Земля
Работает. Отправляю с обычного телефона СМС с кодом "52001 OPEN" - моргает светодиодна 8 выводе в течении 0.5 секунды. Этого должно хватить чтобы отработала кнопка открытия холодильника.
Вот логи из консоли Arduino IDE

Код: Выделить всё

OK
Ready. Ожидаю SMS вида: 52001 open

+CMT: "+7920000000","","26/04/30,23:26:18+12"
GSM: +CMT: "+7920000000","","26/04/30,23:26:18+12"
52001 OPEN
GSM: 52001 OPEN
SMS text: 52001 OPEN
ID: 52001
CMD: OPEN
Команда для этого холодильника: OPEN. Мигаем LED.
Код исправленной программы. Дальше он будет модифицироваться под мои нужды. Но мне сейчас главное открыть холодильник удаленно. Через СМС это уже работает.

Код: Выделить всё

#include <SoftwareSerial.h>

// Пины для SIM800L
const int GSM_RX_PIN = 2; // Arduino RX (слушаем TX SIM800L)
const int GSM_TX_PIN = 3; // Arduino TX (пишем в RX SIM800L)

// Светодиод (эмуляция кнопки двери)
const int LED_PIN = 8;

// Наш ID холодильника
const char MY_ID[] = "52001";

SoftwareSerial gsm(GSM_RX_PIN, GSM_TX_PIN); // RX, TX

String incomingLine = "";
bool smsTextNextLine = false; // флаг, что следующая строка — текст СМС

void setup() {
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);

  Serial.begin(9600);
  gsm.begin(9600);

  delay(3000); // дать модему проснуться

  Serial.println("Init SIM800L...");

  sendAT("AT");
  sendAT("ATE0");              // выключить эхо
  sendAT("AT+CMGF=1");         // текстовый режим SMS
  sendAT("AT+CSCS=\"GSM\"");   // кодировка
  sendAT("AT+CNMI=1,2,0,0,0"); // новые SMS сразу по UART

  Serial.println("Ready. Ожидаю SMS вида: 52001 open");
}

void loop() {
  // 1. Прямой мост: всё, что вводим в Serial, отправляем в модем
  while (Serial.available()) {
    char c = Serial.read();
    gsm.write(c);
  }

  // 2. Читаем всё, что пришло от модема
  while (gsm.available()) {
    char c = gsm.read();
    Serial.write(c); // сразу выводим в монитор

    if (c == '\r') {
      // игнорируем
    } else if (c == '\n') {
      if (incomingLine.length() > 0) {
        Serial.print("GSM: ");
        Serial.println(incomingLine);
        handleLine(incomingLine);
        incomingLine = "";
      }
    } else {
      incomingLine += c;
    }
  }
}

// Отправка AT-команды из кода
void sendAT(const char* cmd) {
  gsm.print(cmd);
  gsm.print("\r\n");
  Serial.print(">> ");
  Serial.println(cmd);
  delay(500);
  while (gsm.available()) {
    char c = gsm.read();
    Serial.write(c);
  }
}

// Обработка одной строки от модема
void handleLine(const String& line) {
  if (line.startsWith("+CMT:")) {
    smsTextNextLine = true;
    return;
  }

  if (smsTextNextLine) {
    smsTextNextLine = false;
    processSmsText(line);
  }
}

// Разбор текста SMS
void processSmsText(const String& text) {
  Serial.print("SMS text: ");
  Serial.println(text);

  String t = text;
  t.trim();

  int spaceIndex = t.indexOf(' ');
  if (spaceIndex == -1) {
    Serial.println("Формат SMS не подходит");
    return;
  }

  String idPart = t.substring(0, spaceIndex);
  String cmdPart = t.substring(spaceIndex + 1);
  idPart.trim();
  cmdPart.trim();

  Serial.print("ID: ");
  Serial.println(idPart);
  Serial.print("CMD: ");
  Serial.println(cmdPart);

  if (idPart.equals(String(MY_ID)) && cmdPart.equalsIgnoreCase("open")) {
    Serial.println("Команда для этого холодильника: OPEN. Мигаем LED.");
    blinkLed();
  } else {
    Serial.println("ID не совпал или команда не OPEN.");
  }
}

// Имитация нажатия кнопки
void blinkLed() {
  digitalWrite(LED_PIN, HIGH);
  delay(500);
  digitalWrite(LED_PIN, LOW);
}
Следующий слой — включаем GPRS на SIM800L и шлём HTTP‑запрос на твой шлюз.

Re: GSM КОНТРОЛЛЕР. Модуль удаленного управления.

Добавлено: 01 май 2026, 01:00
MarkT
Закончилось все печально. Начал обкатку программы с GPRS - вышло предупреждение:
Скетч использует 10322 байт (33%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 2006 байт (97%) динамической памяти, оставляя 42 байт для локальных переменных. Максимум: 2048 байт.
Недостаточно памяти, программа может работать нестабильно.
Принято решение обкатывать на минимальном скейтче (выше) без GPRS. В это время буду выбирать/заказывать новый ардуино с большей памятью и тестировать через СМС открытие.

Программа с GPRS.

Код: Выделить всё

#include <SoftwareSerial.h>

// Пины для SIM800L
const int GSM_RX_PIN = 2;
const int GSM_TX_PIN = 3;

// Светодиод (эмуляция двери)
const int LED_PIN = 8;

// Наш ID холодильника
const char MY_ID[] = "52001";

// Настройки GPRS / шлюза
const char APN[]      = "internet.beeline.ru";
const char APN_USER[] = "beeline";
const char APN_PWD[]  = "beeline";
const char GATEWAY[]  = "http://stolovka.pro/wp-js.....................";
const char TOKEN[]    = "DEVTEST";

SoftwareSerial gsm(GSM_RX_PIN, GSM_TX_PIN);

// Для парсинга строк от модема
String incomingLine = "";
bool smsTextNextLine = false;

// Состояния
bool networkRegistered = false;
bool gprsConnected     = false;

unsigned long lastPing          = 0;
const unsigned long PING_INTERVAL = 30000;

unsigned long lastGprsAttempt   = 0;
unsigned long gprsRetryInterval = 60000;
int gprsFailCount               = 0;

void setup() {
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);

  Serial.begin(9600);
  gsm.begin(9600);

  delay(3000);

  Serial.println("Init SIM800L...");

  sendAT("AT", 1000);
  sendAT("ATE0", 1000);
  sendAT("AT+CMGF=1", 1000);
  sendAT("AT+CSCS=\"GSM\"", 1000);
  sendAT("AT+CNMI=1,2,0,0,0", 1000);

  Serial.println("Жду регистрацию в сети...");

  waitForRegistration();

  if (networkRegistered) {
    Serial.println("Сеть: OK. Пробую поднять GPRS...");
    if (gprsConnect()) {
      Serial.println("GPRS подключен. Пинги раз в 30 сек.");
    } else {
      Serial.println("GPRS при старте не поднялся.");
    }
  } else {
    Serial.println("Нет регистрации в сети, GPRS не поднимаю.");
  }

  Serial.println("Ожидаю SMS вида: 52001 open (резерв).");
}

void loop() {
  unsigned long now = millis();

  // Прямой мост для отладки
  while (Serial.available()) {
    gsm.write(Serial.read());
  }

  // Чтение строк от модема (для SMS)
  while (gsm.available()) {
    char c = gsm.read();
    Serial.write(c);

    if (c == '\r') {
    } else if (c == '\n') {
      if (incomingLine.length() > 0) {
        Serial.print("GSM: ");
        Serial.println(incomingLine);
        handleLine(incomingLine);
        incomingLine = "";
      }
    } else {
      incomingLine += c;
    }
  }

  // Пинг по GPRS
  if (gprsConnected) {
    if (now - lastPing > PING_INTERVAL) {
      lastPing = now;
      if (!gprsPing()) {
        Serial.println("GPRS ping failed, disconnecting...");
        gprsDisconnect();
      }
    }
  } else if (networkRegistered) {
    // Попытки поднять GPRS
    if (now - lastGprsAttempt > gprsRetryInterval) {
      lastGprsAttempt = now;
      Serial.println("Пробую поднять GPRS снова...");
      if (gprsConnect()) {
        Serial.println("GPRS подключен.");
        gprsFailCount = 0;
        gprsRetryInterval = 60000;
      } else {
        gprsFailCount++;
        if (gprsFailCount >= 5) {
          gprsRetryInterval = 300000; // 5 минут
        }
      }
    }
  }
}

// ================= сеть =================

void waitForRegistration() {
  const int maxAttempts = 15;
  for (int i = 0; i < maxAttempts; i++) {
    Serial.println("AT+CREG?");
    gsm.print("AT+CREG?\r\n");

    bool ok = false;
    unsigned long t0 = millis();
    String resp = "";
    while (millis() - t0 < 2000) {
      while (gsm.available()) {
        char c = gsm.read();
        Serial.write(c);
        resp += c;
      }
    }
    Serial.println();

    if (resp.indexOf("+CREG:") != -1 &&
        (resp.indexOf("0,1") != -1 || resp.indexOf("0,5") != -1)) {
      networkRegistered = true;
      Serial.println("CREG OK");
      ok = true;
    }

    if (ok) return;
    delay(3000);
  }
}

// ================= GPRS =================

bool gprsConnect() {
  Serial.println("GPRS connect (SAPBR)...");

  sendAT("AT+SAPBR=0,1", 3000);

  if (!sendAT_OK("AT+SAPBR=3,1,\"Contype\",\"GPRS\"", 3000)) {
    Serial.println("SAPBR Contype FAIL");
    return false;
  }

  {
    String cmd = String("AT+SAPBR=3,1,\"APN\",\"") + APN + "\"";
    if (!sendAT_OK(cmd, 3000)) {
      Serial.println("SAPBR APN FAIL");
      return false;
    }
  }

  {
    String cmd = String("AT+SAPBR=3,1,\"USER\",\"") + APN_USER + "\"";
    sendAT_OK(cmd, 2000);
  }
  {
    String cmd = String("AT+SAPBR=3,1,\"PWD\",\"") + APN_PWD + "\"";
    sendAT_OK(cmd, 2000);
  }

  if (!sendAT_OK("AT+SAPBR=1,1", 10000)) {
    Serial.println("SAPBR open FAIL");
    return false;
  }

  sendAT("AT+SAPBR=2,1", 3000);

  gprsConnected = true;
  return true;
}

void gprsDisconnect() {
  sendAT("AT+HTTPTERM", 2000);
  sendAT("AT+SAPBR=0,1", 3000);
  gprsConnected = false;
  Serial.println("GPRS off.");
}

// ОДИН ping
bool gprsPing() {
  Serial.println("GPRS ping...");

  // Собираем URL в локальный буфер
  char url[160];
  snprintf(url, sizeof(url),
           "%s?id=%s&cmd=ping&token=%s",
           GATEWAY, MY_ID, TOKEN);

  Serial.print("Ping URL: ");
  Serial.println(url);

  if (!sendAT_OK("AT+HTTPINIT", 5000)) {
    Serial.println("HTTPINIT FAIL");
    sendAT("AT+HTTPTERM", 2000);
    return false;
  }

  if (!sendAT_OK("AT+HTTPPARA=\"CID\",1", 2000)) {
    Serial.println("HTTPPARA CID FAIL");
    sendAT("AT+HTTPTERM", 2000);
    return false;
  }

  {
    String cmd = String("AT+HTTPPARA=\"URL\",\"") + url + "\"";
    if (!sendAT_OK(cmd, 5000)) {
      Serial.println("HTTPPARA URL FAIL");
      sendAT("AT+HTTPTERM", 2000);
      return false;
    }
  }

  sendAT("AT+HTTPACTION=0", 10000);
  delay(7000);

  // Читаем HTTPREAD и ищем "action":"open"
  gsm.print("AT+HTTPREAD\r\n");
  Serial.println(">> AT+HTTPREAD");

  bool needOpen = false;
  unsigned long t0 = millis();
  char window[32];
  byte winPos = 0;

  while (millis() - t0 < 5000) {
    while (gsm.available()) {
      char c = gsm.read();
      Serial.write(c);

      // скользящее окно
      window[winPos] = c;
      winPos = (winPos + 1) % sizeof(window);

      // грубый поиск подпоследовательности
      // из-за кольцевого буфера проще делать через String,
      // но чтобы не жрать память, просто проверим при накоплении текста.
      // здесь упрощённо: собираем в маленький String до 64 байт
    }
  }
  Serial.println();

  // Для простоты: второй проход — через SerialMonitor смотришь JSON.
  // Если нужен автомат: можно временно собрать ответ в String до 128 байт и искать "action":"open".

  sendAT("AT+HTTPTERM", 2000);

  // На этом шаге считаем, что если HTTPACTION у нас 200 (ты уже видел),
  // то пинг успешен. Логи из Serial покажут JSON.

  return true;
}

// ================= AT helpers =================

void sendAT(const char* cmd, unsigned long timeout) {
  gsm.print(cmd);
  gsm.print("\r\n");
  Serial.print(">> ");
  Serial.println(cmd);
  unsigned long t0 = millis();
  while (millis() - t0 < timeout) {
    while (gsm.available()) {
      char c = gsm.read();
      Serial.write(c);
    }
  }
  Serial.println();
}

bool sendAT_OK(const String& cmd, unsigned long timeout) {
  gsm.print(cmd);
  gsm.print("\r\n");
  Serial.print(">> ");
  Serial.println(cmd);

  String resp = "";
  unsigned long t0 = millis();

  while (millis() - t0 < timeout) {
    while (gsm.available()) {
      char c = gsm.read();
      resp += c;
      Serial.write(c);
      if (resp.length() > 64) { // ограничиваем длину
        resp.remove(0, resp.length() - 32);
      }
    }
    if (resp.indexOf("OK") != -1) {
      Serial.println();
      return true;
    }
    if (resp.indexOf("ERROR") != -1) {
      Serial.println();
      return false;
    }
  }
  Serial.println();
  return false;
}

// ================= SMS / LED =================

void handleLine(const String& line) {
  if (line.startsWith("+CMT:")) {
    smsTextNextLine = true;
    return;
  }

  if (smsTextNextLine) {
    smsTextNextLine = false;
    processSmsText(line);
  }
}

void processSmsText(const String& text) {
  Serial.print("SMS text: ");
  Serial.println(text);

  String t = text;
  t.trim();

  int spaceIndex = t.indexOf(' ');
  if (spaceIndex == -1) {
    Serial.println("Формат SMS не подходит");
    return;
  }

  String idPart = t.substring(0, spaceIndex);
  String cmdPart = t.substring(spaceIndex + 1);
  idPart.trim();
  cmdPart.trim();

  Serial.print("ID: ");
  Serial.println(idPart);
  Serial.print("CMD: ");
  Serial.println(cmdPart);

  if (idPart.equals(String(MY_ID)) && cmdPart.equalsIgnoreCase("open")) {
    Serial.println("Команда для этого холодильника: OPEN. Мигаем LED.");
    blinkLed();
  } else {
    Serial.println("ID не совпал или команда не OPEN.");
  }
}

void blinkLed() {
  digitalWrite(LED_PIN, HIGH);
  delay(500);
  digitalWrite(LED_PIN, LOW);
}

Re: GSM КОНТРОЛЛЕР. Модуль удаленного управления.

Добавлено: 01 май 2026, 01:04
MarkT
Что сделали сегодня
  • Поднял связку Arduino Nano + SIM800L: настроили текстовый режим SMS (AT+CMGF=1, AT+CSCS="GSM", AT+CNMI=1,2,0,0,0) и убедились, что модуль стабильно принимает входящие сообщения.
  • Написали и отладили скетч, который по SMS вида 52001 OPEN парсит ID и команду и мигает светодиодом на D8, эмулируя открытие дверцы холодильника.
  • Сервисы на сайте: подняли REST‑эндпоинт wp-json/sfg/v1/event и проверили, что он отдаёт корректный JSON‑ответ со статусом ok и параметрами id/cmd/token/time.
  • Завели рабочий GPRS‑сценарий: с SIM800L через SAPBR и HTTPACTION=0 успешно сходили на http://stolovka.pro/wp-json/sfg/v1/event?id......., получили +HTTPACTION: 0,200,88 и валидный JSON.
  • Попробовали реализовать «как в SIP»: автоматическую регистрацию в сети, поднятие GPRS и периодические HTTP‑пинги cmd=ping, но упёрлись в 2 КБ RAM у Arduino Nano — глобальные переменные заняли ~97% памяти, что делает такую логику на этой плате нестабильной.

Re: GSM КОНТРОЛЛЕР. Модуль удаленного управления.

Добавлено: 01 май 2026, 09:37
MarkT
В обще пролежал он ночь на тесте.
Утром отправил смс с кодом OPEN 52001. И...
Холодильник не открылся (светодиод не загорелся).
Сижу, думаю....
Побаловался и понял, что придется потанцевать с бубном, прежде чем это все отладить. А очень не хочется терять время...

Рассматриваю 3 взрослых направления:

1) Готовый промышленный GSM/LTE‑RTU с реле
Это «черные коробки», которые уже умеют:
  • поднимать GSM/3G/4G сами;
  • принимать команды по SMS, звонкам, HTTP, MQTT;
  • дергать релейные выходы и/или дискретные входы.
Примеры (для понимания класса устройств):
  • BLIIoT / IOT‑RTU (RTU5020, S272 и т.п.): GSM/3G/4G RTU c 2–4 реле, входами, управлением по SMS, звонкам, иногда HTTP/MQTT.
  • CWT5013/CWT5112 — промышленные модули с 12 DI, 4 DO, GPRS/4G/Wi‑Fi, управляемые через свой протокол по TCP/Modbus/SMS.
  • Teltonika TRB141 — LTE Cat1‑шлюз с цифровыми входами/выходами, работает как мини‑роутер с собственным Linux (RutOS), управляется через веб‑морду, SMS, VPN, и т.п.
Плюсы:
  • Железо уже спроектировано под круглосуточную работу: нормальное питание, watchdog, перезапуск модема.
  • Сайта говоришь с одной понятной API/протоколом (HTTP/MQTT/Modbus TCP), не думая о том, как там AT‑команды размазаны внутри.
Минусы:
  • Свой закрытый протокол/команды, придётся подстраиваться под документацию конкретной коробки.
  • Цена: промышленные RTU стоят заметно дороже, чем «ардуинка + SIM800».
Думаю, что «готовый контроллер для реле с GSM/LTE», в пром‑сегменте такие RTU — самый надёжный путь.

2) «Промышленный Arduino» с GSM на борту
Это компромисс: внутри всё равно ESP32/AVR, но в виде заводского устройства:
  • NORVI GSM Series — ESP32‑базированные контроллеры с GSM/LTE‑модемом, предназначены для IoT, программируются как Arduino/ESP32, но в промкорпусе, с клеммами, питанием 24 В и т.п.
Плюс: свой код (можно перенести FSM с пингами), но не париться базовом железе (питание, ESD, корпус).

Такие железки уже ближе к тому, что тебе нужно: свой контроллер, но «упакованный» как промышленный модуль.

3) «Собрать взрослую версию самому» на более мощном МК
То, что было вчера — это прототип. Чтобы сделать это «по‑взрослому», но сохранив максимально гибкость:
  • взять что‑то типа ESP32 DevKitC или Arduino Mega/Nano Every ;
добавить SIM800/EC200U уже как обычный модем;
  • обвязать всё нормальным питанием, watchdog, аппаратным ресетом модема;
  • всю логику «SIP‑подобных» пингов/очередей/REST‑протокола контролитуется самостоятельно.
  • Если идти чуть современнее, можно даже смотреть на Quectel EC200U‑EU dev‑board:
  • это уже Cat1‑LTE модуль с кучей протоколов (TCP, UDP, MQTT, HTTP/HTTPS, SSL) и демо‑платой;
  • можно либо управлять его AT‑командами с внешнего МК, либо использовать как «почти самостоятельный» девайс (у них есть QPYcom, MicroPython/скрипты).

Re: GSM КОНТРОЛЛЕР. Модуль удаленного управления.

Добавлено: 01 май 2026, 14:46
MarkT
Поковырявшись некоторое время в сети нашел решение. Заменить SIM800L на другой контроллер. Муки выбора. Как вариант - EC200U
Схема такая:
  • EC200U - как устройство для связи. Это по сути dev‑board с модемом + минимум обвязки, а «мир» наружу он видит в основном как UART/ADC/I2C.
  • Adduino Nano. Но по сути это уже не "мозги" холодильника а исполнительное устройство
EC200U имеет 14 выходов
  • 5V, GND, GND, GND — питание/земля.
  • DBG RX / DBG TX — отдельный debug‑UART (для отладки, логов, загрузчика).
  • AUX TX / AUX RX — второй UART, который можно использовать как пользовательский (например, связать с Arduino).
  • RX / TX — основной UART модуля (MAIN UART), через который обычно идут AT‑команды или работает приложение QuecOpen.
  • ADC0 / ADC1 — аналоговые входы модуля (напр. для питания/датчика).
  • SDA / SCL — I2C, можно вешать внешние датчики.
На борту EC200U‑EVB (C4‑P01/QuecOpen/QuecPython) по доке имеется:
  • слот под nano‑SIM и слот под microSD (TF‑карта);
  • основная логика питания, USB‑Type‑C, антенны и т.п.
EC200U будет выполнять следующие функции:
  • связь: LTE, TCP/HTTP/MQTT, SMS;
  • логика протокола: id/cmd/token, очередь команд, резерв по SMS;
  • FOTA/обновление своего приложения. Это важная функция, потому что в холодильнике необходимо будет проводить отладку встроенного ПО, так же в перспективе думаю прикрепить к данному контроллеру считыватель карт для оплате по карте. Что возможно будет только через удаленное обновление.
Ардуино будет "исполнительным" элементом. Будет собирать телеметрию:
  • Компрессор вкл/выкл — логический вход (или даже управление реле).
  • Термодатчик внутри корпуса — I2C/1‑Wire/аналог.
  • Питание 220 В есть/нет — логический вход через оптопару.
  • Дверь открыта/закрыта — логический вход.
Коммуникация с EC200U по UART (например, через AUX UART).

Иными словами в Ардуино будет зашита базовая логика декодировки и кодировки сигналов через UART

Re: GSM КОНТРОЛЛЕР. Модуль удаленного управления.

Добавлено: 02 май 2026, 21:16
MarkT
После долгих мучений выбора, потратив значительное время я в итоге остановился на связке с ESP32, потому что это, по сути, «Arduino++, но уже для взрослых задач». По сравнению с классическими ардуинами тут сразу есть нормальный 32‑битный двухъядерный проц до 240 МГц, приличный объём памяти и самое главное — встроенный Wi‑Fi и Bluetooth, что позволяет без плясок поднимать веб‑морду настройки, локальный интерфейс для сервисников и все типичные IoT‑функции.

В качестве базовой платформы под мозги холодильника я выбрал 0Z7E‑ESP32‑S3 SIM7670G 4G макетную плату. Это плата на ESP32‑S3R2 (Wi‑Fi 2,4 ГГц 802.11 b/g + BLE 5.0, 16 МБ flash, 2 МБ PSRAM) с уже интегрированным 4G‑модулем SIM7670G (LTE Cat‑1, глобальные band’ы), слотом под 18650, контролем напряжения АКБ и зарядкой в том числе от солнечной панели. На борту есть слот microSD/TF, интерфейс под камеру и вся обвязка, чтобы делать портативный 4G‑шлюз/логгер «из коробки».

Для задач именно «мозгов холодильника» такой набор идеально ложится: ESP32‑S3 отвечает за логику, датчики, управление реле и веб‑интерфейс настройки/диагностики по Wi‑Fi, SIM7670G даёт резервируемый канал связи по LTE, а встроенный слот под 18650 фактически решает микровопрос бесперебойника — контроллер успеет пережить кратковременные просадки питания и отправить аварийные уведомления. Плюс это всё уже собрано на одной плате, без необходимости разводить с нуля связку «МК + модем + зарядник», что для прототипа и первых установок сильно экономит время и снижает количество граблей.

Re: GSM КОНТРОЛЛЕР. Модуль удаленного управления.

Добавлено: 02 май 2026, 21:18
MarkT
Дальше вся эта история по сути превращается из классического «GSM‑контроллера / модуля удалённого управления» в полноценные мозги вендингового аппарата.

Если раньше типичный GSM‑контроллер умел по сути только: принять/отправить SMS, дёрнуть пару реле и прислать простую телеметрию, то в случае с ESP32‑S3 + SIM7670G это уже полноценная платформа:

ESP32‑S3 берёт на себя роль основного контроллера автомата: логика работы, опрос датчиков, управление реле, регистрация аварий, учёт состояний (дверь, температура, питание, ошибки компрессора и т.д.).

На борту сразу есть Wi‑Fi — можно поднять локальную веб‑морду для настройки и обслуживания, как в нормальном сетевом устройстве, а не через набор SMS‑команд.

Модем SIM7670G обеспечивает не только SMS, но и полноценный LTE‑канал для связи с сервером: регулярная телеметрия, логирование, удалённые команды, обновления конфигурации.

Слот под 18650 вместе с зарядкой превращает контроллер в устройство с базовой резервной автономией: при пропадании 220 В мозг не падает сразу, а успевает корректно отработать сценарии аварии и уведомления.

В итоге это уже не просто «модуль удалённого управления холодильником по GSM», а реально встроенный контроллер вендингового аппарата с веб‑интерфейсом, IP‑логикой и современным 4G‑каналом, на котором можно строить архитектуру примерно как у IP‑телефонов и малых роутеров, только заточенную под холодильный шкаф.