Перейти к публикации
iT4iT.CLUB
Kitsum

Замок с радиочастотной идентификацией

Рекомендованные сообщения

Добрый вечер всем! Наконец то наткнулся на единственную подходящую для меня разработку! Сразу же собрал устройство на столе и убидился, что все работает как надо! Я хочу пристроить данный девайс в своем авто на блокировку капота при помощи блокиратора двери, но наткнулся на неприятный момент: после записи всех ключей, сбрасываю питание и в момент подачи питания срабатывает реле открывания и работает в постоянную( что губительно для электродвигателя блокиратора) возвращаеться все в рабочее состояние только после считывания ключа. Подскажите люди добрые, как сделать так, чтобы при подаче питания срабатывало реле закрытия на 0,4секунды? или хотябы где искать отвечающую за данные действия процедуру? пересматривал скетч но ничего ненашел известного мому мозгу!

Изменено пользователем sergon63tlt

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@sergon63tlt

Опишите поэтапно, что нужно выполнять и как должен действовать замок. Чем подробнее тем лучше. Какой из вариантов программы Вы использовали? Мы постараемся Вам помочь.

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@Alex13

Внес изменения во все листинги программы опубликованные в теме. Также внес исправление во все схемы.

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Какие изменения в листингах программ? Удаление строчки в инициализация кнопки сброса или ещё какие-то?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@Alex13

Кнопка открытия двери и кнопка сброса памяти

// Кнопка сброса памяти
pinMode(PIN_RESET,INPUT_PULLUP);
key_reset.attach(PIN_RESET);
key_reset.interval(5);
  
// Кнопка открытия двери
pinMode(PIN_OPEN,INPUT_PULLUP);
key_open.attach(PIN_OPEN);
key_open.interval(5);

Сейчас силы брошены на другой проект. Позже опять вернусь к замку.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Скрытый текст


/*
 * Программа управления нагрузкой с помощью RFID-RC522 13.56 мГц
 *  
 * - РАСПИНОВКА ----------------------------------------------------------------------------
 *             MFRC522      Arduino       Arduino   Arduino    Arduino          Arduino
 *             Reader/PCD   Uno           Mega      Nano v3    Leonardo/Micro   Pro Micro
 * Signal      Pin          Pin           Pin       Pin        Pin              Pin
 * -----------------------------------------------------------------------------------------
 * RST/Reset   RST          9             5         D9         RESET/ICSP-5     RST
 * SPI SS      SDA(SS)      10            53        D10        10               10
 * SPI MOSI    MOSI         11 / ICSP-4   51        D11        ICSP-4           16
 * SPI MISO    MISO         12 / ICSP-1   50        D12        ICSP-1           14
 * SPI SCK     SCK          13 / ICSP-3   52        D13        ICSP-3           15
 * -----------------------------------------------------------------------------------------
 *
 */

// Необходимые библиотеки
#include <avr/wdt.h>
#include <EEPROM.h>
#include <SPI.h>
#include <MFRC522.h>
#include <Bounce2.h>

// Необходимые пины
#define PIN_RESET         4        // RESER MEMORY
#define PIN_OPEN          2        // OPEN

#define PIN_RELAY_1       6        // RELAY CLOSE
#define PIN_RELAY_2       7        // RELAY OPEN
#define PIN_TONE          3        // TONE

#define PIN_RST           9        // RFID
#define PIN_SS            10       // RFID

#define PIN_MODE          8        // MODE

#define PIN_ALARM         14       // ALARM ON/OFF
#define PIN_ALARM_1M      15       // ALARM SIGNAL 1M
#define PIN_ALARM_LONG    16       // ALARM SIGNAL LONG TIME         

// Инициализация RFID ридера
MFRC522 mfrc522(PIN_SS, PIN_RST);

// Переменные необходимые для работы со списком ключей
byte **keys;
byte keys_count = EEPROM.read(0);

// Переменные необходимые для режима программирования
byte modeProgTime           = 5;     // Количество секунд удержания мастер ключа для входа\выхода в\из режим\а программирования
bool mode                   = false; // НЕ МЕНЯТЬ!
bool modeLock               = false; // НЕ МЕНЯТЬ!
byte modeClean              = 0;     // НЕ МЕНЯТЬ!
unsigned long modeTimer     = 0;     // НЕ МЕНЯТЬ!
unsigned long resetTimer    = 0;     // НЕ МЕНЯТЬ!

// Переменные для сигнализации
bool invert                 = true;  // Инвертировать выходы сигнализации (A1, A2)
bool alarm                  = false; // НЕ МЕНЯТЬ!
byte alarmCount             = 0;     // НЕ МЕНЯТЬ!
unsigned long alarmTimer    = 0;     // НЕ МЕНЯТЬ!
unsigned long alarmInterval = 0;     // НЕ МЕНЯТЬ!

// Управление замком
unsigned long openTimer     = 0;
bool lockStat               = false;

// Защита кнопок от дребезга
Bounce key_reset = Bounce();
Bounce key_open  = Bounce();
/*
  Якобы программный reset, но мы с Вами знаем, что это не так ;)
*/
void(* resetFunc) (void) = 0;
/*
  Функция звукового оповещения.
  Принимает параметры: количество звуковых сигналов, частота в герцах, продолжительность звука, пауза в милесекундах (не обязательно)
*/
void squeaker(byte count, unsigned int Hz, unsigned int duration, unsigned int sleep = 0) 
{
  for(int i=0; i<count; i++) {
    tone(PIN_TONE, Hz, duration);
    if(sleep > 0) delay(sleep);
  }
}
/*
  Функция читает EEPROM и составляет список активных ключей
  Первый байт в памяти содержит количество ключей
  UID ключа содержит 4 байта
  Общая память 1 + количество ключей * 4
  Максимум можно записать 255 ключей
*/
void keysRead() {
  // Выводим количество ключей
  Serial.print(F("KEYS COUNT: "));
  Serial.println(keys_count);
  int eb = 0;
  keys = (byte**)malloc(sizeof(byte*)*keys_count);
  // Читаем список ключей из EPROM
  Serial.println(F("------------------------------"));
  for(byte i=0; i<keys_count; i++) {
    Serial.print(F("KEY: "));Serial.print(i);Serial.print(" | ");
    keys[i] = (byte*)malloc(sizeof(byte)*4);
    for(byte b=0; b<4; b++) {
      keys[i][b] = EEPROM.read(++eb);
      Serial.print(keys[i][b]);
      if(b < 3) Serial.print(F(" "));
    }
    Serial.println();
  }
  Serial.println(F("------------------------------"));
  Serial.println();
}
/*
  Функция выводит UID ключа и, при необходимости, сопроводительное сообщение
*/
void uidPrint(String text = "") {
  Serial.print(F("UID: "));
  for(byte i=0; i<mfrc522.uid.size; i++) {
    Serial.print(mfrc522.uid.uidByte[i]);
    if(i < mfrc522.uid.size - 1) Serial.print(F(" "));
  }
  Serial.println();
  if(text.length() != 0) Serial.println(text + "\n");
}
/*
  Управление соленоидом с использованием пары реле.
  1 - закрытие, 0 - открытие
*/
void lock(bool lock) {
  digitalWrite(lock ? PIN_RELAY_1 : PIN_RELAY_2, LOW);
  delay(400);
  digitalWrite(lock ? PIN_RELAY_1 : PIN_RELAY_2, HIGH);
  lockStat = lock;
}
/*
  Инициализация программы
*/
void setup() {
  // Настраиваем сторожевой таймер
  wdt_disable();
  delay(8000); // <- ЗАКОМЕНТИРУЙТЕ ЭТУ СТРОКУ, ЕСЛИ ЗНАЕТЕ, ЧТО ТАКОЕ wdt_enable(WDTO_8S);
  wdt_enable(WDTO_8S);
    
  // Инициализация используемых пинов
  // Реле
  pinMode(PIN_RELAY_1, OUTPUT);
  digitalWrite(PIN_RELAY_1, HIGH);
  pinMode(PIN_RELAY_2, OUTPUT);
  digitalWrite(PIN_RELAY_2, HIGH);
  
  // Кнопка сброса памяти
  pinMode(PIN_RESET,INPUT_PULLUP);
  key_reset.attach(PIN_RESET);
  key_reset.interval(5);
  
  // Кнопка открытия двери
  pinMode(PIN_OPEN,INPUT_PULLUP);
  key_open.attach(PIN_OPEN);
  key_open.interval(5);   

  // Перемычка выбора режима работы (0 - автоматическое закрытие двери, 1 - закрытие двери по ключу)
  pinMode(PIN_MODE, INPUT);
  digitalWrite(PIN_MODE, HIGH);

  // Переменные для сигнализации
  pinMode(PIN_ALARM, INPUT_PULLUP);
  digitalWrite(PIN_ALARM, HIGH);

  pinMode(PIN_ALARM_1M, OUTPUT);
  digitalWrite(PIN_ALARM_1M, invert ? HIGH : LOW);

  pinMode(PIN_ALARM_LONG, OUTPUT);
  digitalWrite(PIN_ALARM_LONG, invert ? HIGH : LOW);
  
  // Инициализация консоли
  Serial.begin(9600);
  while (!Serial);
  // Приглашаем в гости
  Serial.println(F("iT4iT CLUB (C) 2015\nhttps://it4it.club\n"));
  
  // Инициализация ридера
  SPI.begin();
  mfrc522.PCD_Init();

  // Читаем количество ключей
  // Значение должно быть равным или больше 1 т.к первый ключ это мастер
  // В случае утери мастер ключа, мы можем сбросить EEPROM и прикрутить новый мастер ключ
  if(keys_count > 0 and keys_count < 255) {
    keysRead();
    lock(true);
  }
  else {
    keys_count = 0;
    Serial.println(F("The master key is not in memory. The first presentation to the key will be the master!\n"));
    lock(false);
  }
}
/*
  Лупаем, что происходит
*/
void loop() {
  // Сбрасываем сторожевой таймер микроконтроллера
  wdt_reset();

  if(alarmInterval > millis()+10000) alarmInterval = 0;
  if(alarmTimer > millis()+10000) alarmTimer = 0;
  if(resetTimer > millis()+10000) resetTimer = 0;
  if(openTimer > millis()+10000) openTimer = 0;
   
  // Изменение режима работы закрытия
  modeLock = !digitalRead(PIN_MODE);
  // Изменение режима работы сигнализации
  alarm    = !digitalRead(PIN_ALARM);
  // Очистка памяти
  key_reset.update();
  if(key_reset.read()) {
    if(resetTimer == 0) resetTimer = millis();
    else {
      if((millis()-resetTimer)/1000 > 5) {
        Serial.println(F("Launched memory cleaning"));
        squeaker(4, 1600, 300, 200);
        wdt_disable();
        for(int i=1; i<=EEPROM.length(); i++) {
          EEPROM.write(i, 0);
          if(!(i%50)) Serial.println(F("#")); else Serial.print(F("#"));
        }
        Serial.println(F("\nMemory cleaning is completed\n"));
        delay(1000);
        resetFunc();
      }
    }
  }
  else if(resetTimer != 0) resetTimer = 0;
  // Открытие двери с кнопки
  key_open.update();
  if(!key_open.read() and openTimer == 0) {
    if(keys_count > 0) {
      if(modeLock or (!modeLock and digitalRead(PIN_RELAY_2) == HIGH)) {
        openTimer = millis()/1000;
        lock(false);
        Serial.println(F("The door opened from the inside\n"));
        squeaker(5, 3200, 100, 300);
      }
    }
    else Serial.println(F("\nAttempting to open the lock from the inside.\nAccess denied. The master key is unknown. The castle is always open.\n"));
    delay(2000);
  }
  // Автоматическое отключение сигнализации
  if(alarmTimer != 0) {
    if(millis()/1000 - alarmTimer > 60) {
      alarmTimer = 0;
      digitalWrite(PIN_ALARM_1M, invert ? HIGH : LOW);
      Serial.println(F("Automatic shutdown of the first signaling channel.\n"));
    }
  }
  // Сброс счетчика подбора ключа
  if(alarmInterval != 0) {
    if(millis()/1000 - alarmInterval > 60) {
      alarmInterval = 0;
      alarmCount = 0;
      Serial.println(F("Time selection key expired.\n"));
    }
  }
  // Автоматическое закрытие двери
  if(openTimer != 0) {
    if(millis()/1000 - openTimer > 5) {
      openTimer = 0;
      if(modeLock) {
        lock(true);
        Serial.println(F("* closed lock\n"));
      }
    }
  }
  // Если ключ отсутствует или не читается, не выполняем дальнейший код
  if(!mfrc522.PICC_IsNewCardPresent()) {
    // Очистка таймера входа в режим программирования, в случае если ридер свободен
    if(modeTimer != 0) {
      if(++modeClean > 5) modeTimer = modeClean = 0;
    }
    return;
  }
  if(!mfrc522.PICC_ReadCardSerial()) return;
  // Останавливаем режим очистки
  modeClean = 0;
  
  // Кривое создание мастер ключа
  if(keys_count == 0) {
    for(byte i=0; i<4; i++) EEPROM.write(i+1, mfrc522.uid.uidByte[i]);
    EEPROM.write(0, keys_count = 1);
    uidPrint(F("master key is created"));
    digitalWrite(PIN_RELAY_2, HIGH);
    keysRead();
    squeaker(8, 1200, 100, 100);
    delay(2000);
    return;
  }
  
  // Проверка ключа на соответствие
  bool access = false;
  bool master = false;
  for(byte i=0; i<keys_count; i++) {
    for(byte b=0; b<4; b++) {
      if(keys[i][b] != mfrc522.uid.uidByte[b]) break;
      if(b == 3) {
        access = true;
        if(i == 0) master = true;
        // Останавливаем проверку костылем т.к "break 2;" не работает
        i = keys_count;
      }
    }
  }
  // ========================================================================================
  // Следующая секция имеет двойное назначение:
  //  1. В обычном режиме - контроль доступа
  //  2. В режиме программирования - запись ключа при его отсутствие в EEPROM
  // ========================================================================================
  // ОБЫЧНЫЙ РЕЖИМ
  // ========================================================================================
  if(access and !mode and !master) {
    // Доступ разрешен
    if(modeLock) {
      openTimer = millis()/1000;
      lock(false); 
    }
    else lock(!lockStat);
    if(alarm) {
      alarmInterval = alarmTimer = alarmCount = 0;
      if((invert and (!digitalRead(PIN_ALARM_1M) or !digitalRead(PIN_ALARM_LONG))) or (!invert and (digitalRead(PIN_ALARM_1M) or digitalRead(PIN_ALARM_LONG)))) {
        digitalWrite(PIN_ALARM_1M, invert ? HIGH : LOW);
        digitalWrite(PIN_ALARM_LONG, invert ? HIGH : LOW);
        Serial.println(F("Clear active alarms signaling\n"));
      }
    }
    uidPrint(F("access allow"));
    squeaker(2, 2200, 200, 200);
    delay(2000);
  }
  else if(!access and !mode and !master) {
    if(alarm) {
      if(alarmInterval == 0) alarmInterval = millis()/1000;
      if(++alarmCount >= 3) {
        if(alarmCount > 3) alarmCount = 3;
        alarmTimer = millis()/1000;
        digitalWrite(PIN_ALARM_1M, invert ? LOW : HIGH);
        digitalWrite(PIN_ALARM_LONG, invert ? LOW : HIGH);
        Serial.println(F("Attention! Attempt selection key! Activate both signaling channel!\n"));
      }
    }
    // Доступ запрещен
    uidPrint(F("access dany"));
    squeaker(1, 500, 1000);
    delay(2000);
  }
  // ========================================================================================
  // РЕЖИМ ПРОГРАММИРОВАНИЯ
  // ========================================================================================
  else if(access and mode and !master) {
    // Попытка записи существующего ключа
    uidPrint(F("error: key elrady exists in eeprom"));
    squeaker(2, 500, 300);
    delay(2000);
  }
  else if(!access and mode and !master) {
    // Записываем новый ключ
    // Максимум 255 ключей (с учетом первого байта) для 328 камня
    if(keys_count < 255) {
      for(byte i=0; i<4; i++) EEPROM.write(1 + keys_count*4 + i, mfrc522.uid.uidByte[i]);
      EEPROM.write(0, ++keys_count);
      uidPrint(F("add key in eeprom"));
      keysRead();
      squeaker(2, 2200, 200, 200);      
    }
    else {
      uidPrint(F("error: not enough memory for recording key!"));
      squeaker(2, 500, 300);
    }
    delay(2000);
  }
  // ========================================================================================
  // РАБОТА С МАСТЕР КЛЮЧОМ
  // ========================================================================================
  else if(access and master) {
    if(alarm) {
      alarmInterval = alarmTimer = alarmCount = 0;
      if((invert and (!digitalRead(PIN_ALARM_1M) or !digitalRead(PIN_ALARM_LONG))) or (!invert and (digitalRead(PIN_ALARM_1M) or digitalRead(PIN_ALARM_LONG)))) {
        digitalWrite(PIN_ALARM_1M, invert ? HIGH : LOW);
        digitalWrite(PIN_ALARM_LONG, invert ? HIGH : LOW);
        Serial.println(F("Clear active alarms signaling\n"));
      }
    }
    // Мастер ключ в обычном режиме
    if(modeTimer == 0) {
      modeTimer = millis()/1000;
      if(!mode) {
        if(modeLock) {
          openTimer = millis()/1000;
          lock(false); 
        }
        else lock(!lockStat);
        // Сигнал о наличии мастер ключа в обычном режиме
        uidPrint(F("MASTER KEY"));
        squeaker(2, 2200, 200, 200);
      }
    }
    else {
      if(millis()/1000 - modeTimer > modeProgTime and modeTimer != 0) {
        modeTimer = 0;
        if((mode = !mode) == true) {
          // Вход в режим программирования
          digitalWrite(PIN_RELAY_2, LOW);
          uidPrint(F("MASTER PROGRAMMING MODE ON"));
          squeaker(4, 1200, 200, 200);
        }
        else {
          // Выход из режима программирования
          digitalWrite(PIN_RELAY_2, HIGH);
          uidPrint(F("MASTER PROGRAMMING MODE OFF"));
          squeaker(4, 2200, 200, 200);
        }
      }
      delay(2000);
      // Дополнительные действия по таймеру modeProgTime
    }
    // Мастер ключ удерживается у ридера
  }
}

 

