The physical button without Internet does not work

Вітаю друзі.

Допоможіть будь ласка. Вже не знаю що робити. Все працює як слід, але коли пропадає інтернет- не працює фізична кнопка. Без інтернету не можу увімкнути чи вимкнути реле. Хоч, наприклад, на подібному пристрої з дисплеєм, з таким же кодом, данні про температуру на дисплей надходять і без інтернету. Але кнопка реле все одно не працює без інтернету.
Я не можу зрозуміти в чому причина і що робити.

Greetings friends

Help please. I do not know what to do. Everything works as it should, but when the Internet disappears, the physical button does not work. Without the internet, I can not turn on or off the relay. Though, for example, on such a device with a display with the same code, data about the temperature on the display are also received without the Internet. But the relay button still does not work without the internet.
I can not understand what the reason is and what to do.

physical button - BUTTON_USER
relay - RELAY

void setup()
{
	// Конфігуруємо підключення до blynk server
	Blynk.config(settings.blynkToken, settings.blynkServer, atoi(settings.blynkPort));

	if (Blynk.connect())
	{
		//TODO
	}
	else
	{
		//TODO
	}

	// Setup a function to be called every second
	timer.setInterval(INTERVAL_SEND_DATA, timerSendServer);
	timer.setInterval(INTERVAL_READ_KEY, timerReadKey);
}

// the loop function runs over and over again until power down or reset
void loop()
{
	Blynk.run(); // Initiates Blynk Server
	timer.run(); // Initiates BlynkTimer
	httpServer.handleClient(); // Initiates OTA WebUpdater

	if (!Blynk.connected() && !triggerBlynkConnect)
	{
		triggerBlynkConnect = true;
		ticker.attach(2, tick);
	}
	else if (Blynk.connected() && triggerBlynkConnect)
	{
		triggerBlynkConnect = false;
	}	
}

BLYNK_CONNECTED()
{
	untick();

	char str[30];
	sprintf(str, "%s Online!", host);
	Blynk.notify(str);
	
	switch (settings.stateRelay)
	{
	case 0:
		Blynk.virtualWrite(BUTTON_RELAY, LOW);		
		break;
	case 1:
		Blynk.virtualWrite(BUTTON_RELAY, HIGH);		
		break;
	case 2:		
		Blynk.syncVirtual(BUTTON_RELAY);
		break;
	default:
		break;
	}
	
	Blynk.syncAll();	
	
	lcd.clear();
	lcd.print(0, 0, host);
	lcd.print(0, 1, WiFi.localIP().toString());

}

BLYNK_WRITE(BUTTON_RELAY)
{		
	digitalWrite(RELAY, param.asInt());		
}

BLYNK_WRITE(MENU_MODE_POWER)
{
	if (settings.stateRelay != param.asInt() - 1)
	{
		settings.stateRelay = param.asInt() - 1;

		// Записуємо введені данні до EEPROM
		EEPROM.begin(512);
		EEPROM.put(0, settings);
		EEPROM.end();
	}
}

void timerReadKey()
{
	if (!digitalRead(BUTTON_USER) && !btnState)
	{
		btnState = true;
		startPressBtn = millis();
	}
	else if (digitalRead(BUTTON_USER) && btnState)
	{
		btnState = false;
		int pressTime = millis() - startPressBtn;

		if (pressTime > INTERVAL_PRESSED_LONG)
		{
			WMSettings defaults;
			settings = defaults;

			// Записуємо данні за замовчуванням до EEPROM
			EEPROM.begin(512);
			EEPROM.put(0, settings);
			EEPROM.end();

			WiFi.disconnect();
			delay(1000);

			ESP.restart();
			delay(1000);
		}
		else if (pressTime < INTERVAL_PRESSED_LONG && pressTime > INTERVAL_PRESSED_SHORT)
		{
			//TODO тут вставити те що буде виконуватись при натисканні кнопки УВІМ/ВИМК
			digitalWrite(RELAY, !digitalRead(RELAY));
			Blynk.virtualWrite(BUTTON_RELAY, digitalRead(RELAY));
		}
		else if (pressTime < INTERVAL_PRESSED_SHORT)
		{
			// Хибне спрацювання для відладки
			char str[30];
			sprintf(str, "Fixed false triggering %ims", pressTime);
			Serial.println(str);
			terminal.println(str);			
		}
	}
}

