MP3 дверной звонок

Ralgxi
Offline
Зарегистрирован: 16.08.2021

MP3 эвонок на Wemos D1 Mini и DFPlayer Mini с беспроводной WI-FI кнопкой на ESP8266-01

Все звуковые файлы должны лежать в папке «mp3» на TF карте в следующем формате: «0001.mp3», «0002.mp3», «0003.mp3» и т.д.

Приемник слушает порт по которому приходит состояние кнопки и если есть нажатие, то проигрывается мелодия. Пока мелодия воспроизводится на нажатие кнопки приемник не реагирует. После проигрывания, при следующем нажатии будет проигрываться следующая мелодия.

Геркон с нормально разомкнутыми контактами ставится на дверь для останова воспроизведения при ее открывании.

Ralgxi
Offline
Зарегистрирован: 16.08.2021

Скетч приемника:

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <DFPlayer_Mini_Mp3.h>
#include <SoftwareSerial.h>

#define BAUD_RATE 9600

SoftwareSerial swSer(D5, D6, false, 256);    //  d5-Rx  d6-Tx

int vol = 15;
boolean in_zvonok;

#define reed_switch   D1  // Геркон двери

//***************Изменить для себя *************************

const char* host = "esp07_Zvonok";
const char* SSIDDAT = "........";             
const char* PASSSIDDAT = "........";   

//***********************************************************

unsigned int  localUdpPort = 1855;     

char incomingPacket[255];
char  replyPacekt[] = "Hi there! Got the message :-)";
//  "Привет! Сообщение получено :-)"

IPAddress local_IP(192, 168, 8, 1);
IPAddress gateway(192, 168, 8, 1);
IPAddress subnet(255, 255, 255, 0);

WiFiUDP Udp;

//==================================================

/* Для двери */
void Stop_Muzik()
{
  interrupts();
  mp3_stop ();
}

//===================================================

void setup()
{
  Serial.begin(BAUD_RATE);
  swSer.begin(BAUD_RATE);

  pinMode(D7, INPUT);  
  pinMode(reed_switch, INPUT);

  mp3_set_serial(swSer);    
  delay(10);                  
  mp3_set_volume (vol);
  delay (10);
  mp3_set_EQ (5);     // Эквалайзер

  WiFi.hostname(host);
  WiFi.mode( WIFI_AP);       
  Serial.println("");
  Serial.println(WiFi.softAPConfig(local_IP, gateway, subnet) ? "Ready" : "Failed!"); 
  Serial.println("");
  Serial.println(WiFi.softAP(SSIDDAT, PASSSIDDAT) ? "Ready" : "Failed!");     

  delay(1000);

  Serial.println("");
  Serial.printf("Stations connected = %d\n", WiFi.softAPgetStationNum()); 
  Serial.print("Soft-AP IP address = ");        
  Serial.print(WiFi.softAPIP());
  Serial.println("");
  Serial.printf("MAC address = %s\n", WiFi.softAPmacAddress().c_str());        //  "MAC-адрес = "

  Udp.begin(localUdpPort);
  Serial.printf("Now listening at IP %s, UDP port %d\n", WiFi.localIP().toString().c_str(), localUdpPort);

  
  noInterrupts();
  attachInterrupt(reed_switch, Stop_Muzik, CHANGE);
  interrupts();

}

//###########################################

void loop()
{
  int packetSize = Udp.parsePacket();
  if (packetSize)
  {
//  Serial.printf("Received %d bytes from %s, port %d\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());  //  "Получено %d байт от %s, порт %d%"

    int len = Udp.read(incomingPacket, 255);
    if (len > 0) {
      incomingPacket[len] = 0;
    }

    in_zvonok = atoi(incomingPacket);

    // отправляем ответ на IP-адрес и порт, с которых пришел пакет:
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write(replyPacekt);
    Udp.endPacket();

  }

  //================================================

  bool  Busy = (digitalRead (D7));
//  boolean play_state = in_zvonok;
  if (Busy == HIGH) {                     // Низкий означает идет воспроизведение, высокий означает нет
  if (in_zvonok == HIGH) {                     // if (play_state == HIGH) {  
      delay (10);
      in_zvonok = 0;
      mp3_next ();                               //   mp3_random_play (); // Воспроизвести в  случайном порядке.
    }
  }
  else in_zvonok = 0;

  // delay(1000);

}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

В скетче ошибка (в функции Stop_Muzik) из-за которой система будет иногда подвисать без видимых причин. Виновата в этом будет, по установившейся в российском ардуино-сообществе традиции, "китайскость модулей"  (ну, а кто ещё может быть виноват?) :-)))

Ralgxi
Offline
Зарегистрирован: 16.08.2021

Такой ошибки не знаю. В процессе отладки все работало штатно, без каких либо глюков.

