• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Глупые вопросы от Новичка - NodeMCU v3 и Умному Дому

Semedney

Member
MQ-2 газовый датчик, а ИП212-142 дымовой. Один вешают на управление вытяжкой допустим над плитой в кухне, другой по потолку охраняемого объекта. Ну и если вы хотите не просто смотреть, то лучше еще предусмотреть элементы активной защиты ну допустим вентиляция или элементы пожаротушения. Да и чем Вас обычные датчик охранно-пожарной сигнализации не устраивают или свой велосипед ?
Элементы активной безопасности будут, датчик это просто индикатор (кнопка) по его состоянию сервер умного дома будет либо действовать, либо бездействовать. Обычные датчики - я вот когда купил новую квартиру, там они весели везде, на вопрос что они делают, мне ответили просто дадут сигнал о том что есть дым и они ни как не связаны с системой управления, и какой толк от них если они пищат а дома нет ни кого ?
 

Semedney

Member
Причин может быть две:
1. датчик не настроен (вернее настроен на какой то бред). На нем есть пара подстроечных резисторов, один из которых регулирует чувствительность, а второй время на которое датчик включается после срабатывания. Разберитесь с ними.
2. датчик настроен, но поскольку вы постоянно рядом с ним - он постоянно видит вас.

Странно. Попробуй 2 вещи:
1. В конце строк вставить принудительный перевод строки: "выводимая строка \n\r"
2. После каждого сообщения вызывать принудительно Serial.flush()

Как то так: https://zizibot.ru/articles/electronics/tca9548a/

Разумеется. Но для тяжелых случаев есть хитрость: как правило частота с которой работает i2c около 100КГц, есть быстрый вариант 400КГц и даже супербыстрый 1МГц. Ясно что при таких частотах длина проводов не должна быть более 10-20 см. Но можно использовать и медленные режимы (да, придется поковыряться в настройках библиотеки) 40 и 10 КГц. Последний будет нормально работать и на 1-2 метра (экранированной витой пары разумеется).

В общем-то изначально esp8266 для этого и задумывался - дешевый беспроводной транспорт. По одному датчику на одну esp. Но сейчас народ хочет забить каждый контроллер "под завязку". Впрочем истина она где-то посередине.

Разумно

Для экранированной витой пары или коаксиала (телевизионный кабель) - можно метров 5-6 для простых цифровых датчиков вкл/выкл. То есть герконы, кнопки и др.

Заранее обдумайте чем и как будете все это питать. esp8266 чувствительна к качеству источника питания. В пике бывает жрет > 100мА что может сильно осложнить батарейное питание, при этом тянуть питание везде параллельно с сигнальными проводами может оказаться плохой идеей.
Спасибо. Я за ранее по периметру дома прокинул витую пару, именно по ней я хочу все питать, думаю что надо загонять в нее 12-24 В от мощного блока, а уже у ESP ставить понижение. От ESP питать сами датчики, вернее в моей схеме питание от ESP нужно будет только датчику температуры, и датчику движения - остальное будет просто брать 3,3 В что бы при замыкании создать высокий уровень на входах - думаю хватит.

Юрий, а что скажите по кодам которые я Выкладывал, там все нормально? Может как то можно упростить или так и делается как у меня ?
 

Юрий Ботов

Moderator
Команда форума
Вам должно быть стыдно за такие "потолочные" рассуждения.
Полагаю, что если Вам лень читать документацию,
то Ваш уровень знаний позволяет Вам рассчитать задержки на линии и определить допустимую длину.
Там не только в задержках вопрос, а в "насасываемых" помехах. Наши дома нашпигованы всевозможными проводами, в том числе соседскими, о которых мы порой даже не догадываемся. У меня например по полу идут провода к люстрам соседа снизу. Так что документация это одно, а реальная жизнь немного другое. Сначала попробуйте поработать на 20 метров 400 кГц на "typycal" кабеле в условиях квартиры, померьте количество ошибок и коллизий на шине, а потом вдохновляйте начинающих.
 

nikolz

Well-known member
Там не только в задержках вопрос, а в "насасываемых" помехах. Наши дома нашпигованы всевозможными проводами, в том числе соседскими, о которых мы порой даже не догадываемся. У меня например по полу идут провода к люстрам соседа снизу. Так что документация это одно, а реальная жизнь немного другое. Сначала попробуйте поработать на 20 метров 400 кГц на "typycal" кабеле в условиях квартиры, померьте количество ошибок и коллизий на шине, а потом вдохновляйте начинающих.
Проблемы обычно в голове, вернее в отсутствии знаний. Вот и появляются шаманы с бубном.
-----------------------
У Вас полагаю в квартире есть ethernet , да и интернет кабелем есть, ну на работе точно есть.
Ну и какая там частота? и на какое расстояние?
Поэтому признайте , что ошиблись.
И не надо ля-ля.
 

Юрий Ботов

Moderator
Команда форума
Дома 100tx - около 6 метров, 25 МГц. Каждый вечер когда сосед снизу включает люстру - перезагружаю хаб и роутер ибо виснут :)
 

Semedney

Member
Прошу прошения что вступаю в вашу дискуссию в моей теме, но не могли бы вы посмотреть код по существу.
Код только должен отправлять данные по протоколу MQTT от датчиков.