void timerSendServer()
{
	if (Blynk.connected())
	{
		//TODO
	}
	else
	{
		//TODO
	}
}

void tick()
{
	//toggle state
	int state = digitalRead(LED_GREEN);  // get the current state of GPIO pin
	digitalWrite(LED_GREEN, !state);     // set pin to the opposite state
}

void untick()
{
	ticker.detach();
	digitalWrite(LED_GREEN, HIGH); //keep LED off
}
1 Like

are you aware that blynk is a blocking routine? it means until it can’t speak to the server, it keeps blocking the rest of the code and nothing else can work.

there are several topics / solutions on this forum, just read this:

the solution provided by @Costas it works ok!

1 Like

@wanek дякую за відповідь. Я спробую той спосіб. Не розумію тоді чому інформація на дисплей надсилається (в іншому проекті), blynk не блокує. А опитування кнопки блокує.

@wanek thanks for the answer. I will try that way. I do not understand why the information on the display is sent (in another project), the blynk does not block. And the poll of the button is blocked.

it is hard to say without knowing the setup / code

@wanek абсолютно все те саме, що вивід на дисплей, що опитування кнопки. дисплей оновлює інформацію. кнопки не опитуються (не міняється стан реле).

@wanek absolutely everything is the same as the display output that the poll of the button. the display updates information. the buttons are not interrogated (the state of the relay does not change).

void timerReadKey()
{
	if (!digitalRead(BUTTON_USER) && !btnState)
	{
		btnState = true;
		startPressBtn = millis();
	}
	else if (digitalRead(BUTTON_USER) && btnState)
	{
		btnState = false;
		int pressTime = millis() - startPressBtn;

		if (pressTime > INTERVAL_PRESSED_LONG)
		{
			Blynk.notify("Device setting reset! Connected WiFi AP this device!");
			display.clear();
			display.drawString(10, 22, "Device setting reset!");
			display.drawString(0, 34, "Connected WiFi AP this device");
			display.display();

			WMSettings defaults;
			settings = defaults;

			// Записуємо данні за замовчуванням до EEPROM
			EEPROM.begin(512);
			EEPROM.put(0, settings);
			EEPROM.end();
			delay(1000);

			WiFi.disconnect();
			delay(1000);

			ESP.restart();
			delay(1000);
		}
		else if (pressTime < INTERVAL_PRESSED_LONG && pressTime > INTERVAL_PRESSED_SHORT)
		{
			digitalWrite(RELAY, !digitalRead(RELAY));
			
			if (Blynk.connected())
			{
				Blynk.virtualWrite(BUTTON_RELAY, digitalRead(RELAY));
				// Serial.println("Button Lamp pressed is Device!");
				terminal.print(String(hour()) + ":" + minute() + ":" + second() + " - ");
				terminal.println("Button Lamp pressed is Device!");
			}
			
			display.clear();
			display.setFont(ArialMT_Plain_24);
			display.setTextAlignment(TEXT_ALIGN_CENTER);

			if (digitalRead(RELAY) == HIGH)
			{
				display.drawString(64, 22, "ON");
			}
			else
			{
				display.drawString(64, 22, "OFF");
			}

			display.display();
		}
		else if (pressTime < INTERVAL_PRESSED_SHORT)
		{
			char str[30];
			sprintf(str, "Fixed false triggering %ims", pressTime);
			// Serial.println(str);
			if (Blynk.connected())
			{
				terminal.print(String(hour()) + ":" + minute() + ":" + second());
				terminal.println(str);
				terminal.flush();
				// Blynk.notify(str);
			}			
		}
	}
}

void timerRefreshData()
{
	lamp_status = digitalRead(RELAY);

	float temp_h_dht22 = dht.readHumidity();
	float temp_t_dht22 = dht.readTemperature();

	if (isnan(temp_h_dht22) || isnan(temp_t_dht22))
	{
		terminal.print(String(hour()) + ":" + minute() + ":" + second() + " - ");
		terminal.println("DHT22 is read error!");
		terminal.flush();
	}
	else
	{		
		h_dht22 = temp_h_dht22;
		t_dht22 = temp_t_dht22;
		hic = dht.computeHeatIndex(t_dht22, h_dht22, false);		
	}

	ShowDataDisplay(t_dht22, h_dht22, hic, lamp_status);
}