Подвисание возможны из-за слишком длинного провода  (было такое на другой конструкции), наведенные помехи.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ralgxi пишет:

Такой ошибки не знаю. 

Так подумайте. Я же Вам даже сказал где именно она.

Я, конечно, могу всё объяснить (скажите, объясню, мне не трудно), но я всегда предпочитаю только дать намёк и оставить человеку шанс дойти самому, это гораздо приятнее и полезнее.

Ralgxi пишет:
В процессе отладки все работало штатно
Это ни о чём не говорит. Я же сказал, "иногда". В том и подлость подобных ошибок, что она глюкнет раз в неделю, потом затаивается до следующего глюка через неделю. И у разработчика очень велик соблазн списать всё на локальную/случайную "вспышку на Солнце" или на "наведённые помехи". 

Ralgxi
Offline
Зарегистрирован: 16.08.2021

Далее кнопка:


#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

//#define button   2  // Кнопка звонка
volatile boolean flag = true;  // флаг нажатой кнопки

//***********Изменить на свои ***********************

const char* host = "esp01_Button";

const char* AP_SSID = "........";
const char* AP_PASS = "........";

//***************************************************

char buff[255];

int packetSize;

unsigned int  localUdpPort = 1855;

IPAddress ip_esp07_Zvonok (192, 168, 8, 1);  // IP адрес первого модуля
IPAddress ipClient(192, 168, 8, 3);
IPAddress Subnet(255, 255, 255, 0);

WiFiUDP Udp;

//=======================================================

void handover()
{
  itoa(flag, buff, 10);

  int packetSize = Udp.parsePacket();         

  if (!packetSize) {
    Udp.beginPacket(ip_esp07_Zvonok, localUdpPort);
    Udp.write(buff);
    Udp.endPacket();
    delay(25);
  }
}

//=====================================================

void setup()
{

  WiFi.hostname(host);
  WiFi.mode( WIFI_STA);          
//  Serial.printf("Connecting to %s ", AP_SSID);    

  WiFi.begin(AP_SSID, AP_PASS);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
 //   Serial.print(".");
  }
//  Serial.println(" connected");      

  WiFi.config(ipClient, ip_esp07_Zvonok, Subnet);

  Udp.begin(localUdpPort);

//  Serial.printf("Now listening at IP %s, UDP port %d\n", WiFi.localIP().toString().c_str(), localUdpPort);
                                                                         

   handover();

// Serial.println("передали и спать");
 
  ESP.deepSleep(0);

}

//=============================================

void loop()
{

  // delay(1000);

}


 

Ralgxi
Offline
Зарегистрирован: 16.08.2021

Спасибо за подсказку. Буду разбираться сам.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Разбирайтесь, удачи. Но, если что, предложение "объяснить" остаётся в силе, обращайтесь.

Ralgxi
Offline
Зарегистрирован: 16.08.2021

ЕвгенийП пишет:

В скетче ошибка (в функции Stop_Muzik) из-за которой система будет иногда подвисать без видимых причин. Виновата в этом будет, по установившейся в российском ардуино-сообществе традиции, "китайскость модулей"  (ну, а кто ещё может быть виноват?) :-)))

Думаю дребезг контакта геркона. Тогда так конечно не вариант. Позже исправлю программу, сейчас на работе, немного некогда.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, не только, но и дребезг тоже. В общем случае, программа зависнет, если функция  будет вызвана менее, чем через 50 мс после того, как вызывалась она же (как раз дребезг) или любая другая функция, которая шлёт команды проигрывателю (см. функцию mp3_send_cmd на предмет почему так). Исправить - там всего одну строчку добавить - просто разрешить прерывания перед вызовом mp3_stop - тогда всё будет нормально.

Ralgxi
Offline
Зарегистрирован: 16.08.2021

ЕвгенийП пишет:

Ну, не только, но и дребезг тоже. В общем случае, программа зависнет, если функция  будет вызвана менее, чем через 50 мс после того, как вызывалась она же (как раз дребезг) или любая другая функция, которая шлёт команды проигрывателю (см. функцию mp3_send_cmd на предмет почему так). Исправить - там всего одну строчку добавить - просто разрешить прерывания перед вызовом mp3_stop - тогда всё будет нормально.

Спасибо за объяснения, я хотел перед mp3_stop запретить прерывание, а по Busy разрешить.

Скетч подправил.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ralgxi пишет:
а по Busy разрешить.
Это бесполезно. Прерывания запрещены в функции обработки прерываний (Stop_Muzik) независимо от того, разрешали Вы их раньше или нет.

Если Вы поправили в посте №1, то так, как сейчас - неправильно. Вы не разрешили прерывания, а просто отключили дальнейший вызов обработчика. В каких-то ситуациях это может не помочь. Надо просто разрешить там прерывания (sei() или interruts() ) и больше ничего мудрить не нужно.