// Блок [Подключение библиотек] ************************************************
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <BME280I2C.h>
#include <Wire.h>
// END Блок [Подключение библиотек] ********************************************

// Блок [Подключение к сети WI-FI] *********************************************
const char* ssid = "ХХХХХХХХ"; // Имя WI-FI сети
const char* password = "ХХХХХХХХХХХХ"; // Пароль WI-FI сети
const char* mqtt_server = "192.168.2.3"; // IP адрес MQTT сервер
// END Блок [Подключение к сети WI-FI] *****************************************


#define motionSensorD6 D6 // пин, к которому подключен датчик Движения
#define openSensorD3 D3 // пин, к которому подключен датчик Окна 1
#define openSensorD4 D4 // пин, к которому подключен датчик Окна 2
#define smokeSensorD5 D5 // пин, к которому подключен датчик Дыма


#define Temp_topic "ESP/Temp" // Топик Температуры
#define Humidity_topic "ESP/Humidity" // Топик Влажности
#define Pressure_topic "ESP/Pressure" // Топик Давления
#define motionSensor_topic "ESP/Motion" // Топик датчика движения
#define openSensor_topic1 "ESP/WINDOWS_1" // Топик датчика окна 1
#define openSensor_topic2 "ESP/WINDOWS_2" // Топик датчика окна 2
#define smokeSensor_topic "ESP/SMOKE" // Топик датчика Дыма


WiFiClient espClient;
PubSubClient client(espClient);
BME280I2C bme280;

long last_mls = millis();
long last_mls_temp = millis();
long last_mls_move = millis();
long last_mls_moveOff = millis();

boolean moveOn = false;
boolean Win1On = false;
boolean Win2On = false;
boolean SmokeOn = false;

int Win1Old;
int Win2Old;
int SmokeOld;


char msg[50];


void IRAM_ATTR detectsMovementD6() { // Функция при обнаружении движения на D6
if(int val = digitalRead(motionSensorD6)){
delay(10);
if(int val = digitalRead(motionSensorD6)){
client.publish(motionSensor_topic, String(val).c_str(), false); // Публикуем состояние датчика движения
Serial.println("Движение D6!!!");
moveOn = true;
}
}
}


void IRAM_ATTR detectsOpenD3() { // Функция при обнаружении Открытия окна D3
Win1On = true;
Win1Old = digitalRead(openSensorD3);
}

void IRAM_ATTR detectsOpenD4() { // Функция при обнаружении Открытия окна D4
Win2On = true;
Win2Old = digitalRead(openSensorD4);
}

void IRAM_ATTR detectsSmokeD5() { // Функция при обнаружении движения на D6
SmokeOn = true;
SmokeOld = digitalRead(smokeSensorD5);
}


void setup() {

Serial.begin(115200);
client.setServer(mqtt_server, 1883);

delay(100);
WiFi.begin(ssid, password);
delay(6000);
client.connect("ESP8266Client");


pinMode(motionSensorD6, INPUT_PULLUP); // уставливаем пин D6 на прием и включаем внутренний подтягивающий резистор
// Первоначальные данные по датчику движения
if(int val = digitalRead(motionSensorD6)){
client.publish(motionSensor_topic, String(val).c_str(), true); // Публикуем состояние датчика движения
Serial.println("Движение D6!!!");
}else{
client.publish(motionSensor_topic, String(val).c_str(), true); // Публикуем состояние датчика движения
Serial.println("Все тихо D6!!!");
}


pinMode(openSensorD3, INPUT_PULLUP); // уставливаем пин D3 на прием и включаем внутренний подтягивающий резистор
attachInterrupt(openSensorD3, detectsOpenD3, CHANGE); // Прерывание для датчика окна запуск функции detectsOpenD3
// Первоначальные данные по датчику окна 1
if(int val = digitalRead(openSensorD3)){
client.publish(openSensor_topic1, String(val).c_str(), false); // Публикуем состояние окна 1
Serial.println("Открыто окно D3!!!");
}else{
client.publish(openSensor_topic1, String(val).c_str(), false); // Публикуем состояние окна 1
Serial.println("Закрыто окно D3!!!");
}
pinMode(openSensorD4, INPUT_PULLUP); // уставливаем пин D4 на прием и включаем внутренний подтягивающий резистор
attachInterrupt(openSensorD4, detectsOpenD4, CHANGE); // Прерывание для датчика окна запуск функции detectsOpenD4
// Первоначальные данные по датчику окна 2
if(int val = digitalRead(openSensorD4)){
client.publish(openSensor_topic2, String(val).c_str(), false); // Публикуем состояние окна 2
Serial.println("Открыто окно D4!!!");
}else{
client.publish(openSensor_topic2, String(val).c_str(), false); // Публикуем состояние окна 2
Serial.println("Закрыто окно D4!!!");
}

pinMode(smokeSensorD5, INPUT_PULLUP); // уставливаем пин D6 на прием и включаем внутренний подтягивающий резистор
attachInterrupt(smokeSensorD5, detectsSmokeD5, CHANGE); // Прерывание для датчика движения запуск функции detectsMovementD6
// Первоначальные данные по датчика дыма
if(int val = digitalRead(smokeSensorD5)){
client.publish(smokeSensor_topic, String(val).c_str(), false); // Публикуем состояние датчика дыма
Serial.println("Пожар D5!!!");
}else{
client.publish(smokeSensor_topic, String(val).c_str(), false); // Публикуем состояние датчика дыма
Serial.println("Дыма нет D5!!!");
}

Wire.begin();
while(!bme280.begin())
{
Serial.println("Could not find BME280 sensor 76!");
delay(1000);
}


}