void ShowDataDisplay(float t_dht22, float h_dht22, float hic, bool lamp_status)
{
	display.clear();
	display.setFont(ArialMT_Plain_10);
	display.setTextAlignment(TEXT_ALIGN_LEFT);
	display.drawString(0, 12, String("Time: ") + hour() + ":" + twoDigits(minute()));
	display.drawString(0, 24, "TmpDHT: " + String(t_dht22, 1) + " / " + String(hic, 1) + "C");
	display.drawString(0, 36, "HumDHT: " + String(h_dht22, 1) + "%");

	if (lamp_status)
	{
		display.drawString(0, 48, "Relay is On!");
	}
	else
	{
		display.drawString(0, 48, "Relay is Off!");
	}

	display.display();
}

hm, not sure about this.

maybe the blynk.run blocks the code for a long time (say 30 seconds), then, if can not connect to the server, it allows the main loop to run once, blocks the code for another 30 seconds, etc.

in this scenario, the the display can update itself time by time, and the user not realises that it is not updating in real time.

but if you try to press a button, it is not possible, because that should happen in real time. but this is just my theory! if you have time, you can test it, introducing a serial println in main loop, and print the millis. than you can see how often gets executed without internet…

@Dmitriy or @vshymanskyy could give a better answer for this!

@wanek , можливо і так. Але в мене дисплей оновлюється кожні 5 секунд по таймеру. Я дихаю на DTH22 і чітко, раз в 5 секунд на дисплеї міняється вологість і температура. А також при втраті з’єднання з blynk спрацьовує миготіння світлодіода раз на 2 секунди і це чітко працює раз на дві секунди. В коді це:

@wanek, maybe so. But my display is updated every 5 seconds by the timer. I breathe on DTH22 and clearly, every 5 seconds the display changes humidity and temperature. And also when the connection to blynk is lost, the blinking of the LED flashes every 2 seconds and it works clearly every two seconds. In the code is:

ticker.attach(2, tick);

void tick()
{
	//toggle state
	int state = digitalRead(LED_GREEN);  // get the current state of GPIO pin
	digitalWrite(LED_GREEN, !state);     // set pin to the opposite state
}

Світлодіод і дисплей нічого не гальмує. А от опитування кнопок гальмується? Спочатку опитування кнопок в мене було в головному циклі. Коли помітив що при втраті з’єднання з blynk перестає працювати виключно опитування кнопки, а дисплей і світлодіод, які висять на таймерах - працюють. Я переніс опитування кнопки теж на таймер. Але це не допомогло. Коли є зв’язок з blynk - кнопка працює як слід. Коли втрачено з’єднання - кнопка не працює.

The LED and the display does not slow down anything. But the questioning of the buttons is slowed down? Initially, I surveyed the buttons in the main loop. When I noticed that when a connection to blynk was lost, the poll of the button stops working, and the display and the LED that hang on the timers are working. I also carried a poll of the button too on the timer. But that did not help. When there is a connection with a blynk - the button works as it should. When the connection is lost - the button does not work.

You can use interrupt-based timer (Ticker) or gpio interrupt for getting a more precise button readout.
Then use a volatile flag to notify main thread about an event.

1 Like

what i would be interested, is that the blynk.run() function - if there is no internet connection, does block the code forever, or allows the main loop to execute time by time (say every minute or so?).

@vshymanskyy, дякую. Здається це працює. Хоч і з затримкою в 1-3 секунди, але працює.

@vshymanskyy, thank you. It seems like it works. Though with a delay of 1-3 seconds, but works.

Based on how I interpreted the Docs around Blynk.config(), I suspect that it will delay as it either tries to initiate connection or process housekeeping… at least until the Blynk.disconnect() command.

Although the usual solution is to just not call Blynk.run() unless first verifying connection anyhow, with this undocumented code snippet:

void loop()
{
  if (Blynk.connected()) {
    Blynk.run();
    }
  timer.run();
}