Ralgxi
Offline
Зарегистрирован: 16.08.2021

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ralgxi пишет:

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

Кем и когда оно будет разрешено? В момент входа в обработчик прерывания запрещены. Вы в этом обработчике что делаете? Вызываете mp3_stop. А mp3_stop, в свою очередь, вызывает mp3_send_cmd. Прерывания всё ещё запрещены, ибо их никто не разрешал, так ведь? А Вы эту mp3_send_cmd видели? Я ведь Вам советовал посмотреть на неё. Она начинается вот так:

void mp3_send_cmd (uint8_t cmd, uint16_t high_arg, uint16_t low_arg) {
	unsigned long d = abs(millis() - _last_call);
	if (d < 50) {
		delay(50 - d);
	}
	...

А delay устроен вот так:

void delay(unsigned long ms)
{
	uint32_t start = micros();

	while (ms > 0) {
		yield();
		while ( ms > 0 && (micros() - start) >= 1000) {
			ms--;
			start += 1000;
		}
	}
}

Что имеем? Если, по каким-то причинам (например, из-за дребезга геркона, обработки которого ни в схеме, ни в программе нет), mp3_stop будет вызвана менее, чем через 50мс после последнего вызова (её же или любой другой функции, вызывающей mp3_send_cmd), то delay превратится в вечное ожидание, т.к. прерывания запрещены, а значение, возвращаемое micros(), при закрытых прерываниях изменяться не будет.

Необходимо разрешить прерывания перед вызовом mp3_stop. Сразу "наведённых помех" станет меньше, да и модули станут менее китайскими :-)

Ralgxi
Offline
Зарегистрирован: 16.08.2021

Огромная благодарность Вам за разъяснения, скетч поправил. Думаю еще параллельно геркону поставить конденсатор 0,01 мкф от дребезга.

Анатолий89
Offline
Зарегистрирован: 16.03.2021

Зачем нужен звонок если есть домофон?

Ralgxi
Offline
Зарегистрирован: 16.08.2021

Анатолий89 пишет:

Зачем нужен звонок если есть домофон?

Свой дом. До калитки метров 12.

Анатолий89
Offline
Зарегистрирован: 16.03.2021

И постоянно к калитке бегаете открывать/закрывать/заряжать?

Анатолий89
Offline
Зарегистрирован: 16.03.2021

На калитку электрозамок надо,вот к чему я...

Ralgxi
Offline
Зарегистрирован: 16.08.2021

Свои так заходят, чужие звонят, геркон стоит на входной двери в дом, питание кнопки от аккумуляторов с ноутбука через DC-DC понижающий/повышающий преобразователь. И не нужно никакого электрозамка. Цель уйти от любых проводов до калитки.

sadman41
Offline
Зарегистрирован: 19.10.2016

Звонка с использованием ip-стека тут ещё не было. Дальше дело за SSL/TSL, полагаю...

Ralgxi
Offline
Зарегистрирован: 16.08.2021

sadman41 пишет:
Звонка с использованием ip-стека тут ещё не было. Дальше дело за SSL/TSL, полагаю...

Нет, это я не потяну, но в курятнике WI-FI поставил для управления освещением... рассвет\закат...

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

А мне вот непонятно, зачем дверному звонку больше одной мелодии?

Мне всегда казалось, что звук дверного звонка должен быть таким, который невозможно перепутать с каким-либо другим звуком (например, от проигрывателя или телевизора).

Ralgxi
Offline
Зарегистрирован: 16.08.2021

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ralgxi пишет:

Свой дом. 

И что? У меня тоже. Домофону-то это как может помешать? Неужели Вам приятно бежать на улицу каждому калитку открывать, особенно зимой?

sadman41
Offline
Зарегистрирован: 19.10.2016

В такую погоду свои дома сидят, телевизор смотрют. Только чужие шастают...

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Ralgxi пишет:

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

Вам нравится на каждую новую мелодию, доносящуюся из радиоприемника, бежать и открывать калитку?

Как избежать путаницы, если и по содержанию, и по качеству звук дверного замка не будет отличаться от звука музыкального центра?

Ralgxi
Offline
Зарегистрирован: 16.08.2021

andriano пишет:

Вам нравится на каждую новую мелодию, доносящуюся из радиоприемника, бежать и открывать калитку?

Как избежать путаницы, если и по содержанию, и по качеству звук дверного замка не будет отличаться от звука музыкального центра?

Глупости не говорите, если вы не отличаете, мои какие проблемы.

Ralgxi
Offline
Зарегистрирован: 16.08.2021

Домофон даже и не думаю ставить. Не вижу такой необходимости.

Ralgxi
Offline
Зарегистрирован: 16.08.2021

Изменил схему.