void reconnect_server() {

if (WiFi.status() != WL_CONNECTED){
WiFi.begin(ssid, password);
Serial.println("");
Serial.println("WiFi connect...");
} else {
Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.print("");
}

if(!client.connected() && WiFi.status() == WL_CONNECTED){
if (client.connect("ESP8266Client")) {
Serial.println("Mosquitto connect...");
client.subscribe(motionSensor_topic);
client.subscribe(openSensor_topic1);
client.subscribe(openSensor_topic2);
} else {
Serial.print("failed connect Mosquitto, rc=");
Serial.print(client.state());
Serial.println("");
}
}
}



void IRAM_ATTR ChangeTemp() { // Функция считывания и публикации данных о температуре
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
BME280::presUnit presUnit(BME280::presUnit_Pa);

// Датчик температуры на адресе 0х76
float temp76(NAN), hum76(NAN), pres76(NAN);
bme280.read(pres76,temp76,hum76,tempUnit,presUnit);
Serial.print("Temp76: ");
Serial.print(temp76);
Serial.println("°C");
Serial.print("Humidity76: ");
Serial.print(hum76);
Serial.println("% RH");
Serial.print("Pressure76: ");
Serial.print(pres76*0.00750062,2);
Serial.println(" mmHg");
client.publish(Temp_topic, String(temp76).c_str(), false); // Публикуем температуру
client.publish(Humidity_topic, String(hum76).c_str(), false); // Публикуем влажность
client.publish(Pressure_topic, String(pres76*0.00750062,2).c_str(), false); // Публикуем давление

}


void loop(){

client.loop();

// Блок [Проверка подключения] **********************************************
if (millis() - last_mls > 60000) { // Проверка подключения к сети (раз в 60 сек.)
last_mls = millis();
reconnect_server();
}
// END Блок [Проверка подключения] ******************************************


// Блок [Проверка температуры ] **********************************************
if (millis() - last_mls_temp > 60000) { // Проверка температуры (раз в 60 сек.)
last_mls_temp = millis();
ChangeTemp();
}
// END Блок [Проверка температуры] ******************************************


// Блок [Проверка движения ] **********************************************
if (moveOn = false) { // будем проверять если не зафиксировано сработки датчика
if (millis() - last_mls_move > 3000) { // Проверка датчика движения (раз в 3 сек.)
last_mls_move = millis();
detectsMovementD6();
}
}
if (moveOn = true) { // будем проверять если Зафиксировано сработка датчика
if (millis() - last_mls_moveOff > 15000) { // Проверка (раз в 15 сек.)
last_mls_moveOff = millis();
moveOn=false; // Обнуляем сработку датчика
}
}
// END Блок [Проверка движения] ******************************************


if (Win1On = true) {
delay(10);
if (Win1Old = digitalRead(openSensorD3)){

if(int val = digitalRead(openSensorD3)){
client.publish(openSensor_topic1, String(val).c_str(), false); // Публикуем состояние окна 1
Serial.println("Открыто окно D3!!!");
}else{
client.publish(openSensor_topic1, String(val).c_str(), false); // Публикуем состояние окна 1
Serial.println("Закрыто окно D3!!!");
}
Win1Old = digitalRead(openSensorD3);
}
Win1On = false;
}

if (Win2On = true) {
delay(10);
if (Win2Old = digitalRead(openSensorD4)){
if(int val = digitalRead(openSensorD4)){
client.publish(openSensor_topic2, String(val).c_str(), false); // Публикуем состояние окна 2
Serial.println("Открыто окно D4!!!");
}else{
client.publish(openSensor_topic2, String(val).c_str(), false); // Публикуем состояние окна 2
Serial.println("Закрыто окно D4!!!");
}
Win2Old = digitalRead(openSensorD4);
}
Win2On = false;
}
if (SmokeOn = true) {
delay(10);
if (SmokeOld = digitalRead(smokeSensorD5)){
if(int val = digitalRead(smokeSensorD5)){
client.publish(smokeSensor_topic, String(val).c_str(), false); // Публикуем состояние датчика дыма
Serial.println("Пожар D5!!!");
}else{
client.publish(smokeSensor_topic, String(val).c_str(), false); // Публикуем состояние датчика дыма
Serial.println("Дыма нет D5!!!");
}
SmokeOld = digitalRead(smokeSensorD5);
}
SmokeOn = false;
}
 

Юрий Ботов

Moderator
Команда форума
Ну... это скорее нам надо просить прощения что флудом занимаемся.

А по коду :) ужасно. Нет в целом может даже будет как-то работать (хотя и не всегда правильно), но разбираться в нем крайне сложно - "спагетти код".

