Показ дописів із міткою Blynk. Показати всі дописи
Показ дописів із міткою Blynk. Показати всі дописи

середу, 16 грудня 2020 р.

Blynk: підключення до точки WiFi та серверу Blynk, очікування WiFi точки, перепідключення до WiFi та серверу Blynk, робота основного коду без блокування при очікування з'єднання для ESP32/ESP8266

Передмова

Помітив, що багато початківців, які хочуть створити для себе IoT пристрій на базі WiFi мікроконтролера ESP8266 або ESP32 з системою Blynk, стикаються з такою проблемою як:

  • не виконання коду, поки пристрій не підключиться до точки WiFi;
  • відсутность спроб відновити з'єднання у разі втрати зв'язку з мережею;
  • блокування коду при втраті зв'язку з сервером Blynk.
Як не вирішити ці проблеми пристрій і залишиться поробкою вихідного дня для спробувати. Якийсь путній і завершений пристрій створити з таким підходом неможливо. Бібліотека Blynk потужна і універсальна бібліотека, до якої входять і інші бібліотеки, такі як робота з таймерами, датою, керування підключеннями, і багато іншого. Але! Без власного, продуманого коду створити завершений пристрій, який можна вже і виводити на ринок, або хоча б, щоб він був зручний для власного користування, для дому, для сім'ї - не побудувати. Так що пропоную все ж таки попрацювати над власним кодом, який працює з мережею, та усуває недолік блокування власного коду у разі втрати з'єднання з сервером Blynk. Та досить балачок, давайте розпочнемо, бо насправді не все так складно.

Проблематика

Ми можемо взяти за основу будь який приклад Blynk і вже навколо нього "наростити" свій функціонал. Але це буде не зовсім вірно. Тому пишемо в першу чергу код, який буде, наш модуль WiFi, завжди тримати на зв'язку з точкою WiFi. Та при втраті підключення до Blynk зробити логіку, яка дозволить не блокувати основний код, та періодично намагатись під'єднатись до серверу Blynk.

Поширений приклад для підключення до WiFi нам пропонують в такому вигляді:

#include <ESP8266WiFi.h>