На данный момент после сброса питания, при условии что прописаны ключи, лог. единица появляется на выводах 6(реле закрытия) кратковременно и 7(реле открытия) лог. единица весит до тех пор пока не поднести к считывателю ключ. К выводу 6( реле закрытия) претензий нет! Как сделать так, чтобы, при сбросе питания на вывод 7 не подавалась единица?

Хотелось бы, чтоб после подачи питания лог. единица  подавалась только на вывод 6( реле закрытия).

 

Изменено пользователем sergon63tlt

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Мне кажется проблема в сигналах на этих пинах! По умолчанию стоит высокий уровень и пропадает он при поднесении ключа т.е. Вам надо инвертировать сигнал, как это сделать есть в форуме на странице 4.

Скрытый текст
Цитата
В 24.03.2016 в 22:35, Kitsum сказал:

Да, можно.

В функции Setup происходит инициализация пинов для управления реле замка




  // Инициализация используемых пинов
  // Реле
  pinMode(PIN_RELAY_1, OUTPUT);
  digitalWrite(PIN_RELAY_1, HIGH);
  pinMode(PIN_RELAY_2, OUTPUT);
  digitalWrite(PIN_RELAY_2, HIGH);

Необходимо заменить HIGH на LOW

За управление замком отвечает функция lock




void lock(bool lock) {
  digitalWrite(lock ? PIN_RELAY_1 : PIN_RELAY_2, LOW);
  delay(400);
  digitalWrite(lock ? PIN_RELAY_1 : PIN_RELAY_2, HIGH);
  lockStat = lock;
}

Аналогичным образом необходимо заменить значения LOW и HIGH на противоположные

 

 

 

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Совершенно верно. Изначально подразумевалось использование Китайских реле в качестве управления нагрузкой, а для их работы необходим инвертированный сигнал - HIGH для закрытия и LOW для открытия реле. Естественно, что если выкинуть реле из схемы, то необходимо произвести изменения в коде, на которые указал @Alex13

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Пробовал менять данные пункты, но это не то... Сигнал инвертировал перед первой заливкой скетча, так как у меня реле китайское. все равно реле открытия после подачи питания работает в постоянную, я как понимаю изначально скетч был написан для двери с электромагнитным замком и у него при первом старте требуется назначить мастер ключ, а пока он не назначен, замок всегда открыт! вот что то подобное происходит у меня, замок требует поднести мастер ключ, независимо от того, что он уже был прописан в ячейке "0" до отключения питания и соответственно держит реле открытия под нагрузкой! Вот именно эту процедуру( удержание двери открытой до поднесения мастер ключа) мне и нужно удалить, ввиду того что, при внезапном разряде автомобильной АКБ и подаче резервного питания через специально выведенный разъем, автомобильный соленоид, под напряжением долго не выдержит, да и в довесок степень защиты существенно снижается... Достаточно кратковременно устроить обрыв питания и уаля!!! замок сам себя откроет. Не судите строго, знаний пока маловато.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

еще заметил одну особенность: при случайном замыкании  контактов питания считывателя( +3.3в и общий) питание восстанавливаться, а вот сам считыватель теряется до полного сброса питания.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Да, изначально скетч писался для электромагнитного замка, но управление нагрузкой это всего лишь пару строчек кода, которые легко переписываются. Львиная доля программы - обработка RFID меток и соответствующая реакция на них.

Для того чтобы было понятно, что мы пытаемся изменить, предлагаю с начало разобраться в том, что происходит при подаче питания с пинами управления реле.

  1. В самом начале программы смотрим содержимое первого байта EEPROM микроконтроллера. Там должно быть число, указывающее на количество ключей.
    byte keys_count = EEPROM.read();
  2. В функции Setup происходит инициализация пинов и на них выставляется высокий логический уровень, опять же все ради Китайских реле, это обесточит их.
    // Реле
    pinMode(PIN_RELAY_1, OUTPUT);
    digitalWrite(PIN_RELAY_1, HIGH);
    pinMode(PIN_RELAY_2, OUTPUT);
    digitalWrite(PIN_RELAY_2, HIGH);
  3. Следующий ключевой момент - принятие решения, открыть замок при отсутствие ключей в памяти и сообщить об этом в Serial или же запереть замок и встать на охрану.
    if(keys_count >  and keys_count < 255) {
      keysRead();
      lock(true);
    }
    else {
      keys_count = ;
      Serial.println(F("The master key is not in memory. The first presentation to the key will be the master!\n"));
      lock(false);
    }
  4. Серьезным отличием от электромагнитного замка является наличие функции void lock(bool lock); именно она манипулирует пинами и переключает реле с паузой в 0.4 сек. Заодно фиксирует последнее состояние замка, своего рода программный концевик на двери.
    void lock(bool lock) {
      digitalWrite(lock ? PIN_RELAY_1 : PIN_RELAY_2, LOW);
      delay(400);
      digitalWrite(lock ? PIN_RELAY_1 : PIN_RELAY_2, HIGH);
      lockStat = lock;
    }

До момента, описанного в п.3 реле находились в покое и не производили никаких манипуляций с соленоидом. Функция lock, кроме возложенных на неё обязанностей, гарантирует нам, что любое реле будет в работе ровно 0.4 секунды, а затем вернется в свое обычное состояние. Следовательно, если ключ будет отсутствовать в памяти микроконтроллера то по условию в п.3 произойдет вызов lock(false); и это приведет к появлению логического нуля на 6 пине на 0.4 секунды, после вернется логическая единица. Если в EEPROM будет находиться хотя бы один ключ, то произойдет вызов lock(true); и аналогичные манипуляции произойдут с пином 7 - замок закроется.