C++:
void IRAM_ATTR detectsMovementD6() { // Функция при обнаружении движения на D6
  if (int val = digitalRead(motionSensorD6)) {
    delay(10);
    if (int val = digitalRead(motionSensorD6)) {
      client.publish(motionSensor_topic, String(val).c_str(), false); // Публикуем состояние датчика движения
Тут мы имеем ДВЕ разные переменные val с одинаковым именем и вложенной областью видимости. Причем, на самом деле тут не нужно ни одной.

C++:
void IRAM_ATTR detectsMovementD6() { // Функция при обнаружении движения на D6
  if (digitalRead(motionSensorD6)) {
    delay(10);
    if (digitalRead(motionSensorD6)) {
      client.publish(motionSensor_topic, "1", false); // Публикуем состояние датчика движения
Обратите внимание на "1" - лучше пишите константы вручную вместо String(val),c_str(), они ведь всегда известны из контекста. А на деле во-первых выиграйте в наглядности, во-вторых сэкономите кучу RAM, ее всегда не хватает...
И это везде далее по тексту.

C++:
while(!bme280.begin())
{
Serial.println("Could not find BME280 sensor 76!");
delay(1000);
}
Таймаут при инициализации BME280 не имеет смысла. Либо датчик виден либо нет, тогда и потом не прочухается. Это не USB и не WIFI которым нужно долго и упорно договаривать ся о протоколах, каналах и т.п. Так что достаточно if вместо while.

C++:
  if (moveOn = false) { // будем проверять если не зафиксировано сработки датчика
 
if (moveOn = true) { // будем проверять если Зафиксировано сработка датчика

if (Win1On = true) {

if (Win1Old = digitalRead(openSensorD3)) {
// и дальше по тексту аналогично
Я так понимаю что хотели сделать сравнение но получилось присваивание.

char msg[50];
А это кто? Вы его нигде не используете...

C++:
void IRAM_ATTR detectsOpenD3() { // Функция при обнаружении Открытия окна D3
  Win1On = true;
  Win1Old = digitalRead(openSensorD3);
}

void IRAM_ATTR detectsOpenD4() { // Функция при обнаружении Открытия окна D4
  Win2On = true;
  Win2Old = digitalRead(openSensorD4);
}

void IRAM_ATTR detectsSmokeD5() { // Функция при обнаружении движения на D6
  SmokeOn = true;
  SmokeOld = digitalRead(smokeSensorD5);
}
Практически уверен что эти обработчики прерываний делают совсем не то что вы хотели, учитывая что режим прерываний "CHANGE"

Уфф, пока хватит. Приводите в порядок.

PS С москитом я не имел дела, так что ничего умного не могу сказать.
 

nikolz

Well-known member
Дома 100tx - около 6 метров, 25 МГц. Каждый вечер когда сосед снизу включает люстру - перезагружаю хаб и роутер ибо виснут :)
Как я понял из Ваших коммент. Вы по образованию программист.
Хочу помочь Вам в решении либо понимании Вашей проблемы с соседом.
В данном случае проблема не в интерфейсах а банально - в малой нагрузочной способности вашей линии сети на 220 вольт
----------------
Пример с соседом очень наглядно это подтверждает
Рассмотрим пример с люстрой
Допустим в люстре 4 лампы накаливания по 60 вт
Мы ожидает что они потребляют 240 вт
Но в момент включения сопротивление холодной лампы примерно в 10 раз меньше, чем горячей
Мощность лампочки,Вт25406075100
R холодной нити,Ом15090-10060-6545-5037-40
R горячей
нити, Ом
19301200805650490
Rгор./Rхол.1212131312
В результате в момент включения в максимуме напряжения люстра будет потреблять примерно 6500 вт
и вход сети 220 вольт соседа потянет из общей магистрали 30 ампер
----------------------
Вы соединены с ним практически параллельно
В спокойном режиме Вы с соседом потребляете вместе ампер 5.
В данном случает возникает импульс который приходит к вам по сети 220 вольт в виде просадки сетевого напряжения
и ваши выпрямители на входе ваших устройств не справляются с этим импульсом и пропускают его на чипы
в итоге у вас все виснет.
-----------------------------
В качестве примера могу сказать, что у меня сеть 100 мегабит и длина кабеля от роутера до последней точки 15 метров.
Никогда не бывает сбоя не только от соседа снизу но и сбоку и даже когда сам включаю люстру
-----------------------
Поэтому могу вас заверить что все интерфейсы работают на десятки метров а при понижении частот ниже 100 кГц можете получить и километры.
В вашем случае надо либо менять проводку, либо подключаться к малонагруженной фазе, либо повышать качество работы блоков питания в вашей аппаратуре.
 

Юрий Ботов

Moderator
Команда форума
По образованию я радиоинженер, антенщик. МВТУ им.Баумана. Ничего нового вы не сказали. У меня большая просьба, моим образованием заниматься в личке (вы знаете как ей пользоваться?). У этой темы есть хозяин и у него конкретные проблемы. Хотите ему помочь - помогите, не хотите - не мешайте другим. Хозяину мой пардон.
 

Semedney

Member
C++:
void IRAM_ATTR detectsOpenD3() { // Функция при обнаружении Открытия окна D3
  Win1On = true;
  Win1Old = digitalRead(openSensorD3);
}

void IRAM_ATTR detectsOpenD4() { // Функция при обнаружении Открытия окна D4
  Win2On = true;
  Win2Old = digitalRead(openSensorD4);
}

void IRAM_ATTR detectsSmokeD5() { // Функция при обнаружении движения на D6
  SmokeOn = true;
  SmokeOld = digitalRead(smokeSensorD5);
}
Практически уверен что эти обработчики прерываний делают совсем не то что вы хотели, учитывая что режим прерываний "CHANGE"
Спасибо.
Все что выше я понял, буду разбираться.
А что с этими обработчиками я не совсем понимаю.
Цель была такая, отловить момент когда на пине прошло какое либо изменение в функции прерывания, установить флаг о том что изменение прошло, далее в основном цикле по флагу проверить что именно произошло включение или выключение.
 

Semedney

Member
По образованию я радиоинженер, антенщик. МВТУ им.Баумана. Ничего нового вы не сказали. У меня большая просьба, моим образованием заниматься в личке (вы знаете как ей пользоваться?). У этой темы есть хозяин и у него конкретные проблемы. Хотите ему помочь - помогите, не хотите - не мешайте другим. Хозяину мой пардон.
Юрий,
возник еще один вопрос, а именно какие пины можно использовать для ввода а какие нет? При каких условиях ?

А именно сомнения по использованию:
D3, D4, D7, D8 - герконы, (датчики открытия) по умолчанию на пине должен быть Высокий уровень т.е. = "Закрыто", при сработке Низкий уровень = "Открыто"

D5, D6, D9, D10 - датчики дыма и движения, по умолчанию на пине должен быть низкий уровень т.е. = "Покой", при сработке Высокий = "Активно"

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

Semedney

Member
Юрий,
возник еще один вопрос, а именно какие пины можно использовать для ввода а какие нет? При каких условиях ?

А именно сомнения по использованию:
D3, D4, D7, D8 - герконы, (датчики открытия) по умолчанию на пине должен быть Высокий уровень т.е. = "Закрыто", при сработке Низкий уровень = "Открыто"

D5, D6, D9, D10 - датчики дыма и движения, по умолчанию на пине должен быть низкий уровень т.е. = "Покой", при сработке Высокий = "Активно"

Читаю, у почти большинства пинов есть несколько функций, каке то нельзя подтягивать к минусу при старте, какие то наоборот, запутался окончательно.
Юрий.
Отвечаю сам себе и попутно задам еще вопросы.

Итак что я понял.
Если Мы используем встроенный подтягивающий резистор и задаем pin на Input с функцией INPUT_PULLUP то устанавливаем pin по умолчанию в высокий уровень, т.е = 1, в данной ситуации у нас получается когда High - Норма, Low - сработка.

Если использовать внешний подтягивающий резистор (номинал так и не понял его, но вроде как 10кОм - так?) и подключем его к земле, то на pin по умолчанию будет низкий уровень, т.е = 0, в данной ситуации у нас получается когда High - сработка , Low - Норма.

Теперь задача, какие пины из D3 - D10 нельзя при старте подтягивать к плюсу, какие к минусу ?
 

Юрий Ботов

Moderator
Команда форума
Цель была такая, отловить момент когда на пине прошло какое либо изменение в функции прерывания, установить флаг о том что изменение прошло, далее в основном цикле по флагу проверить что именно произошло включение или выключение.
Возможно я просто не разобрался с скачками вверх вниз в коде. Попроуйте оставить как есть, если что потом разберемся.
возник еще один вопрос, а именно какие пины можно использовать для ввода а какие нет?
Давайте попробуем использовать пока только то что можно использовать безопасно, если не хватит тогода уже будем думать дальше:
GPIO4/SCL,
GPIO5/SDA - для подключения всех датчиков которые используют I2C (температура/давление...)
GPIO12,
GPIO13,
GPIO14 - для подключения "контактных" датчиков (герконы, кнопки, сенсор движения).
AIN - аналоговый вход тоже можно использовать как цифровой.

Все остальное делится на несколько категорий:
- нельзя использовать никогда и никак: GPIO6-GPIO11 - их использует процессор для чтения/записи кода и данных его собственного SPI FLASH.
- можно использовать но понимая, что при перепрошивке на них будет полный ужас - GPIO1/TX, GPIO3/RX (то есть как входы их использовать можно, но как выходы - только четко понимая как подключенные снаружи устройства будут реагировать на перепрошивку)
- только как выход GPIO16. Просто он на самом деле вообще не GPIO, а выход RTC которым можно программно управлять
- выводы критичные к моменту подачи питания или ресета: GPIO0 - использовать не стоит, по сути он указывает как процессору загружаться: в нормальном режиме или в режиме загрузки. При использовании придется городить специальную внешнюю обвеску которая будет отвечать за поведение при включениии питания. GPIO2 при рестарте должен быть 0, а GPIO15 при рестарте должен быть 1. Проще использовать их как выходы, ибо для использования как входов также придется городить внешнюю обвеску которая при рестарте будет притягивать их куда надо.
Если Мы используем встроенный подтягивающий резистор и задаем pin на Input с функцией INPUT_PULLUP то устанавливаем pin по умолчанию в высокий уровень, т.е = 1,
Нет. Подтяжка это немного другое. Допустим выход без подтяжки: цепляем светодиод с выхода на питание - моргает, с выхода на землю ... не моргает, тишина. Если включить на выходе подтяжку будет моргать при обеих видах подключения. Представляете транзистор? Выход без подтяжки это просто его коллектор, никак не связанный с выводом питания, поэтому если с коллектора подключить лампочку к земле - она не будет светиться, цепь не замкнута. А резистор подтяжки как раз замыкает цепь с коллектора транзистора на питание. (ну да транзисторы там конечно другие, не биполярные, но идея та-же).
То есть:
- если включить внутреннюю подтяжку и подать на выход 1 на выходе будет 1 относительно земли
- если включить внутреннюю подтяжку и подать на выход 0 на выходе будет 0 относительно земли
- если убрать внутреннюю подтяжку и подать на выход 1 на выходе будет 0 относительно земли
- если убрать внутреннюю подтяжку и подать на выход 0 на выходе будет 0 относительно земли

- если включить внутреннюю подтяжку и подать на выход 1 на выходе будет 0 относительно питания
- если включить внутреннюю подтяжку и подать на выход 0 на выходе будет 1 относительно питания
- если убрать внутреннюю подтяжку и подать на выход 1 на выходе будет 0 относительно питания
- если убрать внутреннюю подтяжку и подать на выход 0 на выходе будет 1 относительно питания
 

Юрий Ботов

Moderator
Команда форума
Если Мы используем встроенный подтягивающий резистор и задаем pin на Input с функцией INPUT_PULLUP то устанавливаем pin по умолчанию в высокий уровень, т.е = 1, в данной ситуации у нас получается когда High - Норма, Low - сработка.
Если использовать внешний подтягивающий резистор (номинал так и не понял его, но вроде как 10кОм - так?) и подключем его к земле, то на pin по умолчанию будет низкий уровень, т.е = 0, в данной ситуации у нас получается когда High - сработка , Low - Норма.
Перечитал это заново и понял что отвечал не на то что нужно. Я писал про подтяжку на выходе а вы про вход.
Путано. Давайте я напишу:
Есть вход GPIO контроллера. Кидаем с него резистор подтяжки на питание (живой снаружи или используя INPUT_PULLUP). Контур охраны (нормально разомкнутый геркон - геркон который замкнут когда окно закрыто и магнит рядом с герконом и геркон разомкнут когда окно открыто) подстоединяем со входа на землю. Закрываем окно. В нормальном состоянии имеем на ноге GPIO - 0. Открываем окно - получаем 1 на входе GPIO.
Для нормально замкнутого геркона делаем наоборот. Есть вход GPIO контроллера. Кидаем с него резистор подтяжки на землю (живой снаружи). Контур охраны (нормально замкнутый геркон - геркон который разомкнут когда окно закрыто и магнит рядом с герконом и геркон замкнут когда окно открыто) подстоединяем со входа на питание. Закрываем окно. В нормальном состоянии имеем на ноге GPIO - 0. Открываем окно - получаем 1 на входе GPIO.
Общая идея такая.
Что до внешнего резистора подтяжки: подбирайте из диапазона 1кОм - 100кОм.
При меньших значениях меньше чувствительность к электромагнитным шумам но больше потребление из источника питания. Сначала попробуйте побольше, потом если будут ложные срабатывания - уменьшайте номинал.
 

Юрий Ботов

Moderator
Команда форума
Кстати :) есть классический способ обхода таких сигнализаций - выдавить стекло и положить на геркон другой магнит. Поэтому в мало-мальски серьезных системах клеят еще пьезодатчик на стекло, который "слышит" момент раскалывания стекла. Я думаю вы их не раз видели.
 

svs2007m

Active member
мало-мальски серьезных системах ставятся адекватные системы а не китайский ширпотреб. Дружище, автор темы если ты хочешь что-то сохранить в случае .... Ты думаешь куча "дебилов" понаоткрывала охранные агентства от балды ? Там "бауманка " факультатив. Где как зачем и почему на раз.
ГЛАВНЫЙ ВОПРОС кто мах. за 3 мин приедет и примет решение.
Если ты думаешь что ТЫ то слино ошибаешься. (или учи УПК и УК)
 

Semedney

Member
мало-мальски серьезных системах ставятся адекватные системы а не китайский ширпотреб. Дружище, автор темы если ты хочешь что-то сохранить в случае .... Ты думаешь куча "дебилов" понаоткрывала охранные агентства от балды ? Там "бауманка " факультатив. Где как зачем и почему на раз.
ГЛАВНЫЙ ВОПРОС кто мах. за 3 мин приедет и примет решение.
Если ты думаешь что ТЫ то слино ошибаешься. (или учи УПК и УК)
Ну тут больше не о безопасности идет речь конечно, я прекрасно понимаю что обойти такой датчик нет проблем, тут я больше орентируюсь на что бы не забыть открытое оно или дверь при отъезде, в доме 11 окон и бегать по всем комнатам что бы проверить как то долго.
А насчет охраны, то тут у меня сосед есть с ружом, и дом у него двух этажный, видит он мой как на ладони. :D
 

Semedney

Member
Перечитал это заново и понял что отвечал не на то что нужно. Я писал про подтяжку на выходе а вы про вход.

Спасибо.
Вроде удалось написать работающий код.
Для датчика движения я использовал GPIO15


Теперь вопрос такой, что делать со всеми не используемыми пинами при сборе устройства?

Как можно питать схему через пин VIN 5V, читал что можно туда подавать 5-18 В так ?
Хочу тянуть питание 12 вольт и раздовать его на несколько плат.
Также от него питать датчик дыма
 

Semedney

Member
Код:
// Блок [Подключение библиотек] ************************************************
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <BME280I2C.h>
#include <Wire.h>
// END Блок [Подключение библиотек] ********************************************
 
// Блок [Подключение к сети WI-FI] *********************************************
const char* ssid = "ХХХХХХХХ";                // Имя WI-FI сети
const char* password = "ХХХХХХХХХХХХ";        // Пароль WI-FI сети
const char* mqtt_server = "192.168.2.3";      // IP адрес MQTT сервер
// END Блок [Подключение к сети WI-FI] *****************************************
 
#define openSensor1   D5 // пин, к которому подключен датчик Окна 1
#define openSensor2   D6 // пин, к которому подключен датчик Окна 2
#define smokeSensor   D7 // пин, к которому подключен датчик Дыма


#define motionSensor   D8 // пин, к которому подключен датчик Движения


 


#define Temp_topic "ESP/Temp"      // Топик Температуры
#define Humidity_topic "ESP/Humidity"      // Топик Влажности
#define Pressure_topic "ESP/Pressure"      // Топик Давления

#define motionSensor_topic "ESP/Motion"      // Топик датчика движения
#define openSensor_topic1 "ESP/WINDOWS_1"     // Топик датчика окна 1
#define openSensor_topic2 "ESP/WINDOWS_2"     // Топик датчика окна 2
#define smokeSensor_topic "ESP/SMOKE"     // Топик датчика Дыма
 
/*
WiFiClient espClient;
PubSubClient client(espClient);
*/
BME280I2C bme280;
long last_mls_temp = millis();
float temp76(NAN), hum76(NAN), pres76(NAN);
float old_temp(NAN), old_hum(NAN), old_pres(NAN);


boolean Win1On = false;
int Win1Old;

boolean Win2On = false;
int Win2Old;

boolean SmokeOn = false;
int SmokeOld;

boolean moveOn = false;

long last_mls_move = millis();
long last_mls_moveOff = millis();
/*
long last_mls = millis();



*/




void IRAM_ATTR detectsMovement() { // Функция при обнаружении движения на
    
    if(digitalRead(motionSensor)){
 
    delay(50);
    
        if(digitalRead(motionSensor)){
          if (moveOn == false) {
          //client.publish(motionSensor_topic, "1" , false); // Публикуем состояние датчика движения 
          Serial.println("Движение !");
          moveOn = true;
          }
        }
      
    }
}


void IRAM_ATTR detectsOpen1() { // Функция при обнаружении Открытия окна 1
    Win1On = true;
    Win1Old = digitalRead(openSensor1);
 }

void IRAM_ATTR detectsOpen2() { // Функция при обнаружении Открытия окна 2
    Win2On = true;
    Win2Old = digitalRead(openSensor2);
 }


void IRAM_ATTR detectsSmoke() { // Функция при обнаружении Дыма
  SmokeOn = true;
  SmokeOld = digitalRead(smokeSensor);
}


void setup() {

  Serial.begin(115200);
/* 
  client.setServer(mqtt_server, 1883);
  delay(100);
  WiFi.begin(ssid, password);
  delay(6000);
  client.connect("ESP8266Client");
*/ 
 
  pinMode(motionSensor, INPUT_PULLUP); // уставливаем пин  на прием и включаем внутренний подтягивающий
  
 

    
  pinMode(openSensor1, INPUT_PULLUP); // уставливаем пин  на прием и включаем внутренний подтягивающий резистор
  attachInterrupt(openSensor1, detectsOpen1, CHANGE); // Прерывание для датчика окна запуск функции  detectsOpen1 
  Win1On = true;
  Win1Old = digitalRead(openSensor1);
    
  pinMode(openSensor2, INPUT_PULLUP); // уставливаем пин  на прием и включаем внутренний подтягивающий резистор
  attachInterrupt(openSensor2, detectsOpen2, CHANGE); // Прерывание для датчика окна запуск функции  detectsOpen2   
  Win2On = true;
  Win2Old = digitalRead(openSensor2);

  pinMode(smokeSensor, INPUT); // уставливаем пин на прием
  attachInterrupt(smokeSensor, detectsSmoke, CHANGE); // Прерывание для датчика движения запуск функции 
  SmokeOn = true;
  SmokeOld = digitalRead(smokeSensor);

  
Wire.begin();
delay(500);
  if (!bme280.begin()){Serial.println("Could not find BME280 sensor 76!");}

    
}

/*
void reconnect_server() {
 
  if (WiFi.status() != WL_CONNECTED){
    WiFi.begin(ssid, password);
    Serial.println("");
    Serial.println("WiFi connect...");
  } else {
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    Serial.print("");
  }
 
  if(!client.connected() && WiFi.status() == WL_CONNECTED){
    if (client.connect("ESP8266Client")) {
      Serial.println("Mosquitto connect...");
  client.subscribe(motionSensor_topic);
  client.subscribe(openSensor_topic1);
  client.subscribe(openSensor_topic2);
    } else {
      Serial.print("failed connect Mosquitto, rc=");
      Serial.print(client.state());
      Serial.println("");
    }
  }
}
*/


void IRAM_ATTR ChangeTemp() { // Функция считывания и публикации данных о температуре
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
BME280::PresUnit presUnit(BME280::PresUnit_Pa);
// Датчик температуры на адресе 0х76
bme280.read(pres76,temp76,hum76,tempUnit,presUnit);
if (isnan(temp76) || isnan(hum76) || isnan(pres76) ) {
//if (isnan(temp76)) { 
      Serial.println("Ошибка чтения датчика BME280");
    }
    else
    {
        if (old_temp == temp76*10)
         {
         Serial.println("Данные температуры не изменились !");
         }
        else
        {
          Serial.print("Temp76: ");
          Serial.print(temp76);
          Serial.println("°C");
          //client.publish(Temp_topic, String(temp76,1).c_str(), false); // Публикуем температуру         
          //client.loop();
          old_temp = temp76*10;
        }

      if (old_hum == round(hum76))
         {
         Serial.println("Данные влажности не изменились !");
         }
        else
        {
          Serial.print("Humidity76: ");
          Serial.print(round(hum76));
          Serial.println("% RH");
          //client.publish(Humidity_topic, String(round(hum76)).c_str(), false); // Публикуем влажность         
          //client.loop();
          old_hum = round(hum76);
        }   

      if (old_pres == round(pres76))
         {
         Serial.println("Данные давления не изменились !");
         }
        else
        {
          Serial.print("Pressure76: ");
          Serial.print(round(pres76*0.00750062));
          Serial.println(" mmHg");
          //client.publish(Pressure_topic, String(round(pres76*0.00750062)).c_str(), false); // Публикуем давление       
          //client.loop();
          old_pres = round(pres76);
        }       
    }
}


void loop(){
 

 
// Блок [Проверка подключения] **********************************************

/*
client.loop();
if (millis() - last_mls > 60000) { // Проверка подключения к сети (раз в 60 сек.)
    last_mls = millis();
    reconnect_server();
}
*/
// END Блок [Проверка подключения] ******************************************


// Блок [Проверка температуры ] **********************************************
if (millis() - last_mls_temp > 60000) { // Проверка температуры  (раз в 60 сек.) 60000
    last_mls_temp = millis();
    ChangeTemp();
}
// END Блок [Проверка температуры] ******************************************


// Блок [Проверка движения ] **********************************************
 detectsMovement();

if (moveOn == false) { // будем проверять если не зафиксировано сработки датчика
  if (millis() - last_mls_move > 3000) { // Проверка датчика движения (раз в 3 сек.)
      last_mls_move = millis();
      detectsMovement();
  }
}

if (moveOn == true) { // будем проверять если Зафиксировано сработка датчика, что бы сбросить сработку
  if (millis() - last_mls_moveOff > 15000) { // Проверка  (раз в 15 сек.)
      last_mls_moveOff = millis();
      moveOn=false; // Обнуляем сработку датчика
      //client.publish(motionSensor_topic, "0" , false); // Публикуем состояние датчика движения
      Serial.println("Все тихо !");
  }
}
// END Блок [Проверка движения] ******************************************



if (Win1On == true) {
    delay(10);
    if (Win1Old == digitalRead(openSensor1)){
    
      if(digitalRead(openSensor1)){
        //client.publish(openSensor_topic1, "1", false); // Публикуем состояние окна 1   
        //client.loop();
        Serial.println("Открыто окно 1");
      }else{
        //client.publish(openSensor_topic1, "0", false); // Публикуем состояние окна 1 
        //client.loop();
        Serial.println("Закрыто окно 1");
      }
    Win1Old = digitalRead(openSensor1); 
    }
  Win1On = false;
}


if (Win2On == true) {
    delay(10);
    if (Win2Old == digitalRead(openSensor2)){
      if(digitalRead(openSensor2)){
        //client.publish(openSensor_topic2, "1", false); // Публикуем состояние окна 2 
        //client.loop();
        Serial.println("Открыто окно 2");
      }else{
        //client.publish(openSensor_topic2, "0", false); // Публикуем состояние окна 2 
        //client.loop();
        Serial.println("Закрыто окно 2");
      }
    Win2Old = digitalRead(openSensor2);
    }
  Win2On = false;
}


if (SmokeOn == true) {
    delay(10);
    if (SmokeOld == digitalRead(smokeSensor)){ 
      if(digitalRead(smokeSensor)){
        //client.publish(smokeSensor_topic, "1", false); // Публикуем состояние датчика дыма 
        //client.loop();
        Serial.println("Пожар !");
      }else{
        //client.publish(smokeSensor_topic, "0", false); // Публикуем состояние датчика дыма 
        //client.loop();
        Serial.println("Дыма нет  !");
      }
    SmokeOld = digitalRead(smokeSensor);
    }
  SmokeOn = false;
}

}
 

Юрий Ботов

Moderator
Команда форума
Как можно питать схему через пин VIN 5V, читал что можно туда подавать 5-18 В так ?
Не знаю там входа 5V. Есть Vin на который можно подать 4.3-16 вольт (из даташита на стоящий там стабилизатор)
Теперь вопрос такой, что делать со всеми не используемыми пинами при сборе устройства?
Да ничего особенного делать не надо. С точки зрения повышения помехоустойчивости, можно посадить их на землю, а в коде сделать pinMode(XX,INPUT). Но разумеется это только для тех выводов от поведения которых не зависит загрузка и которые не используются процессором независимо от вас.
Хочу тянуть питание 12 вольт и раздовать его на несколько плат.
Нормально.
 
Сверху Снизу