void setup()
{
  Serial.begin(115200);
  Serial.println();

  WiFi.begin("network-name", "pass-to-network");

  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  Serial.print("Connected, IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {}

В цьому прикладі далі циклу while (WiFi.status() != WL_CONNECTED), поки не буде з'єднання з точкою WiFi, програма не виконається. Нам потрібно, щоб спроби приєднатись до точки WiFi були постійними, а код в циклі loop() виконувався та контролював стан з'єднання з точкою WiFi. 

А поширений приклад для підключення до Blynk нам пропонують в такому вигляді:

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "YourAuthToken";

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "YourNetworkName";
char pass[] = "YourPassword";

void setup()
{
  // Debug console
  Serial.begin(9600);

  Blynk.begin(auth, ssid, pass);
  // You can also specify server:
  //Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 80);
  //Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8080);
}

void loop()
{
  Blynk.run();
  // You can inject your own code or combine it with other sketches.
  // Check other examples on how to communicate with Blynk. Remember
  // to avoid delay() function!
}

В цьому випадку, при відсутності WiFi ваш пристрій так і буде "мертвою залізякою", а у разі наявності WiFi і втрати зв'язку з сервером Blynk, ваш код блокуватиметься функцією Blynk.run() яка викликається з циклу loop() і користуватись пристроєм буде не можливо. 

Приклад рішення для ESP8266

Я пропоную такий варіант коду для підтримки зв'язку з точкою WiFi та сервером Blynk без блокування основного коду:

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include "BlynkSimpleEsp8266.h"

const char* ssid        = "MY_SSID";
const char* password    = "MY_PASS";
const char* blynkToken  = "MY_TOKEN";

bool isWiFiConnected = false;
int  numTimerReconnect = 0;

WiFiEventHandler gotIpEventHandler;
WiFiEventHandler disconnectedEventHandler;
BlynkTimer timer;

void WiFiStationConnected(const WiFiEventStationModeGotIP& event);
void WiFiStationDisconnected(const WiFiEventStationModeDisconnected& event);
void ReconnectBlynk(void);
void BlynkRun(void);

void setup() 
{
  Serial.begin(115200);
  
  gotIpEventHandler = WiFi.onStationModeGotIP(&WiFiStationConnected);
  disconnectedEventHandler = WiFi.onStationModeDisconnected(&WiFiStationDisconnected);

  WiFi.begin(ssid, password);

  Blynk.config(blynkToken);

  if(Blynk.connect())
  {
    Serial.printf("[%8lu] setup: Blynk connected\r\n", millis());
  }
  else
  {
    Serial.printf("[%8lu] setup: Blynk no connected\r\n", millis());
  }
  
  Serial.printf("[%8lu] Setup: Start timer reconnected\r\n", millis());
  numTimerReconnect = timer.setInterval(60000, ReconnectBlynk);
}

void loop() 
{
  BlynkRun();  
  timer.run();
}

void WiFiStationConnected(const WiFiEventStationModeGotIP& event)
{
  isWiFiConnected = true;
  Serial.printf("[%8lu] Interrupt: Connected to AP, Ip: ", millis());
  Serial.println(WiFi.localIP());
}

void WiFiStationDisconnected(const WiFiEventStationModeDisconnected& event)
{
  isWiFiConnected = false;
  Serial.printf("[%8lu] Interrupt: Disconnected to AP!\r\n", millis());
}

void BlynkRun(void)
{
  if (isWiFiConnected)
  {
    if(Blynk.connected())
    {
      if (timer.isEnabled(numTimerReconnect))
      {
        timer.disable(numTimerReconnect);
        Serial.printf("[%8lu] BlynkRun: Stop timer reconnected\r\n", millis());
      }

      Blynk.run();
    }
    else
    {
      if (!timer.isEnabled(numTimerReconnect))
      {
        timer.enable(numTimerReconnect);
        Serial.printf("[%8lu] BlynkRun: Start timer reconnected\r\n", millis());
      }      
    }
  }
}

void ReconnectBlynk(void)
{
  if (!Blynk.connected())
  {
    if (Blynk.connect())
    {				        
      Serial.printf("[%8lu] ReconnectBlynk: Blynk reconnected\r\n", millis());
    }
    else
    {
      Serial.printf("[%8lu] ReconnectBlynk: Blynk not reconnected\r\n", millis());
    }
  }
  else
  {
    Serial.printf("[%8lu] ReconnectBlynk: Blynk connected\r\n", millis());
  }
}


Приклад рішення для ESP32

Приклад для ESP32 дещо відрізняється з попереднім для ESP8266, але логіка роботи залишається такою самою:

#include <Arduino.h>
#include <WiFi.h>
#include "BlynkSimpleEsp32.h"

const char* ssid        =  "MY_SSID";
const char* password    =  "MY_PASS";
const char* blynkToken  =  "MY_TOKEN";

bool isWiFiConnected = false;
int  numTimerReconnect = 0;

BlynkTimer timer;

void WiFiStationConnected(WiFiEvent_t event, WiFiEventInfo_t info);
void WiFiStationDisconnected(WiFiEvent_t event, WiFiEventInfo_t info);
void ReconnectBlynk(void);
void BlynkRun(void);

void setup() 
{
  Serial.begin(115200);

  WiFi.onEvent(WiFiStationConnected, SYSTEM_EVENT_STA_GOT_IP);
  WiFi.onEvent(WiFiStationDisconnected, SYSTEM_EVENT_STA_DISCONNECTED);
  WiFi.begin(ssid, password);

  Blynk.config(blynkToken);

  if(Blynk.connect())
  {
    Serial.printf("[%8lu] setup: Blynk connected\r\n", millis());
  }
  else
  {
    Serial.printf("[%8lu] setup: Blynk no connected\r\n", millis());
  }

  Serial.printf("[%8lu] Setup: Start timer reconnected\r\n", millis());
  numTimerReconnect = timer.setInterval(60000, ReconnectBlynk);
}

void loop() 
{
  BlynkRun();
  timer.run();
}

void WiFiStationConnected(WiFiEvent_t event, WiFiEventInfo_t info)
{
  isWiFiConnected = true;
  Serial.printf("[%8lu] Interrupt: Connected to AP, IP: ", millis());
  Serial.println(WiFi.localIP());
}

void WiFiStationDisconnected(WiFiEvent_t event, WiFiEventInfo_t info)
{
  isWiFiConnected = false;
  Serial.printf("[%8lu] Interrupt: Disconnected to AP!\r\n", millis());
}

void ReconnectBlynk(void)
{
  if (!Blynk.connected())
  {
    if (Blynk.connect())
    {				        
      Serial.printf("[%8lu] ReconnectBlynk: Blynk reconnected\r\n", millis());
    }
    else
    {
      Serial.printf("[%8lu] ReconnectBlynk: Blynk not reconnected\r\n", millis());
    }
  }
  else
  {
    Serial.printf("[%8lu] ReconnectBlynk: Blynk connected\r\n", millis());
  }
}

void BlynkRun(void)
{
  if (isWiFiConnected)
  {
    if(Blynk.connected())
    {
      if (timer.isEnabled(numTimerReconnect))
      {
        timer.disable(numTimerReconnect);
        Serial.printf("[%8lu] BlynkRun: Stop timer reconnected\r\n", millis());
      }

      Blynk.run();
    }
    else
    {
      if (!timer.isEnabled(numTimerReconnect))
      {
        timer.enable(numTimerReconnect);
        Serial.printf("[%8lu] BlynkRun: Start timer reconnected\r\n", millis());
      }      
    }
  }
}

Розумію, що для початківця це доволі складний код і потребує детальних пояснень. Тому  я підготував відео з поясненням і демонстрацією роботи з кнопкою, світлодіодом і таймером. А також демонстраційний код доступний і для завантаження і для ESP8266 , і для ESP32. Приємного перегляду.

Відео з поясненням і демонстрацією



четвер, 19 вересня 2019 р.

Blynk: шаблон-конструктор для створення прошивок з WiFi Manager, WebOTA та автоматичним перепідключенням до вашого WiFi і серверу Blynk

Передмова

Для зручності створив початковий шаблон-конструктор прошивки для системи Blynk з початковими налаштуваннями по WiFi зі смартфону (SSID, PASS, TOKEN, Name Device). З можливістю оновлювати прошивку по повітрю WebOTA, та перепідключенням до мережі WiFi і серверу Blynk у разі пропадання зв'язку. Плюс, якщо зв'язок буде втрачено, функціонал самого пристрою не буде "гальмувати", а буде працювати в режимі OFFLINE як слід, до наступного підключення до серверу. Є обробка натискання системної кнопки "FLASH" яка під'єднана до GPIO_0 і зазвичай присутня на всіх платах на базі "ESP8266" і пристроїв "IoT", наприклад, дуже популярних "Sonoff". Кнопка розпізнає довжину натискання. Коротке натискання - для свого коду, який буде щось вмикати/вимикати. Довге натискання від 5 до 10 секунд - перезавантаження пристрою. Довге натискання понад 10 секунд - скидання всіх налаштувань.

Код шаблону

Код шаблону можна завантажити на GitHub, Dropbox,  або скопіювати прямо звідси:

/*
 Name:  Blynk_Table_Menu.ino
 Created: 9/19/2019 9:04:46 AM
 Author: Andriy Honcharenko
*/

/* CODE BEGIN Includes */
#include <BlynkSimpleEsp8266.h>
#include <Ticker.h>
#include <EEPROM.h>
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>
#include <WiFiManager.h>
/* CODE END Includes */

/* CODE BEGIN UD */
/* User defines ---------------------------------------------------------*/
#define BLYNK_PRINT Serial

#define NAME_DEVICE      "MyHomeIoT-ESP8266"

#define BUTTON_SYS0_PIN     0
#define LED_SYS_PIN      13

#define BUTTON_SYS_B0_VPIN    V20
#define WIFI_SIGNAL_VPIN    V80

#define INTERVAL_PRESSED_RESET_ESP  3000L
#define INTERVAL_PRESSED_RESET_SETTINGS 5000L
#define INTERVAL_PRESSED_SHORT   50
#define INTERVAL_SEND_DATA    30033L
#define INTERVAL_RECONNECT    60407L
#define INTERVAL_REFRESH_DATA   4065L
#define WIFI_MANAGER_TIMEOUT   180

#define EEPROM_SETTINGS_SIZE   512
#define EEPROM_START_SETTING_WM   0
#define EEPROM_SALT_WM     12661

#define LED_SYS_TOGGLE()    digitalWrite(LED_SYS_PIN, !digitalRead(LED_SYS_PIN))
#define LED_SYS_ON()     digitalWrite(LED_SYS_PIN, LOW)
#define LED_SYS_OFF()     digitalWrite(LED_SYS_PIN, HIGH)
/* CODE END UD */

/* CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
bool shouldSaveConfigWM  = false; //flag for saving data
bool btnSystemState0  = false;
bool triggerBlynkConnect = false;
bool isFirstConnect   = true; // Keep this flag not to re-sync on every reconnection

int startPressBtn = 0;

//structure for initial settings. It now takes 116 bytes
typedef struct {
 char  host[33] = NAME_DEVICE;    // 33 + '\0' = 34 bytes
 char  blynkToken[33] = "";     // 33 + '\0' = 34 bytes
 char  blynkServer[33] = "blynk-cloud.com"; // 33 + '\0' = 34 bytes
 char  blynkPort[6] = "8442";    // 04 + '\0' = 05 bytes
 int   salt = EEPROM_SALT_WM;    // 04   = 04 bytes
} WMSettings;         // 111 + 1  = 112 bytes (112 this is a score of 0)
//-----------------------------------------------------------------------------------------

WMSettings wmSettings;

BlynkTimer timer;

Ticker tickerESP8266;

//Declaration OTA WebUpdater
ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;
/* CODE END PV */

/* CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
static void configModeCallback(WiFiManager* myWiFiManager);
static void saveConfigCallback(void);
static void tick(void);
static void untick(void);
static void readSystemKey(void);
static void timerRefreshData(void);
static void timerSendServer(void);
static void timerReconnect(void);
/* CODE END PFP */

// the setup function runs once when you press reset or power the board

void setup() 
{
 Serial.begin(115200);

 pinMode(BUTTON_SYS0_PIN, INPUT_PULLUP);
 pinMode(LED_SYS_PIN, OUTPUT);

 // Read the WM settings data from EEPROM to RAM
 EEPROM.begin(EEPROM_SETTINGS_SIZE);
 EEPROM.get(EEPROM_START_SETTING_WM, wmSettings);
 EEPROM.end();

 if (wmSettings.salt != EEPROM_SALT_WM) 
 {
  Serial.println(F("Invalid wmSettings in EEPROM, trying with defaults"));
  WMSettings defaults;
  wmSettings = defaults;
 }

 // Print old values to the terminal
 Serial.println(wmSettings.host);
 Serial.println(wmSettings.blynkToken);
 Serial.println(wmSettings.blynkServer);
 Serial.println(wmSettings.blynkPort);

 tickerESP8266.attach(0.5, tick);   // start ticker with 0.5 because we start in AP mode and try to connect

 //Local intialization. Once its business is done, there is no need to keep it around
 WiFiManager wifiManager;

 //reset saved wmSettings
 //wifiManager.resetSettings();

 //set minimu quality of signal so it ignores AP's under that quality
 //defaults to 8%
 //wifiManager.setMinimumSignalQuality();

 //sets timeout before webserver loop ends and exits even if there has been no setup.
 //useful for devices that failed to connect at some point and got stuck in a webserver loop
 //in seconds setConfigPortalTimeout is a new name for setTimeout
 wifiManager.setConfigPortalTimeout(WIFI_MANAGER_TIMEOUT);

 // The extra parameters to be configured (can be either global or just in the setup)
 // After connecting, parameter.getValue() will get you the configured value
 // id/name placeholder/prompt default length
 WiFiManagerParameter custom_device_name_text("<br/>Enter name of the device<br/>or leave it as it is<br/>");
 wifiManager.addParameter(&custom_device_name_text);

 WiFiManagerParameter custom_device_name("device-name", "device name", wmSettings.host, 33);
 wifiManager.addParameter(&custom_device_name);

 WiFiManagerParameter custom_blynk_text("<br/>Blynk config.<br/>");
 wifiManager.addParameter(&custom_blynk_text);

 WiFiManagerParameter custom_blynk_token("blynk-token", "blynk token", wmSettings.blynkToken, 33);
 wifiManager.addParameter(&custom_blynk_token);

 WiFiManagerParameter custom_blynk_server("blynk-server", "blynk server", wmSettings.blynkServer, 33);
 wifiManager.addParameter(&custom_blynk_server);

 WiFiManagerParameter custom_blynk_port("blynk-port", "port", wmSettings.blynkPort, 6);
 wifiManager.addParameter(&custom_blynk_port);

 //set config save notify callback
 wifiManager.setSaveConfigCallback(saveConfigCallback);

 //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
 wifiManager.setAPCallback(configModeCallback);

 //set custom ip for portal
 //wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));

 //fetches ssid and pass from eeprom and tries to connect
 //if it does not connect it starts an access point with the specified name
 //here  "AutoConnectAP"
 //and goes into a blocking loop awaiting configuration
 //wifiManager.autoConnect();
 //or use this for auto generated name ESP + ChipID

 if (wifiManager.autoConnect(wmSettings.host))
 {
  //if you get here you have connected to the WiFi
  Serial.println(F("Connected WiFi!"));
 }
 else
 {
  Serial.println(F("failed to connect and hit timeout"));
 }

 untick(); // cancel the flashing LED

 // Copy the entered values to the structure
 strcpy(wmSettings.host, custom_device_name.getValue());
 strcpy(wmSettings.blynkToken, custom_blynk_token.getValue());
 strcpy(wmSettings.blynkServer, custom_blynk_server.getValue());
 strcpy(wmSettings.blynkPort, custom_blynk_port.getValue());

 // Print new values to the terminal
 Serial.println(wmSettings.host);
 Serial.println(wmSettings.blynkToken);
 Serial.println(wmSettings.blynkServer);
 Serial.println(wmSettings.blynkPort);

 if (shouldSaveConfigWM)
 {
  LED_SYS_ON();
  // Write the input to the EEPROM
  EEPROM.begin(EEPROM_SETTINGS_SIZE);
  EEPROM.put(EEPROM_START_SETTING_WM, wmSettings);
  EEPROM.end();
  //---------------------------------
  LED_SYS_OFF();
 }

 // Run OTA WebUpdater
 MDNS.begin(wmSettings.host);
 httpUpdater.setup(&httpServer);
 httpServer.begin();
 MDNS.addService("http", "tcp", 80);
 Serial.printf("HTTPUpdateServer ready! Open http://%s.local/update in your browser\n", wmSettings.host);

 // Configure connection to blynk server
 Blynk.config(wmSettings.blynkToken, wmSettings.blynkServer, atoi(wmSettings.blynkPort));

 if (Blynk.connect())
 {
  //TODO: something to do if connected
 }
 else
 {
  //TODO: something to do if you failed to connect
 }

 timer.setInterval(INTERVAL_REFRESH_DATA, timerRefreshData);
 timer.setInterval(INTERVAL_SEND_DATA, timerSendServer);
 timer.setInterval(INTERVAL_RECONNECT, timerReconnect); 
}

// the loop function runs over and over again until power down or reset
void loop() 
{
 if (Blynk.connected())
 {
  Blynk.run(); // Initiates Blynk Server  
 }
 else
 {
  if (!tickerESP8266.active())
  {
   tickerESP8266.attach(2, tick);
  }
 }

 timer.run(); // Initiates BlynkTimer
 
 httpServer.handleClient(); // Initiates OTA WebUpdater  

 readSystemKey();
}

/* BLYNK CODE BEGIN */
BLYNK_CONNECTED()
{
 untick(); 

 Serial.println(F("Blynk Connected!"));
 Serial.println(F("local ip"));
 Serial.println(WiFi.localIP());  

 char str[32];
 sprintf_P(str, PSTR("%s Online!"), wmSettings.host); 
 Blynk.notify(str);

 if (isFirstConnect)
 {
  Blynk.syncAll();
  isFirstConnect = false;
 }
}

BLYNK_WRITE(BUTTON_SYS_B0_VPIN) // Example
{ 
 //TODO: something to do when a button is clicked in the Blynk app
 
 Serial.println(F("System_0 button pressed is App!")); 
}
/* BLYNK CODE END */

/* CODE BEGIN USER FUNCTION */
static void timerRefreshData(void)
{
 //TODO: here are functions for updating data from sensors, ADC, etc ...
}

static void timerSendServer(void)
{
 if (Blynk.connected())
 {
  //TODO: here are the functions that send data to the Blynk server
  Blynk.virtualWrite(WIFI_SIGNAL_VPIN, map(WiFi.RSSI(), -105, -40, 0, 100)); //Example send level WiFi signal
 }
 else
 {
  //TODO:
 }
}

static void timerReconnect(void)
{
 if (WiFi.status() != WL_CONNECTED)
 {
  Serial.println(F("WiFi not connected"));

  if (WiFi.begin() == WL_CONNECTED)
  {
   Serial.println(F("WiFi reconnected"));
  }
  else
  {
   Serial.println(F("WiFi not reconnected"));
  }
 }
 else// if (WiFi.status() == WL_CONNECTED)
 {
  Serial.println(F("WiFi in connected"));

  if (!Blynk.connected())
  {
   if (Blynk.connect())
   {
    Serial.println(F("Blynk reconnected"));
   }
   else
   {
    Serial.println(F("Blynk not reconnected"));
   }
  }
  else
  {
   Serial.println(F("Blynk in connected"));
  }
 }
}

static void configModeCallback(WiFiManager* myWiFiManager)
{
 Serial.println(F("Entered config mode"));
 Serial.println(WiFi.softAPIP());
 //if you used auto generated SSID, print it
 Serial.println(myWiFiManager->getConfigPortalSSID());
 //entered config mode, make led toggle faster
 tickerESP8266.attach(0.2, tick);
}

//callback notifying us of the need to save config
static void saveConfigCallback()
{
 Serial.println(F("Should save config"));
 shouldSaveConfigWM = true;
}

static void tick(void)
{
 //toggle state  
 LED_SYS_TOGGLE();     // set pin to the opposite state
}

static void untick(void)
{
 tickerESP8266.detach();
 LED_SYS_OFF(); //keep LED off 
 
}

static void readSystemKey(void)
{
 if (!digitalRead(BUTTON_SYS0_PIN) && !btnSystemState0)
 {
  btnSystemState0 = true;
  startPressBtn = millis();
 }
 else if (digitalRead(BUTTON_SYS0_PIN) && btnSystemState0)
 {
  btnSystemState0 = false;
  int pressTime = millis() - startPressBtn;

  if (pressTime > INTERVAL_PRESSED_RESET_ESP && pressTime < INTERVAL_PRESSED_RESET_SETTINGS)
  {
   if (Blynk.connected())
   {    
    Blynk.notify(String(wmSettings.host) + F(" reboot!"));
   }
   
   Blynk.disconnect();  
   tickerESP8266.attach(0.1, tick);   
   delay(2000);
   ESP.restart();
  }
  else if (pressTime > INTERVAL_PRESSED_RESET_SETTINGS)
  {
   if (Blynk.connected())
   {        
    Blynk.notify(String(wmSettings.host) + F(" setting reset! Connected WiFi AP this device!"));
   }   

   WMSettings defaults;
   wmSettings = defaults;

   LED_SYS_ON();
   // We write the default data to EEPROM
   EEPROM.begin(EEPROM_SETTINGS_SIZE);
   EEPROM.put(EEPROM_START_SETTING_WM, wmSettings);
   EEPROM.end();
   //------------------------------------------
   LED_SYS_OFF();

   delay(1000);
   WiFi.disconnect();
   delay(1000);
   ESP.restart();
  }
  else if (pressTime < INTERVAL_PRESSED_RESET_ESP && pressTime > INTERVAL_PRESSED_SHORT)
  {   
   Serial.println(F("System button_0 pressed is Device!"));
   // TODO: insert here what will happen when you press the ON / OFF button   
  }
  else if (pressTime < INTERVAL_PRESSED_SHORT)
  {   
   Serial.printf("Fixed false triggering %ims", pressTime);
   Serial.println();
  }  
 }
}
/* CODE END USER FUNCTION */

Можливості

  • При першому, після прошивання, увімкнені пристроєм утворюється точка WiFi з ім'ям "MyHomeIoT-ESP8266". Підключиться до цієї точки своїм смартфоном і відкрийте браузер та перейдіть за адресою 192.168.4.1 до налаштувань;
  • Для прикладу і перевірки на віртуальну шпильку V80 відправляються дані рівня сигналу WiFi. Додайте якийсь віджет "value" і назначте йому віртуальну шпильку V80;
  • Кнопка, яка підключена до GPIO_0 обробляється шаблоном та може реагувати на коротке натискання - вставляєте свій код для увімкнення/вимкнення чогось, або інших дій. Довге натискання кнопки від 5 до 10 секунд - перезавантаження пристрою. Довге натискання понад 10 секунд - скидання всіх налаштувань;
  • Для прикладу є обробка віртуальної кнопки V20. Якщо в BlynkApp додати до проекту кнопку на віртуальну шпильку V20, то пристрій в термінал буде надсилати повідомлення про те що кнопку натиснули з додатку Blynk. Інший код-функціонал на ваш розсуд;
  • Є можливість оновити прошивку по повітрю - WebOTA. Для цього потрібно знати IP пристрою і з будь якого браузера який знаходиться в тій же ж самій мережі набрати "IP_Your_Drvice/update". Наприклад ваш пристрій має IP - 192.168.100.111, тоді в браузер вводимо "192.168.100.111/update", обираємо файл прошивки і тиснемо кнопку "update". 
  • При втраті WiFi мережі, або зв'язку з сервером Blynk, функціонал пристрою не буде "гальмувати" і зв'язок автоматично відновиться при першій можливості;
  • Присутні в шаблоні три таймери для збору даних з датчиків (вставляєте свій код), для надсилання даних на сервер (вставляєте свій код. Є приклад з рівнем сигналу WiFi), та таймер для перепідключення до WiFi і Blynk;
  • Якщо до пристрою GPIO_13 підключити світлодіод, це додасть інформативності. Часте блимання - створена точка WiFi, повільне блимання - йде підключення до Wi-Fi і серверу Blynk, блимання раз на 2 секунди - немає підключення до серверу, або мережі.

пʼятницю, 7 червня 2019 р.

Blynk: Авто-кватирка на ESP8266 та Stepper Motor

Передмова

Розробив на замовлення "Авто-кватирку", яка може міряти температуру і вологість в приміщення сенсором DHT, та відкривати чи закривати кватирку, або вікно за допомоги крокового двигуна (Stepper Motor 28BYJ-48 With Driver Module ULN2003). Схему і код публікую з дозволу замовника. 

Зачиняти і відчиняти вікно можна як з кнопки на пристрою, так і зі смартфону з додатку Blynk. А також задати залежності відкриття і закриття від температури і вологості в приміщенні. Плюс є два тижневих планувальника подій, яким можна задати час відкриття, та час закриття вікна. Чим повністю автоматизувати процес провітрювання приміщення.

Залізяччя

Схема

Схема авто-кватирка
Макет авто-кватирки

Скетч

Текст програми завеликий для публікації в статті. Завантажити скетч можна на GitHub.
На початку програми є деякі налаштування, за допомоги яких можна встановити інші піни для сенсора, мотора, кнопки, геркону, світлодіоду та номера віртуальних шпильок в Blynk:

#define BUTTON_SYSTEM   0
#define LED_BLUE    2
#define INITIAL_POSITION_SWITCH 16
#define ULN2003_IN1    5
#define ULN2003_IN2    4
#define ULN2003_IN3    14
#define ULN2003_IN4    12

#define DHTTYPE DHT11  // DHT11, DHT 22  (AM2302), AM2321
#define DHTPIN 13   // DHT PIN

// Сенсор DHT
#define TMP_DHT V5
#define HUM_DHT V6

#define MOTOR_MOVE_SLIDER   V20 // Віджет слайдера
#define MOTOR_SPEED_STEP_CONTROL V21 // Віджет STEP CONTROL
#define MOTOR_MAXIMUM_STEPS   V22 // Максимальна кількість кроків для слайдеру і кнопки
#define MOTOR_DIRECTION_MENU  V60 // Меню направлення руху мотору

#define TERMINAL   V41
#define TIME_INPUT_0  V50
#define TIME_INPUT_1  V51
#define WIFI_SIGNAL V80

Рекомендації по збиранню

  1. Зібрати макет чи завершений пристрій відповідно до наведеної схеми. Обов'язково живіть окремими джерелами струму двигун і сам пристрій. Геркон розташуйте на рамі вікна, а магніт розташуйте на кватирці або фрамузі так, щоб геркон замикався при закритті кватирки чи фрамуги. Розташування крокового двигуна і яка саме буде конструкція відкриття/закриття залежить від вашої фантазії і можливостей і виходить за рамки цієї статті;
  2. Скомпілювати скетч та залити до ESP8266 за допомоги Arduino IDE, або MS Visual Studio з плагіном visualMicro. Обов'язково перед компіляцією зробіть зміни до коду в бібліотеку "stepper". Відкрийте файл "stepper.cpp" та додайте рядок "delay(0);" до коду в це місце:
    // decrement the number of steps, moving one step each time:
      while (steps_left > 0)
      {
        delay(0);
        unsigned long now = micros();
    
    Або взяти готовий бінарник, як вас влаштовує типова схема наведена вище, і прошити цей бінарник будь яким прошивачем, який може прошити ESP8266. Наприклад "flash download tools", "ESP8266Flasher", тощо. Після прошивання, обов'язково зняти живлення з ESP8266. Вимкнути взагалі весь пристрій що прошили.
  3. Завантажити на свій смартфон додаток Blynk для андроїд, або Blynk для iOS;
  4. Запустити додаток і зареєструватись в системі Blynk:
  5. Увімкнути сканування QRcode: 
  6. Сканувати цей QRcode:
  7. Після сканування у вас з'явиться готовий проект. Відкрийте налаштування проекту:
  8. Зайдіть у розділ "Device":
  9. Зайдіть у властивості "My Devices", як немає жодного пристрою, додайте "New Device":
  10. Отримайте "Auth Token" та натисніть де позначено червоним прямокутником - "AUTH TOKEN" скопіюється до буферу. За потреби натисніть на "Email" і отримаєте "AUTH TOKEN" на свою поштову скриньку:
  11. З головного екрану проекту запустіть свій проект:
  12. Подайте живлення на свій пристрій. Двигун почне обертання, поки не замкнеться "геркон" магнітом (калібрування положення "вікно закрите"), або не пройде 10 секунд (timeout). На стадії тестування і ознайомлення можна самому рукою піднести магніт до геркону, або якимсь іншим чином замкнути контакти геркону. Далі почне блимати синій світлодіод на платі ESP8266, який під'єднано до GPIO2. На своєму смартфоні скануємо мережі Wi-Fi і підключаємось до мережі з назвою "Stepper-Motor-Wemos". Після підключення вам запропонується увійти через браузер на сторінку налаштувань пристрою, або самі запустіть браузер і зайдіть на сторінку налаштувань пристрою за адресою 192.168.4.1;
  13.  Зайти в меню "Configure WiFi":
  14. Ввести "SSID", "password" вашої WiFi мережі де буде працювати пристрій, та вставити з буферу обміну "Auth Token". Зберегти налаштування кнопкою "Save":
  15. Пристрій перезавантажиться, підключиться до вашої WiFi мережі і під'єднається до серверу Blynk. Смартфон від'єднається від мережі пристрою і під'єднається до вашої WiFi мережі. Запускаємо додаток Blynk з цим проектом і спостерігаємо на екрані данні про температуру і вологість, а також можете спробувати керувати слайдером щоб порухати кватирку чи фрамугу вікна.

Опис можливостей

В проекті є налаштування максимальної кількості кроків двигуна "MAX STEPS" і швидкість руху двигуна "SPEED MOTOR". Направлення руху двигуна (revers/direction). Рівень сигналу WiFi. Та вікно терміналу де друкуються деякі події, що відбуваються. Два планувальника подій "TIME INPUT". Та датчики температури і вологості. 

Термінал приймає деякі команди:
  • version - друкує в термінал поточну версію прошивки;
  • name - друкує в термінал поточну назву пристрою;
  • ip - друкує в термінал IP пристрою в мережі;
  • mac - друкує в термінал MAC адресу пристрою;
  • reboot - перезавантажує пристрій;
  • reset - скидає налаштування до "заводських";
  • pins - пам'ятка на яких віртуальних шпилька що "сидить".
Також в проекті присутній віджет "Eventor" за допомоги якого можна встановити залежності від температури і вологості і назначити для цього дії. 

Пристрій підтримує оновлення прошивки по WEB OTA. Для цього потрібно в браузері ПК, який знаходиться в тій же ж мережі що і пристрій, набрати IP адресу пристрою і додати "/update", наприклад пристрій має IP адресу "192.168.0.102" тоді в браузері набрати таку адресу "192.168.0.102/update" і ви потрапите на сторінку оновлення прошивки. Обирайте файл прошивки і тисніть кнопку "UPDATE". Після оновлення пристрій перезавантажиться і почне працювати знову.

Приклад роботи


неділю, 8 липня 2018 р.

Blynk: контроль підключеннями до серверу Blynk та мережі WiFi

update 25.12.2020: написав нову статтю на цю тему плюс відео: "Blynk: підключення до точки WiFi та серверу Blynk, очікування WiFi точки, перепідключення до WiFi та серверу Blynk, робота основного коду без блокування при очікування з'єднання для ESP32/ESP8266"

Передмова

Надихнуло на написання цієї статті це відео з каналу "Інженерка" - рекомендую.

Коли справно працює ваша мережа WiFi, безперебійний доступ до інтернету, та доступ до серверу Blynk, то й немає ніяких проблем з пристроєм який виконує свій функціонал в парі з системою Blynk. Але коли нештатна ситуація з підключенням, при увімкнені пристрою, чи обірвався зв'язок з мережею, чи сервером Blynk, то треба програмно передбачити такі ситуації і передбачити повторне підключення до серверу у разі втрати зв'язку. А також, коли немає зв'язку з сервером з якихось причин, функція Blynk.run(); буде "гальмувати" ваш пристрій, при кожному виклику (за замовчуванням аж 30 секунд). А викликається ця функція в головному циклі як найчастіше. Тому, як не передбачити втрату зв'язку, ви навіть не в змозі будете щось увімкнути на своєму пристрої. Наприклад, це буде у вас WiFi реле. То увімкнути, чи вимкнути реле з кнопки, скоріше за все в вас не вийде, або вийде з величезною затримкою. У всякому разі таким пристроєм користуватись буде не зручно.

Основа

Беремо за основу "пустий" приклад скетчу для роботи з Blynk:
*************************************************************

  Youll need:
   - Blynk App (download from AppStore or Google Play)
   - ESP8266 board
   - Decide how to connect to Blynk
     (USB, Ethernet, Wi-Fi, Bluetooth, ...)

  There is a bunch of great example sketches included to show you how to get
  started. Think of them as LEGO bricks  and combine them as you wish.
  For example, take the Ethernet Shield sketch and combine it with the
  Servo example, or choose a USB sketch and add a code from SendData
  example.
 *************************************************************/

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial


#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "YourAuthToken";

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "YourNetworkName";
char pass[] = "YourPassword";

void setup()
{
  // Debug console
  Serial.begin(115200);

  Blynk.begin(auth, ssid, pass);
  // You can also specify server:
  //Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 8442);
  //Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8442);
}

void loop()
{
  Blynk.run();
  // You can inject your own code or combine it with other sketches.
  // Check other examples on how to communicate with Blynk. Remember
  // to avoid delay() function!
}
Тепер додамо до цієї основи програмний контроль підключення до WiFi і Blynk.

Доопрацьований базовий скетч з контролем підключення до Wi-Fi та Blynk

Код для скетчу можете копіювати звідси або завантажити файл:
/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial


#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

bool triggerBlynkConnect = false;
bool isFirstConnect = true; // Keep this flag not to re-sync on every reconnection

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "YourAuthToken";

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "YourNetworkName";
char pass[] = "YourPassword";

// Оголошення таймеру
BlynkTimer timer;

static void timerReconnect(void);

void setup()
{
  // Debug console
  Serial.begin(115200);

  // Конфігуруємо підключення до blynk server
  Blynk.config(auth);
  
  //Під'єднуємось до WiFi мережі
  Blynk.connectWiFi(ssid, pass);

  if (WiFi.status() == WL_CONNECTED)
  {
    if (Blynk.connect())
    {
      triggerBlynkConnect = true;
    }
    else
    {
      triggerBlynkConnect = false;
    }
  }

  timer.setInterval(60000L, timerReconnect);
}

void loop()
{
  if (Blynk.connected())
  {
    Blynk.run(); // Initiates Blynk Server  
  }
  else
  {
    triggerBlynkConnect = false;
  }

  timer.run(); // Initiates BlynkTimer
}

BLYNK_CONNECTED()
{
  triggerBlynkConnect = true;

  Serial.println(F("Blynk Connected!"));
  Serial.println(F("local ip"));
  Serial.println(WiFi.localIP());

  if (isFirstConnect)
  {       
    Blynk.syncAll();    

    isFirstConnect = false;
  }
}

static void timerReconnect(void)
{
  if (WiFi.status() != WL_CONNECTED)
  {
    Serial.println(F("WiFi not connected"));
    
    Blynk.connectWiFi(ssid, pass);
  }
  else
  {
    Serial.println(F("WiFi in connected"));
  }

  if (!Blynk.connected() && WiFi.status() == WL_CONNECTED)
  {
    if (Blynk.connect())
    {
      Serial.println(F("Blynk reconnected"));
    }
    else
    {
      Serial.println(F("Blynk not reconnected"));
    }
  }
  else
  {
    Serial.println(F("Blynk in connected"));
  }
}
І трішки пояснень по порядку:

  • змінна triggerBlynkConnect саме в цьому скетчі не використовується. Їй назначається true або false, але ніде не аналізується цей стан. Але коли знадобиться такий аналіз, то змінна, значення якої залежить чи є з'єднання з сервером blynk, або немає такого з'єднання з сервером, у вас вже буде.
  • змінна isFirstConnect потрібна для того, щоб синхронізація шпильок відбувалась тільки раз при першому підключенні.
  • оголошуємо таймер BlynkTimer timer і оголошуємо прототип функції для реконекту static void timerReconnect(void)
  • конектимось до WiFi мережі і в разі успіху конектимось до серверу блінк, як ні, то до серверу блінк і не намагаємось пробитись.
  • запускаємо таймер реконекту timer.setInterval(60000L, timerReconnect) - кожну хвилину буде виконуватись функція static void timerReconnect(void), де буде здійснюватись підключення до WiFi і Blynk у разі потреби, а як з конектом буде все гаразд, то нічого не буде виконуватись в цій функції.
  • в безкінечному циклі loop буде виконуватись Blynk.run(); тільки в тому разі, коли є підключення до серверу Blynk, а у разі втрати з'єднання, ваш код не буде "гальмувати".
  • функція BLYNK_CONNECTED() викликається кожного разу при з'єднанні з сервером Blynk і щоб кожного разу, при реконекті не синхронізувались всі шпильки, аналізуємо стан змінної isFirstConnect
До цього базового, доопрацьованого скетчу можете додавати свій функціонал і не боятись втрати зв'язку. Коли зв'язок відновиться, ваш пристрій знову підключиться до мережі і серверу. А також не буде "гальмуватись" ваш код коли не буде зв'язку, бо функція Blynk.run(); буде викликатись тільки коли є зв'язок з сервером.

Післямова

Як вам сподобалась стаття і хочете підтримати проект і бачити нові статті про Blynk, то буду вдячний за будь-які "донати".

четвер, 31 травня 2018 р.

MyHomeIoT: Розширювач портів Expander 4x4 шина I2C

MyHomeIoT Expander 4x4

Розширювач портів MyHomeIoT Expander 4х4 призначений для керування додатковими чотирма реле по шині I2C з мікроконтролера. Приєднавши цю плату до Sonoff Basic (TH), або до будь якого пристрою на ESP8266 схемно сумісного з Sonoff basic (TH) прошитого прошивкою MyHomeIoT починаючи з версії 1.1.1 і вище до шини I2C, отримуєте керування додатковими, чотирма, реле зі світлодіодною індикацією і зворотнім зв'язком, як з додатку blynk app, так і з кнопок на самій платі. В додачу на кожне додаткове реле по одному планувальнику на тиждень.

Схема розширювача

Принципова схема розширювача MyHomeIoT Expander 4x4
Схема складається з мікросхеми PCF8574P, яка є двонаправленим розширювачем портів вводу/виводу з керуванням по I2C шині і має адресу 0x20. Та мікросхеми ULN2803A, яка є масивом транзисторів Дарлінгтона і має 8 транзисторів з загальним емітером та внутрішніми діодами для індуктивних навантажень (реле). 

Мікросхема U1 (стабілізатор напруги) може бути як на 3.3 вольта, так і на 5 вольт. В залежності від ваших потреб.

Якщо поставити перемичку на J2 то мікросхема U2 PCF8574 буде живитись від свого внутрішнього живлення, а також ці 3.3 вольта, або 5 вольт буде подано на роз'єм J5 і можна буде живити плату з мікроконтролером. 

Якщо перемичку не ставити, то для мікросхеми U2 PCF8574 живлення 3.3 вольта, або 5 вольт очікується з плати мікроконтролеру. І в такому разі стабілізатор напруги на мікросхемі U1 можна не встановлювати. 

Комутувати навантаження на контактах реле можна до 5 ампер. Якщо потрібно комутувати навантаження з більшим струмом, потрібно запаяти на доріжки додаткові дроти.

Печатна плата

Печатна плата з елементами
Плата вид зверху
Плата вид з низу
Плата в зборі
Добре по розміру підходить така коробочка:
107*87*59mm Plastic Electronics Box Project Case DIN Rail PLC Junction Box DIY
Замовити можна, наприклад, тут, або тут, або ще деінде. Отвори в платі під кріплення в цій коробочці прийдеться висвердлити самому.

Варіанти підключення

Плата розширювача з Sonoff basic

Підключення розширювача до Sonoff Basic

Плата розширювача з NodeMCU та іншими ESP8266

Підключення розширювача до NodeMCU

Демонстраційний код

Хто хоче використовувати цей розширювач портів в своїх розробках, то ось для прикладу демонстраційний код для системи Blynk:

/*
 Name:  Blynk_pcf8574_demo.ino
 Created: 7/11/2018 10:17:12 AM
 Author: Andriy Honcharenko
*/

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <Wire.h>
#include <pcf8574_esp.h>

#define ADDRESS_PCF8574   0x20 // Address PCF8574 on the I2C bus
#define SDA    4 // Pin SDA wire 
#define SCL    5 // Pin SCL wire

#define BUTTON_1   V1 // Expander I/O 4x4 relay1
#define BUTTON_2   V2 // Expander I/O 4x4 relay2
#define BUTTON_3   V3 // Expander I/O 4x4 relay3
#define BUTTON_4   V4 // Expander I/O 4x4 relay4

// Macros to work with bits
#define BIT_SET(reg, bit) reg |= 1 << bit
#define BIT_RESET(reg, bit) reg &= ~(1 << bit)
#define BIT_TOGGLE(reg, bit) reg ^= 1 << bit
#define BIT_IS_SET(reg, bit) (reg & (1 << bit)) != 0
#define BIT_IS_RESET(reg, bit) (reg & (1 << bit)) == 0
//--------------------------

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "auth";

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "ssid";
char pass[] = "pass";

//----------------------------------
//PCF8574
//----------------------------------
typedef struct {  
 bool triggerButton[4] = { false, false, false, false };
 bool stateButton[4] = { false, false, false, false };
}PCF8574TypeDef;

PCF8574TypeDef pcf8574Struct;

PCF857x pcf8574(ADDRESS_PCF8574, &Wire, false);

// Prototypes of functions
static void readExpanderKey(void);  // Read the state of the buttons
static void writeStateExpanderRelay(void); // Write the state of the relay
//-----------------------------------

void setup()
{
 // Debug console
 Serial.begin(115200);

 Wire.begin(SDA, SCL);
 
 pcf8574.begin(0xF0);

 Blynk.begin(auth, ssid, pass);
 // You can also specify server:
 //Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 8442);
 //Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8442);
}

void loop()
{
 Blynk.run();
 // You can inject your own code or combine it with other sketches.
 // Check other examples on how to communicate with Blynk. Remember
 // to avoid delay() function!

 // Read the state of the buttons on the PCF8574
 readExpanderKey();
}

BLYNK_CONNECTED()
{
 Blynk.notify("Demo PCF8574 online!");
 
 Blynk.syncAll();
}

BLYNK_WRITE(BUTTON_1)
{
 pcf8574Struct.stateButton[0] = param.asInt(); 
 //Let's record the state of the relay on PCF8574
 writeStateExpanderRelay();
}

BLYNK_WRITE(BUTTON_2)
{
 pcf8574Struct.stateButton[1] = param.asInt();
 //Let's record the state of the relay on PCF8574
 writeStateExpanderRelay();
}

BLYNK_WRITE(BUTTON_3)
{
 pcf8574Struct.stateButton[2] = param.asInt();
 //Let's record the state of the relay on PCF8574
 writeStateExpanderRelay();
}

BLYNK_WRITE(BUTTON_4)
{
 pcf8574Struct.stateButton[3] = param.asInt();
 //Let's record the state of the relay on PCF8574
 writeStateExpanderRelay();
}

static void readExpanderKey(void)
{ 
 // Read all 8 bits at once
 uint8_t buff_in = pcf8574.read8();
 // We are only interested in 4 high bits (button state)
 buff_in >>= 4;
 // Analyze the state of high bits
 for (int i = 0; i < 4; i++)
 {
  if (BIT_IS_RESET(buff_in, (i)) && !pcf8574Struct.triggerButton[i])
  {
   pcf8574Struct.triggerButton[i] = true;
   pcf8574Struct.stateButton[i] = !pcf8574Struct.stateButton[i];

   if (Blynk.connected())
   {
    switch (i)
    {
    case 0:
     Blynk.virtualWrite(BUTTON_1, pcf8574Struct.stateButton[i]);
     break;
    case 1:
     Blynk.virtualWrite(BUTTON_2, pcf8574Struct.stateButton[i]);
     break;
    case 2:
     Blynk.virtualWrite(BUTTON_3, pcf8574Struct.stateButton[i]);
     break;
    case 3:
     Blynk.virtualWrite(BUTTON_4, pcf8574Struct.stateButton[i]);
     break;
    default:
     break;
    }    
   }
  }
  else if (BIT_IS_SET(buff_in, (i)) && pcf8574Struct.triggerButton[i])
  {
   pcf8574Struct.triggerButton[i] = false;
  }
 }
 // Let's record the new state of the relay
 writeStateExpanderRelay();
}

static void writeStateExpanderRelay(void)
{ 
 uint8_t buff_out = 0xFF;

 for (int i = 0; i < 4; i++)
 {

  if (pcf8574Struct.stateButton[i])
  {   
   BIT_SET(buff_out, i);
  }
  else
  {
   BIT_RESET(buff_out, i);
  }
 }

 pcf8574.write8(buff_out);
}
Отримайте "AUTH TOKEN" для свого пристрою, та вставте його в демонстраційний код замість "auth". А також вставте в демокод "SSID" і "PASS" вашої WiFi мережі.

Демонстраційний проект

До проекту Blynk додайте 4 кнопки і назначте їм і'я, колір - за вашим смаком. А також назначте кнопкам віртуальні шпильки: V1, V2, V3, V4. Режим всіх кнопок "SWITCH".
Додайте віджет "Notification".

Або скануйте цей код і отримаєте готовий демо-проект на свій смартфон:

Замовлення

  • Плата - 3$ (у.о)
  • Плата + деталі для самостійного збирання - 9$ (у.о)
  • Плата зібрана і протестована -  12$ (у.о)
Щодо придбання плат пишіть на taburyak@gmail.com

Файли

Відео демонстрація