Предлагаю проделать следующее: 

  1. Просмотреть вывод в Serial начиная с момента подачи питания, возможно там будет подсказка.
  2. Модернизировать функцию lock и выводить в Serial все, что происходит с реле
    void lock(bool lock) {
      digitalWrite(lock ? PIN_RELAY_1 : PIN_RELAY_2, LOW);
      Serial.println(lock ? "RELAY CLOSE (PIN 6) ACTIVATED" : "RELAY OPEN (PIN 7) ACTIVATED");
      delay(400);
      digitalWrite(lock ? PIN_RELAY_1 : PIN_RELAY_2, HIGH);
      Serial.println(lock ? "RELAY CLOSE (PIN 6) DEACTIVATED" : "RELAY OPEN (PIN 7) DEACTIVATED");
      lockStat = lock;
    }
  3. Можно, но не обязательно, пару фотографий как это выглядит (собрано).

 

22 часа назад, sergon63tlt сказал:

еще заметил одну особенность: при случайном замыкании  контактов питания считывателя( +3.3в и общий) питание восстанавливаться, а вот сам считыватель теряется до полного сброса питания.

Это вполне ожидаемое поведение т.к после подачи питания, микроконтроллер MFRC522 скорее всего ожидает запись в соответствующие регистры. Уверен, что этим занимается PCD_Init().

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Мне кажется проблема с кнопками открытия двери и сброса памяти! Когда я собирал проект на макетке, кнопка сброса памяти была подтянута к земле напрямую, а кнопка открытия двери вообще была откинута всё работало! Попробуйте так. 

Ещё посмотрите остальные пины которые изменяют состояние замка и сигнализации! Вот например переключатель ручного закрытия замка или автоматического, в ручном режиме чтоб закрыть замок, надо ещё раз поднести ключ. В общем внимательно всё проверьте и  почитайте как всё работает, думаю ошибку найдёте, как было и у меня, виной кривой работы замка оказались банальные светодиоды!!!

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
6 часов назад, Alex13 сказал:

кнопка сброса памяти была подтянута к земле напрямую, а кнопка открытия двери вообще была откинута всё работало!

именно таким способом у меня все и подключено! пробовал без подтягивания 4ого пина к земле, каждые 8 секунд стералась энерго независимая память вместе с ключами.

Изменено пользователем sergon63tlt

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
6 часов назад, Kitsum сказал:

Предлагаю проделать следующее: 

  1. Просмотреть вывод в Serial начиная с момента подачи питания, возможно там будет подсказка.
  2. Модернизировать функцию lock и выводить в Serial все, что происходит с реле
    
    void lock(bool lock) {
      digitalWrite(lock ? PIN_RELAY_1 : PIN_RELAY_2, LOW);
      Serial.println(lock ? "RELAY CLOSE (PIN 6) ACTIVATED" : "RELAY OPEN (PIN 7) ACTIVATED");
      delay(400);
      digitalWrite(lock ? PIN_RELAY_1 : PIN_RELAY_2, HIGH);
      Serial.println(lock ? "RELAY CLOSE (PIN 6) DEACTIVATED" : "RELAY OPEN (PIN 7) DEACTIVATED");
      lockStat = lock;
    }

Последовал предложенному примеру, и вот что получилось при уже прописанных ключах:

Скрытый текст

Безымянный.jpg

реле закрытия повело себя как и описано в мониторе СОМ, а вот реле открытия включилось одновременно с реле закрытия и не отключается до поднесения любого из прописанных ключей:

Скрытый текст

IMG_20160421_222326.jpg

а вот в СОМ порт информации о действии реле открытия не поступает...

Изменено пользователем sergon63tlt

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 час назад, sergon63tlt сказал:

реле закрытия повело себя как и описано в мониторе СОМ, а вот реле открытия включилось одновременно с реле закрытия и не отключается до поднесения любого из прописанных ключей

Обновил программу из этого поста. Пробуйте залить её как есть, не внося никаких изменений. Посмотрим что будет в Serial. И подтяните пины 8 и 4 земле.

Изменено пользователем Kitsum

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

А где переключатель режима открытия?!? Мой Вам совет, не поленитесь и соберите схему полностью, иначе совсем запутаетесь!!! Какой-то порт болтается в воздухе и начинаются глюки!!!

Скрытый текст

рабочая схема.png

А кнопки оставьте как у Вас уже собрано. Если ещё не прочитали  форум прочтите, настоятельно рекомендую!!! Посмотрите как я с глюками боролся, странички то всего четыре!

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
11 минуту назад, Alex13 сказал:

А где переключатель режима открытия?!? Мой Вам совет, не поленитесь и соберите схему полностью, иначе совсем запутаетесь!!! Какой-то порт болтается в воздухе и начинаются глюки!!!

  Показать содержимое

рабочая схема.png

А кнопки оставьте как у Вас уже собрано. Если ещё не прочитали  форум прочтите, настоятельно рекомендую!!! Посмотрите как я с глюками боролся, странички то всего четыре!

форум мной был прочитан от начала и до моей первой записи:D а когда пошло не так, прочитал еще 2 раза и пытался сам разобраться что к чему но, мой начальный уровень дал понять  только 30% скетча:$ Все равно спасибо за советы!

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Извиняюсь за назойливость! Приятно когда всё работает как хотелось! :D

  • Like 2

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
13 минуты назад, sergon63tlt сказал:

Вот теперь " то, что доктор прописал":) Если не секрет какие были изменения?

@sergon63tlt отключены лишние подтягивающие резисторы встроенные в микроконтроллер и исправил некоторые косяки которые связанные с внедрением функции lock. Хотя на домашнем компьютере версия замка @Alex13 была уже с этими исправлениями... Это еще раз доказывает, что коллективно проект развивается намного быстрее и качественнее.

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@Kitsum Спасибо за помощь в трудную минуту и питание моего мозга нужной информацией! теперь моя машинка станет еще угоноустойчивее благодаря всем форумчанам и в отдельности благодаря вам!

Изменено пользователем sergon63tlt
  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 час назад, sergon63tlt сказал:

@Kitsum Спасибо за помощь в трудную минуту и питание моего мозга нужной информацией! теперь моя машинка станет еще угоноустойчивее благодаря всем форумчанам и в отдельности благодаря вам!

скупая мужская слеза...

  • Like 2

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 21.04.2016 в 21:01, sergon63tlt сказал:

именно таким способом у меня все и подключено! пробовал без подтягивания 4ого пина к земле, каждые 8 секунд стералась энерго независимая память вместе с ключами.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В Saturday, April 23, 2016 в 14:12, svchekalin сказал:

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

