Задача
Мониторить состояние канала Интернет, если пропадает линк – то “тревога-тревога, волк украл зайчат” (С). В общем должна сработать сигнализация.
В общем виде нам нужно пинговать внутренний шлюз Интернет. Внешний шлюз (провайдер или публичный DNS). Если где-то не проходят пинги – соответствующая реакция. На прототипе – светодиоды. На практике – реле с выводом на сигнализацию “Сигнал”.
Что нам потребуется:
- Arduino Uno
- Ethernet Shield w5100
- Реле
- Светодиоды
- Резисторы
- Соединительные провода
- Макетная плата
Прототип с нуля выйдет примерно на 1000 рублей
Сборка
Соединяем ArduinoUno и EthernetShield. Последний (как и вообще шилды) выполнен таким образом, что повторяет распиновку Arduino и выносит выводы дальше, то есть можно объединить несколько шилдов как бутерброд. Сам Ethernet Shield использует лишь несколько цифровых пинов.
Выводим на Breadboard (макетку) общий 3.3V, общую землю, а так же цифровые выводы с 5 по 7 для светодиодов.
Параллельно с красным светодиодом запитываем реле, через которое у нас будет ещё один светодиод (это в тестовой сборке, по факту будет сигнализация).
Реле там имеет два состояния – NO и NC (нормально открытое и нормально закрытое), при соответствующем сигнале само-собой ситуация меняется на противоположную. Подключать можно хоть 220V прибор (оно на 250 рассчитано).
Программирование
#include <SPI.h>
#include <Ethernet.h>
#include <ICMPPing.h>
byte mac[] = {0xDE, 0xAD, 0xBE, 0xFE, 0xFE, 0xFE}; // MAC адрес устройства
byte ip[] = {192,168,1,130}; // IP устройства
byte ds[] = {192,168,1,100}; // DNS
byte gw[] = {192,168,1,100}; // GW
IPAddress pingAddr(192,168,1,9); // локальный адрес
IPAddress pingAddr2(77,88,8,8); // публичный DNS
SOCKET pingSocket = 0;
int interval = 10000; // 10 секунд
int MAX_FAIL = 6; // сколько пингов считать неуспешными
int FAIL = 0; // счётчик фейлов
int ledRED = 7; // пин для красного диода (и далее - остальных)
int ledYEL = 6;
int ledGRN = 5;
ICMPPing ping(pingSocket, (uint16_t)random(0, 255));
// Инициализируем Ethernet нашим MAC, IP и шлюзом по умолчанию.
void setup()
{
Ethernet.begin(mac, ip, ds, gw);
pinMode(ledGRN, OUTPUT);
pinMode(ledYEL, OUTPUT);
pinMode(ledRED, OUTPUT);
}
void loop()
{
ICMPEchoReply echoReply = ping(pingAddr, 2);
if (echoReply.status == SUCCESS)
{
ICMPEchoReply echoReplyWORLD = ping(pingAddr2, 2);
if (echoReplyWORLD.status == SUCCESS)
{
digitalWrite(ledGRN, HIGH);
digitalWrite(ledRED, LOW);
digitalWrite(ledYEL, LOW);
FAIL=0;
}
else
{
digitalWrite(ledGRN, LOW);
digitalWrite(ledRED, LOW);
digitalWrite(ledYEL, HIGH);
FAIL=0;
}
}
else
{
// Увеличиваем счётчик фейлов
FAIL++;
}
// Если счётчик фейлов превысил некий порог
if (FAIL >= MAX_FAIL)
{
// Меняем индикацию
digitalWrite(ledGRN, LOW);
digitalWrite(ledYEL, LOW);
digitalWrite(ledRED, HIGH);
}
// не даём счётчику фейлов переполнять переменную
if (FAIL > 300) {FAIL=6;}
delay(interval);
}
Как это работает
Всё ясно из исходника, думаю. Раз в интервал мы посылаем пинг на несколько адресов (локальный и удалённый). Если оба пинга проходят, то зажигаем зелёный светодиод. Если проходит только локальный, то оранжевый, если ни один не проходит – увеличиваем счётчик фейлов. Когда счётчик фейлов достигнет критического значения, зажигаем красный светодиод. Попутно замыкаем реле и трубим сигнализацию.
Зачем вообще этот счётчик? Иногда случается так, что пакет может затеряться. Какой-то глюк в сети, когда коммутаторы не успели обработать все фреймы из-за пиковой загрузки или ещё какое-нибудь ЧП, в общем один пакет пропал. Нет смысла бить тревогу в этом случае, нужно всего лишь дождаться следующего прохождения пакета. А вот если подряд несколько запросов теряются, то это уже повод.
Видео
На видео есть участок, где на первый взгляд ничего не происходит. На самом деле это отрабатывает защита от ложных срабатываний.
Конечно не всё в этой схеме идеально. По сути мне нужно несколько реле, чтобы сигнализировать так же в случае проблем с внешкой. Но это уже дело техники.
Ах да, и ещё надо бы распаять нормально на плате это, а не на макетке. Навесной монтаж – он быстр, но очень ненадёжен.
Comments: