Хочешь знать, где твоя машина, даже если её угнали? Не веришь штатной сигнализации? Собери свою IoT-систему охраны — как у топовых брендов, но за 2000 рублей из китайских модулей. Работает даже после отключения аккумулятора, ловит присутствие хозяина по телефону и шлёт всё в твою самописную систему на PHP.
Все события делятся на уровни подозрительности. Тревога срабатывает только если отсутствует хозяин (BLE-метка не обнаружена). Ниже — полный перечень сценариев и условий их срабатывания.
glass_breakowner_present (все тревоги отключены)suspicious_loiteringloud_noisedoor_openedvehicle_movingengine_startedignition_onpower_disconnected (угон в процессе!)tamperingСистема не принимает решений — она фиксирует факты. Ты сам видишь: «в 03:14 напряжение пропало, через 10 сек — движение, координаты такие-то». Решать — угон или нет — будешь ты.
Классика умных сигналок:
Мы реализуем это на ESP32 (а не на Arduino — он мощнее, есть Bluetooth, Wi-Fi, два ядра и встроенный BLE).
Установи в Arduino IDE через менеджер библиотек:
Adafruit GPS Library — для NEO-6MAdafruit BME280 LibraryAdafruit MPU6050ESP32 BLE Arduino — для сканирования BLESoftwareSerial — для SIM800L (или используй аппаратный UART2)Пример функции отправки события:
#include <HTTPClient.h>
void sendEventToServer(String eventType, float lat, float lon, float voltage) {
if (WiFi.status() == WL_CONNECTED) { // или через GPRS, если нет Wi-Fi
HTTPClient http;
http.begin("http://yourdomain.com/tracker.php");
http.addHeader("Content-Type", "application/json");
String json = "{";
json += "\"event\":\"" + eventType + "\",";
json += "\"lat\":" + String(lat, 6) + ",";
json += "\"lon\":" + String(lon, 6) + ",";
json += "\"voltage\":" + String(voltage) + ",";
json += "\"time\":\"" + getTimeString() + "\"";
json += "}";
int httpResponseCode = http.POST(json);
http.end();
}
}
Файл tracker.php:
<?php
$data = json_decode(file_get_contents('php://input'), true);
// Сохраняем в БД
file_put_contents('logs.txt', date('Y-m-d H:i:s') . " " . json_encode($data) . "\n", FILE_APPEND);
// Отправляем в Telegram
$botToken = '123456:ABC';
$chatId = '7890';
$msg = "🚨 Тревога: {$data['event']}\n📍 {$data['lat']}, {$data['lon']}\n🔋 {$data['voltage']} В";
file_get_contents("https://api.telegram.org/bot{$botToken}/sendMessage?chat_id={$chatId}&text=" . urlencode($msg));
?>
Твой PHP-сервер (или отдельная IoT-система по Webhook/WeGuard) может:
Ты получил:
И всё это — за цену дешёвой китайской сигналки, но с полным контролем и расширяемостью.
#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
// === BLE ===
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
// === GPS ===
#include <Adafruit_GPS.h>
#define GPSSerial Serial2
Adafruit_GPS GPS(&GPSSerial);
// === BME280 ===
#include <Adafruit_BME280.h>
Adafruit_BME280 bme;
// === MPU6050 ===
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
Adafruit_MPU6050 mpu;
// === GSM ===
#include <TinyGsmClient.h>
#define TINY_GSM_MODEM_SIM800
#define SerialAT Serial1
TinyGsm modem(SerialAT);
TinyGsmClient client(modem);
const char* apn = "internet"; // уточни у оператора
// === Пины ===
#define VOLTAGE_PIN 34 // аналоговый вход (делитель 12В)
#define VIBRATION_PIN 4 // SW-420
#define RADAR_PIN 15 // RCWL-0516
// === BLE ===
bool phoneDetected = false;
String targetDeviceName = "YourPhoneName"; // ← ЗАМЕНИ НА ИМЯ ТВОЕГО ТЕЛЕФОНА!
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
if (advertisedDevice.haveName()) {
if (advertisedDevice.getName().c_str() == targetDeviceName) {
phoneDetected = true;
}
}
}
};
// === Вспомогательные функции ===
float readCarVoltage() {
int val = analogRead(VOLTAGE_PIN);
// Делитель: 20к + 10к → коэффициент 3.0
return (val * 3.3 / 4095.0) * 3.0;
}
void sendEvent(const char* eventType) {
// Включаем SIM800L (если управляешь через пин — добавь digitalWrite)
delay(2000);
SerialAT.begin(9600, SERIAL_8N1, 16, 17);
modem.restart();
if (!modem.gprsConnect(apn)) {
Serial.println("GPRS failed");
return;
}
// Ждём GPS фикс
GPS.begin(9600);
bool gpsFix = false;
for (int i = 0; i < 20; i++) {
GPS.read();
if (GPS.newNMEAreceived()) {
if (GPS.parse(GPS.lastNMEA())) {
if (GPS.fix) {
gpsFix = true;
break;
}
}
}
delay(500);
}
// Собираем данные
String json = "{";
json += "\"event\":\"" + String(eventType) + "\",";
json += "\"voltage\":" + String(readCarVoltage()) + ",";
json += "\"vibration\":" + String(digitalRead(VIBRATION_PIN)) + ",";
json += "\"radar\":" + String(digitalRead(RADAR_PIN)) + ",";
if (gpsFix) {
json += "\"lat\":" + String(GPS.latitude, 6) + ",";
json += "\"lon\":" + String(GPS.longitude, 6) + ",";
} else {
json += "\"lat\":0,\"lon\":0,";
}
if (bme.performReading()) {
json += "\"pressure\":" + String(bme.pressure / 100.0) + ",";
json += "\"temp\":" + String(bme.temperature) + ",";
} else {
json += "\"pressure\":0,\"temp\":0,";
}
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
json += "\"accel_x\":" + String(a.acceleration.x) + "";
json += "}";
// Отправка на сервер
if (client.connect("yourdomain.com", 80)) {
client.print("POST /tracker.php HTTP/1.1\r\n");
client.print("Host: yourdomain.com\r\n");
client.print("Content-Type: application/json\r\n");
client.print("Content-Length: " + String(json.length()) + "\r\n");
client.print("\r\n");
client.print(json);
client.stop();
Serial.println("Sent: " + json);
}
modem.gprsDisconnect();
GPS.end();
}
// === SETUP ===
void setup() {
Serial.begin(115200);
Wire.begin();
// Датчики
pinMode(VIBRATION_PIN, INPUT);
pinMode(RADAR_PIN, INPUT);
analogReadResolution(12); // ESP32
// GPS
GPSSerial.begin(9600, SERIAL_8N1, 5, -1); // RX=5, TX не нужен
// BME280
if (!bme.begin(0x76)) {
Serial.println("BME280 not found");
}
// MPU6050
if (!mpu.begin()) {
Serial.println("MPU6050 not found");
}
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
// GSM
SerialAT.begin(9600, SERIAL_8N1, 16, 17);
modem.restart();
// BLE
BLEDevice::init("");
}
// === LOOP ===
void loop() {
// Сканируем BLE 5 сек
phoneDetected = false;
BLEScan* pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true);
pBLEScan->start(5, false);
pBLEScan->clearResults();
delay(1000);
// Если телефона нет — читаем датчики
if (!phoneDetected) {
Serial.println("Phone NOT detected. Reading sensors...");
bool eventTriggered = false;
String eventType = "";
// Проверка вибрации
if (digitalRead(VIBRATION_PIN) == HIGH) {
eventType = "vibration";
eventTriggered = true;
}
// Проверка радара
if (digitalRead(RADAR_PIN) == HIGH) {
eventType = "radar_motion";
eventTriggered = true;
}
// Проверка напряжения (зажигание)
float v = readCarVoltage();
if (v > 13.2) {
eventType = "ignition_on";
eventTriggered = true;
}
if (eventTriggered) {
sendEvent(eventType.c_str());
delay(10000); // анти-спам
}
} else {
Serial.println("Phone detected. Sleeping...");
}
// Спим 30 сек
delay(30000);
}
Немного передумал с безопасностью ...
Многие пытаются использовать Bluetooth-маячки (beacon), чтобы автоматически включать/выключать сигнализацию: «подошёл — отключилась, ушёл — включилась». Но есть проблема: любой может просканировать MAC-адрес или UUID и подделать сигнал. Это делает такие системы уязвимыми к простой replay-атаке.
Я решил пойти другим путём — использовать одноразовые криптографические токены, по принципу автомобильных иммобилайзеров. Теперь моя сигнализация реагирует только на аутентичное подтверждение присутствия, а не на «крик в эфир».
Вместо того чтобы маячок постоянно излучал один и тот же идентификатор, я сделал так:
Даже если злоумышленник перехватит код — он не сработает повторно. Это называется HOTP (HMAC-Based One-Time Password).
// Упрощённая логика на стороне автомобиля (ESP32)
#include <WiFi.h>
#include <HTTPClient.h>
#include <Crypto.h> // Библиотека для HMAC, например: https://github.com/intrbiz/arduino-crypto
const uint8_t SECRET_KEY[32] = { /* твой 256-битный секрет */ };
uint32_t last_counter = 1000; // последний принятый счётчик
bool verify_hotp(const char* received_code, uint32_t counter) {
byte hmac[32];
hmac_sha256(SECRET_KEY, 32, (byte*)&counter, 4, hmac);
// Преобразуем HMAC в 6-значный код (как в Google Authenticator)
uint32_t code = ((hmac[19] & 0x7F) << 24 |
(hmac[20] & 0xFF) << 16 |
(hmac[21] & 0xFF) << 8 |
(hmac[22] & 0xFF)) % 1000000;
return (atoi(received_code) == code) && (counter > last_counter);
}
void handle_unlock_request(const char* hotp_code, uint32_t counter) {
if (verify_hotp(hotp_code, counter)) {
last_counter = counter;
digitalWrite(RELAY_PIN, LOW); // отключаем сигнализацию
Serial.println("✅ Сигнализация ОТКЛЮЧЕНА");
// Запускаем таймер на включение при уходе
startAutoArmTimer(30); // 30 секунд
} else {
Serial.println("❌ Неверный или повторный код!");
}
}
// При нажатии кнопки
uint32_t counter = readCounterFromEEPROM(); // читаем текущий счётчик
counter++;
// Генерируем HOTP
byte hmac[32];
hmac_sha256(SECRET_KEY, 32, (byte*)&counter, 4, hmac);
uint32_t code = /* ... как выше ... */ % 1000000;
// Отправляем по BLE / LoRa / GSM / MQTT
sendToCar(String(code), counter);
// Сохраняем новый счётчик
saveCounterToEEPROM(counter);
💡 Совет: для максимальной безопасности используй микросхему с Secure Element (например, ATECC608B или NTAG 424 DNA). Там ключ физически недоступен даже при вскрытии устройства.
Теперь моя машина знает: если код принят — это точно я, а не кто-то с клоном маячка. А когда я ухожу — она сама встаёт на охрану. Без облаков, без уязвимостей, без «водить телефоном у двери».
Большинство автосигнализаций полагаются на уязвимые радиоканалы: 433 МГц, Bluetooth, GSM. Но если вы строите систему с нуля — почему бы не уйти от шаблонов? Ниже — обзор малоиспользуемых, но технически доступных решений, которые сложно подавить стандартными джаммерами.
Модули на базе SX1278 или SX1262 работают в ISM-диапазонах (433/868 МГц), но используют расширенный спектр и когерентную модуляцию. Обычные глушители, ориентированные на OOK/FSK, просто «не видят» такой сигнал. При этом дальность — до 1–2 км в городе, энергопотребление — микроватты в спящем режиме.
Плюс: легко реализовать двустороннюю аутентификацию с AES-128 поверх LoRa-пакета. Машина не откроется, пока брелок не подтвердит команду криптографически.
Сверхширокополосная связь (Ultra-Wideband) работает в диапазоне 6–9 ГГц короткими импульсами. Это позволяет не только обмениваться данными, но и точно измерять расстояние (с точностью до 10 см). Такие системы устойчивы к релейным атакам — если «ключ» находится дальше 1 метра, двигатель не заведётся.
Хотя ESP32 не поддерживает UWB «из коробки», внешние модули вроде Qorvo DW3000 подключаются по SPI и уже используются в Apple CarKey и BMW Digital Key.
Иногда самый надёжный канал — тот, о котором угонщик даже не догадывается:
Такие методы не заменят основную систему, но отлично работают как фактор подтверждения в многоуровневой архитектуре безопасности.
Большинство автосигнализаций используют 433 МГц в режиме OOK/FSK — и именно этот диапазон первым глушат угонщики. Но если перейти на LoRa-модуляцию и немного сместить частоту в рамках разрешённого ISM-диапазона, ваш сигнал становится «невидимым» для большинства джаммеров.
Все они работают в диапазоне 410–525 МГц, что позволяет использовать не только стандартные 433.92 МГц, но и «краевые» частоты вроде 434.5–434.7 МГц — где шум от джаммера уже слабее.
Передача зашифрованной команды на частоте 434.7 МГц:
// Библиотека: https://github.com/sandeepmistry/arduino-LoRa
#include <SPI.h>
#include <LoRa.h>
void setup() {
Serial.begin(115200);
SPI.begin(5, 19, 27, 18); // SCK=5, MISO=19, MOSI=27, SS=18 (для Heltec)
LoRa.setPins(18, 14, 26); // SS, RST, DIO0
if (!LoRa.begin(434.7E6)) { // Частота: 434.7 МГц
Serial.println("LoRa init failed!");
while (1);
}
LoRa.setSpreadingFactor(12); // Макс. устойчивость к шуму
LoRa.setSignalBandwidth(125E3); // Узкая полоса
LoRa.setCodingRate4(8); // Макс. коррекция ошибок
LoRa.enableCrc(); // Обязательно!
}
void loop() {
// Пример: отправить команду "LOCK" с токеном
LoRa.beginPacket();
LoRa.print("CMD:LOCK;TOKEN:7A3F");
LoRa.endPacket();
delay(5000);
}
Такой подход не нарушает закон (всё в ISM-диапазоне), но делает вашу систему практически неуязвимой к типичным угонщицким джаммерам.
Даже самый «экзотический» радиоканал бесполезен без криптографической аутентификации. Настоящая защита строится на принципе: «Не верь команде — проверь её». А частота — просто средство доставки.
Блог только запустил, все статьи генерирую через нейросеть т.к. лень, возможны ошибки. Просто чтобы вы знали и не запускали ядерный реактор по моим статьям ))
Если у вас есть вопросы, или Нашли неточность? пишите в коментах — вместе поправим и сделаем статью более качественной. Я лично объясню нюансы из практики.
Комментарии
Пока нет комментариев. Будьте первым!