Как ни странно, но до сих пор у меня не было ни одного датчика из тех, которые принято относить к "охранным сигнализациям".
Но вот понадобилось поставить сигнализацию на некоторую Железную Дверь, которая должна быть всегда закрыта, если без присмотра. Весь процесс - далее.
Задача простая: сообщать, когда дверь открывается, когда закрывается, и если осталась открытой - напоминать об этом.
Но дверь железная - буквально, в том смысле что она из железных профтруб, в железной раме, а еще - она на улице, т.е. всякие варианты с микровыключателями тут не подходят, всё это будет съедено коррозией.
Поэтому за основу взял индуктивный датчик: такие обычно используются во всяких промышленных системах. Работают просто: подносишь железку - включаются, убираешь - выключаются. Продаются на маркетплейсах, довольно распространенная штука.
Вот именно такой датчик и буду использовать, установив его так, чтобы закрытая дверь приводила к срабатыванию. Сам он герметичный, а блок управления - рядом, в серой пластиковой распаечной коробке - как показала практика такие коробки прекрасно переносят условия улицы, дождь, снег, солнце.
Дрель, метчик на 3, два болтика из комплекта и кусок серой трубы для кабеля.
Питание 12 вольт уже есть, датчик работает от 10 до 30. Остается подключить к этому всему ESP, завязать в PainlessMesh, ловить события "дверь открыта".
Также, для контроля работоспособности, отправлять периодически состояние статус: если очередное сообщение не приходит больше трех минут - значит что-то вышло из строя.
Подключить напрямую датчик нельзя: там будет 12в (может быть и можно, ограничив напряжение стабилитроном, но нет такой необходимости), поэтому использую обычный оптрон.
Также, потребуется понижение напряжения питания с 12 до 3.3 вольт, для этого использую готовый модуль DC-DC.
Ну, и чтобы все это было как-то аккуратнее - соберу на печатной плате.
Размеры печатной платы под коробку 60х35 мм. Разводку платы делаю как обычно во Fritzing. Знаю, что "профессионалы" ее терпеть не могут за "ардуинистость", но она как раз подходит для подобных случаев.
Проблема в том, что для создания печатной платы нужны "отпечатки" деталей, и если с оптронами, резисторами, и даже ESP12 проблемы нет - то найти готовый "отпечаток" под безымянный модуль с Али - задача непростая.
А во Fritzing его можно просто нарисовать!
Для этого нужно сначала сфотографировать модуль. У него несколько контактных отверстий, размещать его я буду на штырьках на лицевой стороне платы, соответственно, фотографирую "сверху", а контактные площадки будут на плате "снизу".
Фотографию модуля нужно развернуть так, чтобы он был по возможности горизонтально и без искажений - с этим прекрасно справится Gimp.
Теперь нужен SVG-редактор. Как ни странно, наиболее известный Inkscape здесь не подходит, создаваемые им SVG не подходят без ручного ковыряния текста SVG, а это как бы неудобно.
Поэтому я использую тут boxy-svg.
Принцип следующий: импортируем картинку модуля, под ее размеры подгоняем viewport, и указываем реальные размеры в миллиметрах.
Теперь всё что будет нарисовано "по фотографии" - уже будет соответствовать реальным размерам.
Самая важная часть - нарисовать контактные площадки.
В данном случае это должны быть кольца, с отверстием посередине - для этого подходит инструмент "эллипс", точнее круг, у которого отключено заполнение, но задана увеличенная толщина линии периметра. Потом, на реальной плате, это будет выглядеть как кольцо.
У этого модуля контактные площадки сдвоенные - но лучше нарисовать одинарные, одна площадка - один контакт.
Контактные площадки группируются в группу, называемую copper1 - это значит они будут отображаться на нижней стороне платы. (copper0 - лицевая, верхняя сторона).Нюанс в том, что у группы есть название, и есть ID - вот тут важно чтобы ID был copper1.
Также рисую примерно расположение деталей на модуле и группирую их в группу layout - это не обязательно, просто потом так легче узнавать, какой именно модуль используется.
Фотографию из файла можно удалить, она больше не нужна.
Дальше во Fritzing находим что-нибудь похожее, чтобы не рисовать еще и схему - тоже 4 контакта, вход-выход, и редактируем, сохраняя как новую деталь.
Отмечаем контакты как штырьки - это заставит программу размещать деталь на лицевой стороне.
В разделе PCB загружаем новый SVG, и отмечаем какой контакт к какой площадке относится.
В разделе Schematic уже есть схема "блока питания", и контакты к выводам привязаны - можно не менять.
В разделе Breadboard снова загружаем SVG - должна появится условная картинка с деталями - тут тоже нужно привязать контакты к площадкам.
В разделе Icon можно просто повторно использовать Breadboard, это только для картинки в списке деталей.
Всё это сохраняется как новый элемент - теперь можно добавлять его в схему:
И конечно, развести плату:
Конечно, изготовление сложных плат лучше поручить профессионалам, а для этого надо бы правильно расположить все нужные надписи, добавить какую-нибудь красивую картинку, но потом придется долго ждать чтобы получить свой десяток плат - а мне нужна всего одна и сейчас.
Поэтому просто ограничимся самой платой, без шелкографии, и сделаем ее сами и быстро.
Сохраняем проект как etched pdf, из которого будут нужны два файла: дорожки и маска.
PDF затягиваем в Gimp с разрешением 1200 dpi, инвертируем цвета.
Так же рядом затягиваем маску с тем же разрешением, ничего не инвертируем.
Печатается это все на листе тонкой бумаги, около 80 г/м2, или на кальке
На кусок стектотекстолита накатывается ламинатором пленка фоторезиста (Китай, маркетплейс)
Сверху смачивается обычным подсолнечным маслом и накрывается калькой. Калька тоже смазывается, и она становится прозрачной.
4 секунды под светодиодной УФ-лампой, сдираем верхнюю защитную пленочку - готово к проявке
3 минуты в растворе строительного "жидкого стекла" с водой, примерно 1:2 - незасвеченное сползает лохмотьями
Травление: аптечная 3% перекись + чайная ложка соли + чайная ложка лимонной кислоты - примерно 10 минут
Смывка фоторезиста - "Крот" + вода, соотношение примерно 1:3, ок. 3 минут - остатки фоторезиста обесцвечиваются и сползают.
Ну, дальше нанесение маски, засветка, смывка - это всегда плохо получалось, поэтому углубляться не стоит. Сверление отверстий, обрезка краев шлифмашинкой.
В итоге получается плата, готовая к распайке:
Теперь программная часть.
Уже практически типовой скетч:
/*
* check PIN state, set event
*
*/
#include "painlessMesh.h"
#include <LittleFS.h>
#include <ArduinoJson.h>
#define VERSION "Guard v1.0"
#define OTA_NAME "guard"
#define MESH_PREFIX "ХХХХХ"
#define MESH_PASSWORD "ХХХХХ"
#define MESH_PORT 5678
painlessMesh mesh;
size_t gw_id = 0;
size_t me_id = 0;
int state;
#define PIN_CTL 13
#define IND 2
// =========================================================
// Prototypes
void receivedCallback( uint32_t from, String &msg );
void newConnectionCallback(uint32_t nodeId);
// =========================================================
void MeshSetup(){
gw_id = 0;
mesh.setDebugMsgTypes( ERROR | STARTUP | DEBUG | CONNECTION );
mesh.init( MESH_PREFIX, MESH_PASSWORD, MESH_PORT );
mesh.onReceive(&receivedCallback);
mesh.onNewConnection(&newConnectionCallback);
mesh.initOTAReceive(OTA_NAME);
mesh.setContainsRoot(true);
}
// =========================================================
#define TTL 180000
unsigned long ttl_timer;
int ttl_check;
void TtlSetup(){
ttl_timer = millis();
ttl_check = 0;
}
void TtlLoop(){
if(abs((long)(millis() - ttl_timer)) > TTL){
ttl_timer = millis();
if (ttl_check == 0){
ESP.reset();
}else{
ttl_check = 0;
mesh.sendBroadcast("ping");
}
}
}
// time ===================================================
#include <time.h>
#include <lwip/apps/sntp.h>
void TimeSetup(){
sntp_stop();
}
// =========================================================
unsigned long state_timer;
#define STATE_PERIOD 60000
#define STATE_RND 5000
void StateSetup(){
state_timer = 0;
gw_id = 0;
}
void StateLoop(){
DynamicJsonDocument doc(300); // messages
if(abs((long)(millis() - state_timer)) > STATE_PERIOD){
state_timer = millis();
state_timer += random(STATE_RND);
doc["ident"] = OTA_NAME;
time_t now = time(nullptr);
doc["dtm"] = now;
doc["block"] = "state";
long rssi = WiFi.RSSI();
doc["rssi"] = rssi;
doc["state"] = state;
if(rssi < -60){
digitalWrite(IND,HIGH);
}else{
digitalWrite(IND,LOW);
}
String message;
serializeJson(doc, message);
if(gw_id > 0){
mesh.sendSingle(gw_id, message);
}
else{
mesh.sendBroadcast(message);
}
}
}
// =========================================================
void setup() {
LittleFS.begin();
pinMode(IND,OUTPUT);
digitalWrite(IND,HIGH);
MeshSetup();
TimeSetup();
pinMode(PIN_CTL, INPUT_PULLUP);
state = digitalRead(PIN_CTL);
TtlSetup();
StateSetup();
}
void loop() {
mesh.update();
TtlLoop();
int x = digitalRead(PIN_CTL);
if(state != x){
String str = "{\"alarm\":1,\"state\":";
str += x;
str += "}";
state = x;
if(gw_id > 0){
mesh.sendSingle(gw_id, str);
}
else{
mesh.sendBroadcast(str);
}
}
StateLoop();
delay(100);
}
void newConnectionCallback(uint32_t nodeId) {
char buf[80];
time_t now = time(nullptr);
sprintf(buf,"settime %u",now);
mesh.sendSingle(nodeId, buf);
}
void receivedCallback( uint32_t from, String &msg ) {
ttl_check = 1;
// ===============================
if (msg == "state") {
gw_id = from;
state_timer = 0;
} else
// ===============================
if (msg == "version") {
mesh.sendSingle(from, VERSION);
} else
// ===============================
if (msg == "restart") {
mesh.sendSingle(from, "OK");
ESP.restart();
} else
// ===============================
if (msg.startsWith("settime ")) {
String num = msg.substring(8);
time_t tim = num.toInt();
time_t now = time(nullptr);
if(tim != 0 && tim > now){
timeval tv = { tim, 0 };
settimeofday(&tv, nullptr);
}
}
}
Суть программы простая: подключаемся в mesh-сеть, ловим сообщения, отправляем свои.
При подключении к какому-то из модулей он отправляет команду settime - это подерживает единое время во всей сети.
Периодически отправка пингов, периодически отправка сообщений о своем состоянии. Чтобы не накладывались сообщения - рандомизация.
Если нет новых сообщений более чем 180 сек - перезагрузка модуля.
Специфическое для данного модуля - за каждую итерацию проверка пина на подтягивание к "земле", с изменением статуса и отправкой сообщения.
Итого, пока дверь закрыта - от датчика идет ток на оптрон, который опускает пин к "земле". Как только дверь открылась - ток выключается, оптрон закрывается, на входе 1, отправляется сообщение. Потом наоборот.
Периодически передается текущее состояние.
Сообщения, отправляемые датчиком, выглядят примерно так:
mesh/from/2874622439 {"ident":"guard","dtm":1738189126,"block":"state","rssi":-91,"state":0}
Теперь их нужно применить в общую систему. Для этого делается скрипт-драйвер:
#!/usr/bin/perl -w
$|=1;
use Net::MQTT::Simple;
use JSON;
use Data::Dumper;
$SIG{CHLD} = "IGNORE";
########################################
my $mqtt = Net::MQTT::Simple->new("127.0.0.1");
#------------------------------------------
# send MQTT message
sub pub {
my ($topic, $message, $retain) = @_;
my $pid = fork();
if(defined $pid && $pid == 0){
if($retain){
$mqtt->retain($topic => $message);
}else{
$mqtt->publish($topic => $message);
}
sleep(2);
exit(0);
}
}
#------------------------------------------
my $door1 = '2874622439';
# processing
$mqtt->run(
# receive Info requests
"mesh/from/$door1" => sub {
my ($topic, $message) = @_;
print ".";
my $data = undef;
if($message =~ /^{.*}$/){
$data = from_json($message);
}
if(defined $data && defined $data->{ state }){
my $t = $data->{state};
if($t == 1){
pub("alarm/text","Дверь открыта!");
}
elsif($data->{ alarm }){
pub("alarm/text","Дверь закрыта");
}
}
},
);
exit;
Вот теперь всё: дверь открывается - на телефон приходит сообщение, дверь закрывается - снова приходит сообщение.
Избыточно сложно? Может быть, но в пару строк в драйвере можно добавить отправку команды на включение чего-нибудь (красной лампочки, прожектора, сирены), вести лог когда что открывалось.
А еще получился по сути универсальный модуль, который можно подключить к любому "шлейфу", будь это герконные датчики на окнах, PIR-сенсоры, или какие-нибудь лазерные барьеры - просто сообщения будут приходить от разных ID.
Но такой задачи нет. Пока нет.
Комментарии (15)
Roman_shvbsk
29.01.2025 23:56Да, для контроля дверей обычно используются "извещатели охранные магнитоконтактные", в основе которых геркон. Они очень дешевые, энергонезависимые, массовые и надежные. Индуктивный тут непонятно какие преимущества может дать. И такие магнитоконтактные извещатели должны быть по любому готовые с зигби, вайфаем или что тут требовалось в данном случае. Это самое простое что может быть. Но может я не прав и это не "велосипед".
JBFW Автор
29.01.2025 23:56Геркон на железной двери с железной рамой работает плохо. В отличии от деревянной или хотя бы алюминиевой. Именно поэтому такой датчик, он тут более подходит.
Зигби с простым Wifi не проходят по дальности и обилию железа вокруг, сигнал гасится. Причем зигби гасится 100%, WiFi работает так-сяк, то есть то нет - проходили уже.
aMster1
29.01.2025 23:56Для железных дверей есть специальные герконы. В смысле датчики расчитаны на установку на железную дверь.
поищите ИО-102-20 или ИО-102-40 с разными букавками - их очень много модификации, разных по рабочему расстоянию, герметичности и внешнему виду.
Например у нас ставили на "дверь" в виде прорезанного люка в стали толщиной 16 мм. (Стенка трубы D1020 мм) . Прекрасно работают.
Roman_shvbsk
29.01.2025 23:56Да, для контроля дверей обычно используются "извещатели охранные магнитоконтактные", в основе которых геркон. Они очень дешевые, энергонезависимые, массовые и надежные. Индуктивный тут непонятно какие преимущества может дать. И такие магнитоконтактные извещатели должны быть по любому готовые с зигби, вайфаем или что тут требовалось в данном случае. Это самое простое что может быть. Но может я не прав и это не "велосипед".
Roman_shvbsk
29.01.2025 23:56Да, для контроля дверей обычно используются "извещатели охранные магнитоконтактные", в основе которых геркон. Они очень дешевые, энергонезависимые, массовые и надежные. Индуктивный тут непонятно какие преимущества может дать. И такие магнитоконтактные извещатели должны быть по любому готовые с зигби, вайфаем или что тут требовалось в данном случае. Это самое простое что может быть. Но может я не прав и это не "велосипед".
Markscheider
29.01.2025 23:56А я спрошу по подготовку платы :). Вроде советуют сначала дырки сверлить, а потом травить. Ибо тонкие дорожки при сверлении "пятака" могут отвалиться...
JBFW Автор
29.01.2025 23:56Это от технологии сверления зависит, так скажем. Твердосплавные свёрла сверлят идеально - но станочек нужен, они очень хрупкие и при перекосе моментально лопаются.
А вот если борами зубными сверлить как в древности - то да.Но вообще заранее сверлить очень неудобно будет - это же надо сначала наметить, потом сверлить, потом фоторезист (иначе еще фоторезист сверлом и опилками попортить, и засветить дополнительно). Даже с ЛУТом будет сложно.
Опять же, в древности когда всё это руками рейсфедером рисовалось - там наоборот, удобно было сначала насверлить, потом соединять - наверное это с того времени советуют.xSVPx
29.01.2025 23:56Я не знаю о каком перекосе речь. Лично сверлил стекло "с рук" сверлом 0.8мм в обычном 30м наконечнике. Опыт довольно интересный. Сломал несколько штук за десяток отверстий глубиной 5-10мм. Они совершенно не "моментально лопаются".
Неоднократно сверлил с рук что-то в тестовых печатках. Сломать об текстолит можно, но надо постараться.
Некогда купил 0.25 сверел, дышать на них страшно было. А потом понадобилось одно сломать. И оказалось это не так уж и просто...
JBFW Автор
29.01.2025 23:56Какие именно сверла, вон те как внизу на картинке или обычные?
Те как на картинке - могут разбиться просто от удара, как стекло, не то что от перегиба. Но сверлят очень хорошо, без артефактов на поверхности
boopiz
Боже, как всё сложно.
Самый простой и дешевый вариант на любой случай (дверь, концевик в воде и т.д. и т.п.): обычный геркон и магнит (это типовой триггерный датчик), которому не нужно вообще ничего, он пассивный. Не надо мудрить с питанием для esp и\или другого контроллера (12В, 3.3 В) и т.д.
и esp12 тут лишняя. можно обойтись esp8266-01, выводов там предостаточно для работы.
По типовым схемам включения датчиков, сработка фиксируется прижатием линии к 0 (с этого, как правило, начинают работать большинство протоколов обмена данными, и наличие "линии" это доп сигнализация, что порыва нет.). Значит надо обеспечить дефолтную подтяжку к + питания. Тем более, что доступные gpio esp требуют как раз при старте подтяжку к +vcc, но т.к. данный девайс может при старте находится в одном из положений (замкнуто или разомкнуто), а требование подтяжки надо соблюдать, то безопасно можно исползьовать только один вывод gpio3 (RX).
подтяжка - это токоограничивающий резистор типовым номиналом 4.7 - 10 кОм (нам не нужен ток, нам нужно наличие напряжения на gpio). можно вставить прямо в коннектор между +vcc и gpio3
геркон - подключается одним концом к минусу питания, вторым заводится в тот же разъем gpio3
и теперь при замыкании gpio будет прижиматься к земле, и небольшой ток подтяжки будет успешно туда коммутироваться.
проверка - тривиальна (ее можно писать самому, можно использовать существующие программы для линейки esp (в зависимости от нужд).
надежно, дешево.
xSVPx
Не мало ли 10килоом в случае батарейного питания ? К слову, какие вообще могут быть в таких местах номиналы и как их выбирают ?
JBFW Автор
Потому что задачу надо видеть в комплексе:
Во-первых - Железная Дверь. На которой геркон работает через раз, потому что вся дверь вместе с рамой - магнитопровод.
Дальше: вместо используемых везде esp12 идем покупать esp8266-01 (чтобы сэкономить выводы?) - и разводим зоопарк чипов. Тоже хорошо.
О том, что есть встроенные резисторы подтяжки забываем, зачем они? Добавим внешний.
Причем "вставить прямо в коннектор между +vcc и gpio3" - то есть в не лабораторных условиях ограничиваемся "просто вставить", без пайки или винтового зажима.
И оно будет работать надежно )
xSVPx
Видел в своей жизни сотни железных дверей оборудованных сигнализацией. Простыми, обычными герконами. Уж не знаю как люди решали проблемы, но очевидно, что это совершенно типичный кейс: надо мониторить состояние металлической двери.
И если вы топите за надежность, то промышленно изготовленное решение от известного вендора уж точно надежнее самосбора будет.
Самосбор мне предстоит делать доя контроля того в каком положении ригели. Ничего путного готового не нашел.
ЗЫ. В букварях предостерегают от использования внутренних подтяжек в устройствах с батарейным питанием, но 10к как по мне маловато...
JBFW Автор
В каких именно букварях?