есть более надежный способ с применением сканера отпечатка пальца!

IMG_20160424_221835_844629598.jpgIMG_20160424_221847_157661230.jpg

гдето в инете видел подобную преблуду, собранную на Ардуино.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Пожалуйста, войдите для комментирования

Вы сможете оставить комментарий после входа



Войти сейчас

  • Похожие публикации

    • Автор: Kitsum
      Привет друзья.
      В данной теме пойдет речь о конфигурации микроконтроллера через UART (Universal Asynchronous Receiver-Transmitter) интерфейс. А рассмотрим мы это на примере MQTT логгера. В данном случае, это будет логгер температуры. Мне это устройство потребовалось на работе, даже не мне, а моим коллегам, и оно действительно работает и приносит огромную пользу т.к контроль температуры производится совместно с отличной, на мой взгляд, системой мониторинга Zabbix с оперативными оповещениями, построением графиков, блэк-джеком и... Подробнее о дружбе Arduino и Zabbix можно почитать тут
      Но как всегда, есть нюансы. А заключаются они в том, что в будущем, обслуживать армию мелких контроллеров придется людям, которые заняты своими задачами и им попросту некогда изучать Arduino, не говоря уже о серьезных альтернативах, разбираться в том, как прописать нужные значения переменных в программу и загрузить её в микроконтроллер. Все настройки необходимо производить быстро, с явным указанием изменяемого параметра и его значения. Ровно также, как это делается с любым промышленным оборудованием.
      И тут на помощь приходит UART
      Микросхема UART to USB имеется в большинстве плат семейства Arduino, а там, где её нет, обычно выведены соответствующие "пины". И все это очень облегчает жизнь т.к позволяет общаться с контроллером, просто подключив его к компьютеру напрямую или через переходник, благо их везде навалом, да и стоят они как пачка семечек. Остается только запустить любой терминал, который умеет доставлять в конец строки символ "перевод строки", что известен в народе как "\n", а в ASCII таблице имеет номер 0A.
      Кстати, в Serial мониторе Arduino IDE выставить символ конца строки можно так

      Ну а дальше только, что и остается, как общаться с устройством на той стороне. И тут мы переходим к основному алгоритму программы. Но перед этим хочу отметить, и это ВАЖНО, что за любое упрощение жизни, всякие красивости и прочее, приходиться платить, и цена довольно высока! В данном случае, это ОЗУ микроконтроллера. Поэтому не раскатываем губы, а если очень хочется, то берем следующий по характеристикам микроконтроллер. А начинать мы будем с ATmega328P, что известен в народе как Arduino UNO, Arduino Nano, IBoard v1.1 и т.д по списку. Заканчивать Вы можете чем угодно, хоть ATmega2560, ESP8266 или ESP32. В противном случае, производим оптимизацию кода, отказываемся от громоздких библиотек, или вообще, от Arduino IDE.
      Что мы хотим получить
      Вся конфигурация микроконтроллера должна храниться в энергонезависимой памяти (ПЗУ) известной нам как EEPROMM. Если в ПЗУ конфигурация отсутствует, необходимо иметь резервный план. И им станет сброс конфигурации на настройки по умолчанию. Это поведение знакомо всем, особенно по домашним дешевым маршрутизаторам, а значит, интуитивно понятно. Выводить справку при начале общения пользователя и устройства, на мой взгляд, как манеры высшего общества. Контроллер должен представляться и сообщать всю необходимую информацию о себе и о том, как с ним вести диалог. Все команды должны быть просты и иметь не двусмысленное значение. И конечно, мы должны иметь возможность просмотра текущего состояния датчиков или процессов, которыми занимается устройство в свободное от общения с нами время. Как сохранять конфигурацию в EEPROM
      Пожалуй, стоит начать с того, как сохранить конфигурацию микроконтроллера в энергонезависимую память. Для этих целей, в стандартный набор инструментов Arduino IDE входит библиотека для работы с EEPROM.
      #include <EEPROM.h> На данный момент нас интересуют две функции, это чтение и запись
      EEPROM.get(address, variable); EEPROM.put(address, variable); Обе принимают два параметра:
      Адрес, начиная с которого будет произведено чтение или запись данных в память Переменная чье содержимое надо сохранить или в которую нужно из памяти прочитать Особенность работы этих функция заключается в том, что в зависимости от типа переданной им переменной во втором параметре, будет произведено чтение или запись ровно того количества данных которое соответствует размеру типа этой самой переменной. На простом языке это означает, что если переменная variable будет иметь типа byte, то и работать мы будем с объемом памяти в 1 байт. И тоже самое произойдет с абсолютно любым типом данных пока мы не упремся в размеры самого EEPROM или ОЗУ микроконтролера. Из этого всего следует, что мы можем создать свой собственный тип данных, разместить в нем необходимую нам информацию и всего лишь двумя функциями помещать его в память и извлекать обратно.
      И в этом нам поможет пользовательский составной тип - структура (struct). Данный тип позволяет объединить в себе различные типы данных, упорядочить их и присвоить им понятные имена.
      Это общий пример для большего понимания, как объединить несколько типов данных в одной структуре, получить к ним доступ, записать и прочитать их из EEPROM.
      Наша структура будет немного сложнее, но суть остается той же самой.
      // Дополнительная структура описывающая IPv4 адреса struct addres { byte a; byte b; byte c; byte d; }; // Структура объекта конфига для хранения в EEPROM struct configObj { addres ip; addres subnet; addres gateway; addres dns; byte mac[6]; byte hex; char server[40]; char topic[40]; } config; Данная структура хранит сетевые настройки для работы с Ethernet модулем (w5100 и выше) Arduino, базовые настройки для связи с MQTT брокером. Сразу при описании структуры мы объявили новую переменную с именем config с типом нашей структуры.
      ВАЖНО: кроме наших данных в структуре имеется дополнительная переменная с именем hex. Её задача, это контроль наличия наших данных в EEPROM. Она всегда должна содержать одно и тоже значение. Представьте ситуацию, что вы взяли контроллер в EEPROM которого находится какая-либо информация (может там чисто, но мы этого не знаем наверняка) и мы прочитаем данные и поместим их в нашу переменную. В итоге мы получим данные которым нельзя доверять, а что еще хуже, это если эти самые данные нарушат работу внешнего оборудования.
      Более правильным, на мой взгляд, будет проверка значений по конкретно определенным адресам. Например, мы знаем, что в 16 байте должно быть значение 0xAA и если оно действительно там, то мы убеждаемся, что это наша информация. Естественно, что контрольных точек может быть несколько и разумеется с разными значениями, это увеличит гарантию того, что данные являются нашими, но 100% гарантии не даст. Для более серьезных проектов есть более серьезные методы, например, подсчет контрольной суммы всего набора данных.
      Также структура может иметь вложенные структуры, у нас ими являются: ip, subnet, gateway, dns. Вы можете отказаться от такого варианта и записывать данные просто в массив байт, как это было сделано с MAC адресом. Естественно, что обращаться к этим полям нужно по-разному.
      Запись данных в поле subnet
      config.subnet = {255, 255, 255, 0}; Запись данных в поле mac
      byte mac[] = {0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02}; memcpy(config.mac, mac, 6); С записью данных в поле server все еще проще
      config.server = "mqtt.it4it.club"; Функция, которая возвращает нашу структуру данных с полностью заполненными полями.
      // Начальный конфиг configObj defaultConfig() { configObj config = { {192, 168, 0, 200}, {255, 255, 255, 0}, {192, 168, 0, 1}, {192, 168, 0, 1}, {0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02}, 0xAA, // Не трогать! Используется для проверки конфигурации в EEPROM F("mqtt.it4it.club"), F("arduino/serial/config") }; return config; } К примеру, два последних значения записывать не обязательно, тогда эти поля останутся пусты если использовать данную функцию для возврата к "заводским" настройкам.
      Вот пример того, как используя описанную нами структуру, мы проверяем целостность настроек в EEPROM и в случае не совпадения hex значений, загружаем настройки по умолчанию.
      const byte startingAddress = 9; bool configured = false; void loadConfig() { EEPROM.get(startingAddress, config); if (config.hex == 170) configured = true; else config = defaultConfig(); configEthernet(); // Функция производящая настройку сети } Как контроллеру начать понимать, что от него хотят
      В Arduino имеется функция, вызываемая каждый раз, когда в передаваемый буфер данных попадает знакомый нам символ перевода строки.
      void serialEvent() { // Вызывается каждый раз, когда что-то прилетает по UART // Данные передаются посимвольно. Если в строке 100 символов, то функция будет вызвана 100 раз } И в контексте обсуждаемой нами программы, мы можем представить ее в следующем виде
      void serialEvent() {   serialEventTime = millis();   if (console.available()) {     char c = (char)console.read();     if (inputCommands.length() < inputCommandsLength) {       if (c != '\n') inputCommands += c;       else if (inputCommands.length()) inputCommandsComplete = true;     }   } } Её задача, символ за символом, собрать в кучу все переданные нами данные и при получении заветного символа перевода строки (именно он даст нам понять, что передача сообщения завершена) сообщить, что команда получена и передать накопленный буфер данных своей напарнице по цеху.
      Но перед тем как это сделать стоит рассмотреть альтернативную ветку развития событий, а именно тот факт, что нам попросту могут прислать огромную, кучу шлака без волшебного символа, а раз могут, значит рано или поздно пришлют. И мы бесполезно потратим ценные ресурсы микроконтроллера, что может привести к непредсказуемым результатам в дальнейшем. Поэтому, в логику функции, мы добавим дополнительное ограничение на количество переданных символов, если оно достигнуто, то попросту перестаем воспринимать последующие данные.
      Останется только избавиться от них, и самым удобным моментом будет, когда этот поток шлака прекратиться. Чтобы об этом узнать мы будем запоминать время, когда пришел каждый из символов переданной строки перезаписывая соответствующую временную переменную данными о следующем символе и т.д пока поток не иссякнет. И как только расхождение текущего времени CPU и времени, когда поступил последний символ превысит некоторое значение, пусть это будет 1 секунда, мы очистим нашу память. Этот простой механизм напоминающий амнезию позволит избавить нас от лишних проблем.
      Переменная отвечающая за размер принимаемого буфера
      const byte inputCommandsLength = 60; Теперь можно переходить к напарнице предыдущей героини и, по совместительству, основной рабочей лошадки - функции обрабатывающей адекватно полученные данные.
      void serialEventHandler() { // вызывается в loop и проверяет взведена ли переменная inputCommandsComplete // в полученных данных пытается распознать команды } По началу я хотел описать данную функцию в упрощенном варианте, но в процессе понял, что ничего хорошего из этого не выйдет, и я решил описать только ключевые моменты, но их будет достаточно, на мой взгляд.
      Разбор serialEventHandler
      Полученные данные будут переданы нам в переменной inputCommands с типом String
      В первую очередь стоит почистить ее от лишних пробельных символов. Они часто встречаются в начале и в конце строки если пользователь копирует текст, а не набирает его самостоятельно. Это распространенная ситуация, приводящая к отказу принятия команды и бороться с ней очень просто.
      inputCommands.trim(); Далее стоит отсеять команды, не несущие никакой динамической информации, например, help, restart, reset и т.п это предписывающие команды которые заставляют контроллер выполнять строго описанные функции без вмешательства в их работу.
      if (inputCommands == F("help")) { consoleHelp(); } else if (inputCommands == F("restart")) { resetFunc(); } else { // Все сложные команды обрабатываются в этом блоке } Как Вы видите, все очень просто и скучно. Но не в том случае если команда динамическая, то есть содержит не только саму команду (заголовок) но и полезную нагрузку (параметр) которая может меняться раз от раза. Простой пример это команда изменения ip адреса и её варианты:
      ip 37.140.198.90 ip 192.168.0.244 ip 10.10.10.88 В данном случае, нам стоит понять, относится ли данная команда именно к ip адресу. Для этого в наборе String имеется отличный метод, позволяющий производить сравнение переданного ему параметра с началом строки.
      if (inputCommands.startsWith(F("ip"))) { // Строка inputCommands начинается с пары символов "ip" } Если все идет так, как мы задумали, то нам стоит отделить динамическую часть - наш параметр, от заголовка и получить полезную нагрузку. В этом нам поможет, опять же из набора String, метод substring позволяющий получать часть строки с указанием начального и конечного символа подстроки. Последний параметр указывать не обязательно и в таком случае мы получим всю строку начиная с указанного символа.
      inputCommands.substring(4) В данном случае начиная с 4-его и заканчивая последним. И как Вы успели заметить, отсчет мы начинаем не с третьего символа, что соответствует нашей строке без вступительного "ip", а на один больше т.к между заголовком и параметром имеется разделяющий символ в виде пробела.
      Далее, полученную строку мы передадим в функцию, занимающуюся разбором на компоненты и принимающую следующие параметры:
      Указатель на переменную с типом char, для этого нам потребуется преобразовать наш тип String Символ разделителя, что для IPv4 является точка "." Указатель на массив типа byte, которому будет присвоен результат разбора Количество искомых элементов в строке И система счисления, подразумеваемая в качестве исходной для записи элементов подстроки /* Парсинг https://stackoverflow.com/questions/35227449/convert-ip-or-mac-address-from-string-to-byte-array-arduino-or-c */ void parseBytes(const char* str, char sep, byte* bytes, int maxBytes, int base) { for (int i = 0; i < maxBytes; i++) { bytes[i] = strtoul(str, NULL, base); str = strchr(str, sep); if (str == NULL || *str == '\0') break; str++; } } В нашем случае выглядеть это будет следующим образом
      byte ip[4]; parseBytes(inputCommands.substring(4).c_str(), '.', ip, 4, 10); А дале все становится еще проще, попросту проверить попадает ли наш ip адрес, в список правильных адресов. И самой простой проверкой послужит проверка первого байта адреса на несоответствие не угодным нам сетям (0, 127, 255)
      if (ip[0] != 127 and ip[0] != 255 and ip[0] != 0) { // Производим необходимые нам действия с ip адресом, например, запись в конфиг config.ip = {ip[0], ip[1], ip[2], ip[3]}; } Вы в праве реализовать собственные проверки, какие только душе угодны.
      Также хотелось бы отметить, что обрабатывать некоторые параметры проще и быстрее через их короткие записи. К таким можно отнести маску подсети устройства. Например, привычный дня нас адрес 192.168.0.1 с маской подсети 255.255.255.0 можно записать в виде 192.168.0.1/24, где цифра 24 указывает нашу подсеть в краткой форме. А, следовательно, мы можем записать несколько кратких форм масок подсети в следующем виде:
      subnet 255.255.255.0 или subnet 24 subnet 255.255.0.0 или subnet 16 subnet 255.0.0.0 или subnet 8 Это основные маски, и я не описывал все существующие т.к в этом нет нужды, но если Вам интересно, то почитать про них можно в wikipedia.
      if (inputCommands.startsWith(F("subnet"))) {     String input = inputCommands.substring(8);     if (input == F("24"))      config.subnet = {255, 255, 255,   0};     else if (input == F("16")) config.subnet = {255, 255,   0,   0};     else if (input == F("8"))  config.subnet = {255,   0,   0,   0};     else { // Все остальные маски попадают в этот блок         byte subnet[4];         parseBytes(input.c_str(), '.', subnet, 4, 10); config.subnet = {subnet[0], subnet[1], subnet[2], subnet[3]};     } } MAC адрес хранится у нас в виде массива байт. Его перезапись другим массивом производится с помощью функции memcpy
      if (inputCommands.startsWith(F("mac"))) { byte mac[6]; parseBytes(inputCommands.substring(4).c_str(), ':', mac, 6, 16); memcpy(config.mac, mac, 6); } Изменение адреса MQTT сервера
      if (inputCommands.startsWith(F("server"))) { String server = inputCommands.substring(8); server.trim(); if (server.length() < 40) server.toCharArray(config.server, 40); } В принципе теперь понятно, как производить получение, разбор и сохранение конфигурации в EEPROM микроконтроллера.
      Как это выглядит на практике
      Заливаем программу в микроконтроллер и подключаемся к Arduino по usb или через переходник. Открываем терминал и нас приветствуют краткой справкой с описанием доступных команд.
      - --------------------------------------------------------------------------------------- # Sensor with data sending to mqtt server (c) it4it.club # Use the "config" command to view the current configuration # To change the configuration, specify the parameter name and its new value with a space, # for example "ip 192.168.0.200", "subnet 255.255.255.0" or "mac AA:BB:CC:DD:EE:FF" # You can also specify a subnet using the mask 24, 16 or 8 # Additional commands: # sensors - view current data from sensors # config - view current configuration # save - saves the current configuration # reset - resets all settings # restart - restarts the device # eeprom clear - removes all contents of eeprom # help - view this help - --------------------------------------------------------------------------------------- Т.к. в EEPROM микроконтроллера не была обнаружена конфигурация (волшебный hex байт нам подсказал), то были задействованы стандартные настройки. Просмотреть текущую конфигурацию можно командой config
      config # ip: 192.168.0.200 # subnet: 255.255.255.0 # gateway: 192.168.0.1 # dns: 192.168.0.1 # mac: 00:AA:BB:CC:DE:02 # server: mqtt.it4it.club # topic: arduino/serial/config чтобы изменить значение любого из этих параметров необходимо передать имя параметра и его новое значение, разделенные между собой пробелом.
      ip 10.10.10.99 # ok gateway 10.10.10.1 # ok dns 10.10.10.1 # ok После окончания конфигурации необходимо сохранить настройки и если были затронуты критические параметры, например, сеть, то перезапустить Arduino соответствующей командой.
      save # ok restart # ok # restarting device... Если параметр был успешно принят, то контроллер ответит нам "ok", а в противном случае ругнется.
      ip 127.0.0.1 # bad ip Также мы получим негативный ответ если команда не была распознана.
      qwerqwer1243 # bad command С остальными командами Вы разберетесь самостоятельно.


      Исходник: MQTT_CLIENT_328_SERIAL_CONFIG.zip
      PS: в общем то это статья родилась только для того, чтобы в соседнем форуме с системой мониторинга Zabbix появилась ссылка на устройство, но я надеюсь, что она также станет полезна любителям домашней автоматизации и не только.
  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу.

×
×
  • Создать...