@Gunner а цей зразок коду, що ви навели:

@Gunner and this sample code that you have given:

void loop()
{
  if (Blynk.connected()) {
    Blynk.run();
    }
  timer.run();
}

Вирішує проблему затримки коду коли немає зв’язку з Blynk?

Solves the problem of delaying the code when there is no connection with Blynk?

It is part of an overall package… much depends on the MCU type, how intense your code it, whether you need manual or automatic reconnection attempts, etc… there is no single answer.

Вітання! У мене також були проблеми з Blynk коли не було інтернету - скетч просто зависав. Вирішив просто винісши його в окрему функцію, що запускається за таймером, а основні функції прописав в циклі.


Greeting! I also had problems with Blynk when there was no internet - the sketch just got hung up. I solved it simply by expanding it into a separate function that runs through the timer, and the main functions are written in a loop.

@11112 Так, в мене окремі функції, на зняття показників з DTH22, на оновлення інформації на дисплей і миготіння світлодіодом і вони на таймерах і тікерах - це працює. Але! З читанням стану кнопки це не проходить. Навіть в окремій функції і на таймері. Ледве, ледве реагує на кнопку, якщо зчитувати стан в перериваннях. Зараз як раз цим займаюсь, з’явився на це час. Якщо щось путнє вийде - розкажу що до чого.


@11112 Yes, I have separate functions for deselecting DTH22, updating information on the display and flashing an LED and they are on timers and tickers - it works. But! When reading the status of the button it does not pass. Even in a separate function and on a timer. Hardly, it’s hardly responding to a button if you read the state in interruptions. Now I’m just doing it, it’s time for that. If something goes wrong - I’ll tell you what.

Так хлопці!
Для себе я вирішив проблему. Не знаю наскільки це вірно і елегантно, але це дуже просто і працює.
Велике дякую за ідею @Gunner, це він своїм невеличким прикладом навів мене на думку.

Все працює таким чином:

So guys!
I solved the problem for myself. I do not know how true and elegant it is, but it is very simple and working.
Thanks a lot for @Gunner’s idea, this is a small example of what he thought of me.

Everything works like this:

#define INTERVAL_RECONNECT 60000L

timer.setInterval(INTERVAL_RECONNECT, timerReconnect);

void loop()
{
	if (Blynk.connected())
	{
		Blynk.run(); // Initiates Blynk Server  
	}
	
	timer.run(); // Initiates BlynkTimer	
	readKey();	
}

void timerReconnect()
{
	if (!Blynk.connected())
	{
		Blynk.connect();
	}
}

Працює дуже просто. По таймеру кожну хвилину звертається до функції void timerReconnect(), як є з’єднання з Blynk та нічого і не робимо. Коли пропало з’єднання з Blynk, то в функції void loop() ми вже не гальмуємось Blynk.run(); кожного разу, просто раз на хвилину по таймеру намагаємось підключитись до Blynk. Коли з’єднання відновилось - відновлюється і штатна робота. Тепер читання кнопки гальмується раз на хвилину, на короткий час. Це вже не принципово. Мені підходить. І я дуже радий як воно тепер працює.

?До речі, в яких одиницях вимірюється timeout в Blynk.connect();? Хочу скоротити timeout при спробах підключитись, коли втрачено зв’язок з Blynk.

It works very simply. The timer invokes the void timerReconnect () function every minute, as there is a connection to Blynk and does not do anything. When the connection to Blynk has disappeared, then in the void loop () function, we no longer brak Blynk.run (); every time, just once a minute, we try to connect to the Blynk. When the connection is restored - the regular work is restored. Now reading the button is slowed down once a minute, for a short time. This is not fundamentally. Me fit. And I’m very glad how it works now.

By the way, in which units the timeout is measured in Blynk.connect () ;? I want to reduce the timeout when I try to connect when I lose connection with Blynk.

Seconds - default is 30. So with fast connecting ESP you can probably go much less like Blynk.connect(10);

1 Like

@Gunner If I want to have a timeout in 10 seconds, then I have to do this - Blynk.connect (10) ;?
True?

Ha, I read your mind and was editing my prior post with exact answer :smiley:

1 Like

Yes :grinning: