1 Востаннє редагувалося taburyak (27.11.2018 09:49:49)

Тема: Blynk, ESP8266, IoT

Створю ще одну темку для таких собі питань пов'язаних з програмуванням ESP8266 в засобі розробки Arduino IDE.

Є ESP8266 у нього на шині I2C дисплей і якісь сенсори. Є проста функція, яка по таймеру раз на 2 секунди показує на дисплейчик по черзі: поточний час, стан реле і наприклад, температуру та вологість. Ось ця функція, де : numberOfScreen - поточна "сторінка", MAXNUMBEROFSCREEN - максимальна кількість "сторінок".

void timerChangeScreen()
{
    display.clear();
    display.setFont(ArialMT_Plain_24);
    display.setTextAlignment(TEXT_ALIGN_CENTER);

    if (numberOfScreen == 0)
    {
        display.drawString(64, 22, String(hour()) + ":" + twoDigits(minute()));
    }
    else if (numberOfScreen == 1)
    {
        display.drawString(64, 22, String(t_dht22, 1) + " C");
    }
    else if (numberOfScreen == 2)
    {
        display.drawString(64, 22, String(h_dht22, 1) + " %");
    }
    else if (numberOfScreen == 3)
    {
        if (digitalRead(RELAY_0) == HIGH)
        {
            display.drawString(64, 22, "ON");
        }
        else
        {
            display.drawString(64, 22, "OFF");
        }
    }
    else if (numberOfScreen == 4)
    {
        if (triggerTSL2561Init)
        {
            display.drawString(64, 22, String(lux, 0) + " lux");
        }
    }
    display.display();

    if (++numberOfScreen > MAXNUMBEROFSCREEN)
    {
        numberOfScreen = 0;
    }
}

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

Підкажіть ідею, як реалізувати, інший універсальний підхід. Зараз в мене реалізовано автосканування сенсорів, які під'єднані до ESP`шки і на базі того, що виявилось, хотілось би організувати вивід показників на дисплей.

Ну наприклад, початково нічого не підключено - на дисплей виводиться поточний час і стан реле.
Додав TSL2561, перезавантажив пристрій, програмно виявив що є сенсор освітлення, якось програмно автоматично додалась сторінка для показу люксів на дисплей.
Додав ще сенсор BMP180, перезавантажив, програмно виявив, що є сенсор тиску і температури, якось програмно автоматично додались сторінки для показу тиску і температури на дисплей.
Коли вилучив якийсь сенсор - сторінки для показу вилучаються з обігу теж автоматично без втручання в код.

Звісно не прошу готового коду, а саму ідею як це зробити. Бо навіть не уявляю як це зробити. Ну є якась далека думка, що треба мабуть мати вже всі функції для показу на екран підтримуваних сенсорів, і як виявились ті підтримувані сенсори, додати адреси тих функцій до масиву, а потім з того масиву по черзі брати адреси функцій і по черзі їх викликати. Так? Чи якось по іншому?

Подякували: 0xDADA11C71

2 Востаннє редагувалося ReAl (29.01.2018 10:39:26)

Re: Blynk, ESP8266, IoT

Якщо максимальна кількість різних сенсорів обмежена ще на етапі компіляції і зашитими у флешку драйверами, я б зробив масив вказівників на структури/класи зі станом (відсутній, готовий, …) та функціями «перевірити наявність/ініціалізувати», «опитати/оновити дисплей», …
По таймеру ішов би по масиву, якщо стан відсутній — виклик перевірки ініціалізації, якщо готовий — опитування і відображення, якщо так таки не готовий, то перехід до наступної позиції масиву (зі згортанням в початок), якщо вдалося щось показати на екрані — повернення з функції для виклику в наступному тікові таймера.

Обов'язково (у самій цій функції) перевіряти «пройшли весь цикл і нічого не знайшли», наприклад, на старті prevNumberOfScreen = numberOfScreen; і крутити цикл поки щось знайдеться або поки не буде знову prevNumberOfScreen == numberOfScreen;. Тоді відобразити текст «сенсори відсутні» і до наступного тіка таймера. Інакше ця функція постійно бігатиме по кругу і не поверне керування.
У такому випадкові і перезавантажувати не треба, підключене-відключене відразу буде побачене. Обробкою поточного стану і результату опитування можна виявити пропадання і при цьому якось відзвітувати.

Гірше, якщо, наприклад, давачів температури родини LM75  буде декілька штук в різних місцях (і можуть додаватися-прибиратися). Тоді, мабуть, по чесному список робити і одиницею обробки мати не «сенсор», а «сенсор з конкретною адресою в конкретному місці».

Подякували: taburyak1

3

Re: Blynk, ESP8266, IoT

зачекайте, я з тими сенсорами багатьма не працював, але наприклад DS18B20 має мітки і їх можна ставити паралельно.
Думаю в вашій ситуації треба написати диспетчер задач, та їх приорітетами виконання, так буде краще

4

Re: Blynk, ESP8266, IoT

ReAl написав:

я б зробив масив вказівників на структури/класи зі станом (відсутній, готовий, …) та функціями «перевірити наявність/ініціалізувати», «опитати/оновити дисплей», …

Дякую. Ідея зрозуміла, буду медитувати як то все реалізувати.

5

Re: Blynk, ESP8266, IoT

reverse2500 написав:

Думаю в вашій ситуації треба написати диспетчер задач, та їх приорітетами виконання, так буде краще

Я не такий вже й програмер моторний, як наприклад, Еней був парубком. І мені не зрозуміло що ви запропонували.

6 Востаннє редагувалося taburyak (30.01.2018 11:58:50)

Re: Blynk, ESP8266, IoT

Скористався ідеєю шановного ReAl і спробував її реалізувати в спрощеному варіанті. Мені розібратись з самим принципом. Наявність сенсорів сканується на початку один раз. В залежності від того що є в наявності показуємо на дисплей раз на 2 секунди.

int numValueSensor = 5;

struct showParametrSensor
{
    bool status;
    void(*showValue)();
};

showParametrSensor currentTime     = {true, showCurrentTime};
showParametrSensor statusRelay     = {true, showStatusRelay};
showParametrSensor tsl             = {false, showLightingTSL2561};
showParametrSensor bmp_t         = {false, showTemperatureBMP180};
showParametrSensor bmp_p         = {false, showPressureBMP180};

showParametrSensor* showDisplay[numValueSensor] = {&currentTime, &statusRelay, &tsl, &bmp_t, &bmp_p};

void setup()
{
    ScanAllPeriphDevice();
}

void loop()
{
    for(int i = 0; i < numValueSensor; i++)
    {
        if(showDisplay[i]->status)
        {
            showDisplay[i]->showValue();
            delay(2000);
        }
    }
}

void showCurrentTime(void)
{
    display.drawString(64, 22, String(hour()) + ":" + twoDigits(minute()));
}

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

void showTemperatureBMP180(void)
{
    display.drawString(64, 22, String(t_bmp180, 1) + " C");
}

void showPressureBMP180(void)
{
    display.drawString(64, 22, String(psl_bmp180, 1) + " mm");
}

void showLightingTSL2561(void)
{
    display.drawString(64, 22, String(lux, 0) + " lux");
}

void ScanAllPeriphDevice(void)
{    
    Wire.begin(SDA, SCL);

    if (ScanDevice(ADDRESS_TSL2561))
    {
        tsl.status = true;        
        Serial.println("TSL2561 sensor found");
    }
    else
    {
        tsl.status = false;
        Serial.println("TSL2561 sensor not found");
    }
    if (ScanDevice(ADDRESS_BMP180))
    {
        bmp_t.status = true;
        bmp_p.status = true;
        Serial.println("BMP180 sensor found");
    }
    else
    {
        bmp_t.status = false;
        bmp_p.status = false;
        Serial.println("BMP180 sensor not found");
    }
}

Передбачаємо, що показників на дисплей максимум 5 (numValueSensor).
Оголошуємо структуру де статус сенсора і вказівник на функцію.
Оголошуємо до кожного показника змінну з структурою і заповнюємо її.
Оголошуємо масив з вказівниками на змінні з структурами.
Скануємо периферію ScanAllPeriphDevice, якщо сенсор знайдено status = true;
В циклі перебираємо по черзі вказівники на змінні з структурами і якщо у змінній status = true, то викликаємо їй назначену функцію хай покаже дві секунди і далі, якщо status = false; то йдемо до іншого вказівника в масиві.

Код написав чисто теоритично, для консультування на форумі. Перевірити не маю змоги. Як на вашу думку нормальний підхід? Чи можна щось по іншому? Чи там оптимізувати? Вказівники, ще для мене важка тема.
Прошу поради!!! Дякую.

Подякували: ReAl1

7

Re: Blynk, ESP8266, IoT

Із вказівниками все правильно, тільки функції слід оголосити до того, як їхні імена ставити у структури, можна прототипи вказати до ініціалізації структур, а самі тіла вже де зручно визначати. Інші зауваження стосуються не правильності/неправильності коду, а стилю, то їх окремо/пізніше (головне не забути ;)).

int numValueSensor = 5;

struct showParametrSensor
{
    bool status;
    void(*showValue)();
};

void showCurrentTime(void);
void showStatusRelay(void);
void showLightingTSL2561(void);
void showTemperatureBMP180(void);
void showPressureBMP180(void);

showParametrSensor currentTime     = {true, showCurrentTime};
showParametrSensor statusRelay     = {true, showStatusRelay};
showParametrSensor tsl             = {false, showLightingTSL2561};
showParametrSensor bmp_t         = {false, showTemperatureBMP180};
showParametrSensor bmp_p         = {false, showPressureBMP180};

showParametrSensor* showDisplay[numValueSensor] = {&currentTime, &statusRelay, &tsl, &bmp_t, &bmp_p};

// ...

Ну й я ж не знаю, хто такі оті всі psl_bmp180, звідки беруться і що роблять, то ж тут нічого не скажу.

Подякували: taburyak1

8

Re: Blynk, ESP8266, IoT

ReAl написав:

Із вказівниками все правильно, тільки функції слід оголосити до того, як їхні імена ставити у структури, можна прототипи вказати до ініціалізації структур, а самі тіла вже де зручно визначати. Інші зауваження стосуються не правильності/неправильності коду, а стилю, то їх окремо/пізніше (головне не забути ;)).

Дякую. Зауваження прийнято/усвідомлено.

ReAl написав:

Ну й я ж не знаю, хто такі оті всі psl_bmp180, звідки беруться і що роблять, то ж тут нічого не скажу.

То не важливо. Головне, що я знаю ;)

Добре, наче принцип зрозумів. Як втілю на залізякі буде видніше шо до чого.

9

Re: Blynk, ESP8266, IoT

taburyak написав:

Добре, наче принцип зрозумів. Як втілю на залізякі буде видніше шо до чого.

Втілив. Таки працює. Це магія :)

10

Re: Blynk, ESP8266, IoT

Йдемо далі. Треба ще магії!!!

На ESP8266 крутиться невелика програмка для підтримки зв'язку з сервером. В пам'яті ESP є бібліотечні функції які підтримують зв'язок, відправляють дані і отримують дані. Все це прекрасно працює в середині ESP8266.

А чи можна якимось чином додати якогось магічного коду до ESP8266, щоб я міг ті функції запускати з зовнішнього MCU, який під'єднано до ESP по UART, SPI чи I2C.

Наприклад, для відправки на сервер даних треба викликати таку функцію Blynk.virtualWrite(vPin, value), яка приймає якості параметрів номер шпилькі і які дані на ту шпильку відправити. Тепер уявімо, що мені з зовнішнього MCU на 10 віртуальну шпильку треба відправити число (float) 25,67. По UART, SPI чи I2C з зовнішнього MCU жену байти до ESP, а ESP приймає ті байти і... Що далі? Тут моя думка раптово закінчується.

Нагадую, готового коду/рішення не прошу. Хоч на пальцях поясніть, як то можна реалізувати?

Щось мені здається без вказівників на функції з параметрами тут не обійтись?

11

Re: Blynk, ESP8266, IoT

Ще таке невеличке питання.
Є таке сімейство сенсорів DHT. Купа бібліотек під адуінку і єспеху. Ніде, в отому вашому інтернеті, не знайшов засобу перевірити чи присутній на шпильці сенсор DHT, чи його там немає. Є в кого досвід саме з сенсором DHT виявляти його присутність/відсутність?

12 Востаннє редагувалося reverse2500 (02.02.2018 19:15:13)

Re: Blynk, ESP8266, IoT

Є в кого досвід саме з сенсором DHT виявляти його присутність/відсутність?

часто використовую такий кусок коду

 float h =  dht.readHumidity();                                         
  float t = dht.readTemperature();  
 if (isnan(t) || isnan(h)) {                                              
    Serial.println("Failed to read from DHT");    // тут ясно виведеться якщо DHT11 в моєму випадку не відповідає                        
  } 

по досвіду з ESP8266 в ардуіно пін встановлюється так на DHT

#define DHTPIN 2     // what pin we're connected to 

а ESP8266

#define DHTPIN D2     // what pin we're connected to 

за цієї букви "D" я грався довго

А чи можна якимось чином додати якогось магічного коду до ESP8266, щоб я міг ті функції запускати з зовнішнього MCU, який під'єднано до ESP по UART, SPI чи I2C.

приведу кусок коду

if (Serial.available() > 0) {
                // read the incoming byte:
                incomingByte = Serial.parseFloat();
                EEPROM_float_write(adder, incomingByte);
                                    }

                float temp1 =  EEPROM_float_read(adder);

я так часто міняю показники які передаються через USB ардуіно, все працює, мінімально і максимально, також командами передавав код, включити і вимкнути світодіод

По UART, SPI чи I2C з зовнішнього MCU жену байти до ESP, а ESP приймає ті байти і... Що далі?

switch case конструкція для прикладу як варіант

Подякували: DOP1

13

Re: Blynk, ESP8266, IoT

часто використовую такий кусок коду

Ну справа в тому що в мене два DHT22 і обоє іноді не читаються. Цей метод треба вдосконалити. Коли йде розпізнавання сенсорів то потрібно разів 5 спробувати читати і якщо таки NAN, то сенсора немає. Мабуть так.

switch case конструкція для прикладу як варіант

Категорично не підходить . Треба по іншому якось. Хай навіть якийсь enum з кодами. Але щоб в залежності від коду викликались ті чи інші функції бібліотеки з параметрами.

14 Востаннє редагувалося reverse2500 (03.02.2018 20:33:37)

Re: Blynk, ESP8266, IoT

Ну справа в тому що в мене два DHT22 і обоє іноді не читаються.

а які ? Фото скиньте, мабуть перепутали сигнальний провід і VCC, Там їх є два види, часто в цьому бувають проблеми, я ще осцилоографом дивився, потім піни замінив і норма. Можна і тестером глянути чи дає результат.

require("iuplua")
rs232 = require("luars232")


-- Windows
port_com = "COM3"
local timeout = 10000 -- in miliseconds

local out = io.stderr

-- open port
-- local
e, p = rs232.open(port_com)
if e ~= rs232.RS232_ERR_NOERROR then
    -- handle error
    out:write(string.format("can't open serial port '%s', error: '%s'\n",
            port_name, rs232.error_tostring(e)))
    return
end

-- set port settings
assert(p:set_baud_rate(rs232.RS232_BAUD_9600) == rs232.RS232_ERR_NOERROR)
assert(p:set_data_bits(rs232.RS232_DATA_8) == rs232.RS232_ERR_NOERROR)
assert(p:set_parity(rs232.RS232_PARITY_NONE) == rs232.RS232_ERR_NOERROR)
assert(p:set_stop_bits(rs232.RS232_STOP_1) == rs232.RS232_ERR_NOERROR)
assert(p:set_flow_control(rs232.RS232_FLOW_OFF)  == rs232.RS232_ERR_NOERROR)

btn1 = iup.button{title = "Увімкнути лампочку!"}
btn2 = iup.button{title = "Вимкнути"}
btn3 = iup.button{title = "Вийти і закрити порт"}
// включити світодіод
function btn1:action ()
err, len_written = p:write("H")
    iup.Message("ON", "ON led") 
end
// виключити світодіод функція
function btn2:action ()
err, len_written = p:write("L")
    iup.Message("OFF", "Off led")
end
function btn3:action ()
assert(p:close() == rs232.RS232_ERR_NOERROR)
    iup.Message("Close", "Close port")
end

box = iup.vbox {btn1,btn2,btn3}

dlg = iup.dialog{box; title="Simple Dialog"}
dlg:show()

iup.MainLoop()

от мій простий код для ардуіно який вмикає і вимикає світодіод по команді, що у вас не так ,я не знаю, я не розумію що у вас не виходить, це можна зробити з конструкцією if else з порівнюванням == рівно чи більше чи менше
да, ще для хорошого тону, якщо ви ставите команду якогось приладу, пишіть

delay(2000);

значення повинно бути по даташіту, бо в кожного приладу може бути інше, десь і 500 достатньо, за цього що режим очікування не прописали і не почикали старту, теж можуть бути проблеми

15

Re: Blynk, ESP8266, IoT

от мій простий код для ардуіно який вмикає і вимикає світодіод по команді

Такє я вмію http://stm32withoutfear.blogspot.com/20 … -uart.html
Все інше, або я не можу пояснити, або ви не можете зрозуміти.

Таким способом мені за кожної модифікації коду на MCU1 потрібно міняти код на MCU2 щоб вони один одного розуміли.

От спробую пояснити ще раз.

Є 2 (два) MCU: MCU1 (знімає показники, чекає на команду) і MCU2 зв'язок з сервером, прийом команд з сервера, передача даних на сервер.

MCU1 & MCU2 з'єднані якимось інтерфейсом (не важливо).

На MCU2 є бібліотека з функціями які потрібно викликати з певними параметрами, які це будуть параметри залежить від надісланих байтів з MCU1 до MCU2.

Ось наприклад одна з функцій на MCU2:

/**
     * Sends value to a Virtual Pin
     *
     * @param pin  Virtual Pin number
     * @param data Value to be sent
     */
    template <typename... Args>
    void virtualWrite(int pin, Args... values) {
        char mem[BLYNK_MAX_SENDBYTES];
        BlynkParam cmd(mem, 0, sizeof(mem));
        cmd.add("vw");
        cmd.add(pin);
        cmd.add_multi(values...);
        static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE, 0, cmd.getBuffer(), cmd.getLength()-1);
    }

Ось MCU2 прийняв від MCU1 два байти в одному номер віртуального порту, наприклад 15 і другий байт це ціле число 1. Виклик цієї функції в MCU2 виглядає так Blynk.virtualWrite(15, 1);
Як мені організувати код в MCU2, щоб не перераховувати через Swich case всі віртуальні порти і можливі типи даних, а написати одну функцію, яка буде делегувати до бібліотечної функції виклик з потрібними параметрами.

16

Re: Blynk, ESP8266, IoT

а які ? Фото скиньте, мабуть перепутали сигнальний провід і VCC

https://arduino-ua.com/products_pictures/large_vlajnosti_i_temperatyri_DHT22-3.png

17

Re: Blynk, ESP8266, IoT

AVR. Учебный курс. Операционная система. Диспетчер задач.
я ю зробив через диспетчер завдань, нема відповідь чекає в черзі, зробив що треба, передав дані, там же і вказати приорітет і аргументи можна написати.
А по фото треба резистор на 10 кОМ між ніжкою один і два
http://www.2150692.ru/images/faq/dht22/dht22-connect.png

18

Re: Blynk, ESP8266, IoT

А по фото треба резистор на 10 кОМ між ніжкою один і два

Так і є.

19 Востаннє редагувалося taburyak (07.02.2018 13:56:15)

Re: Blynk, ESP8266, IoT

З MCU1 (STM32) по uart відправляю текстовий рядок:

UART_SendStr("0 33 20 1");

Де сама функція:

void UART_SendChar(char ch)
{
    uint8_t dat = ch;
    HAL_UART_Transmit(&huart1, &dat, 1, 1000);
}

MCU2 (ESP8266) по UART приймає той рядок:

if (Serial.available() > 0)
    {                
        if (i < 2)
        {            
            incomingIntArr[i] = Serial.parseInt();
            i++;
        }
        
        if (i == 2)
        {
            i = 0;            
            Blynk.virtualWrite(incomingIntArr[0], incomingIntArr[1]);
        }
    }

І це працює. На нульову шпильку кидає 33 на 20 шпильку 1.

Так але це виключно integer. Як так зробити зі сторони STM32 щоб перший параметр integer (номер шпильки), а другий параметр може бути як integer, так і float, а також string (масивом char), або ж взагалі просто масивом з byte? Про шаблони почав читати, але ж це C++, а зі сторони STM32 в моєму випадку - Сі.

Далі! Як зі сторони esp8266 зрозуміти що прийшло: int, float чи string? Чи потрібно мудрувати якийсь свій протокол? Де в самому протоколі вже вказувати що до чого.

Я певен що це питання взаємодії між MCU давно вирішено, я просто не знаю куди копати, що гуглити?

20

Re: Blynk, ESP8266, IoT

І як ця магічна штука працює?

#define BLYNK_VAR_INT(name, pin) \
    int name;  \
    BLYNK_WRITE(pin) { name = param.asInt(); } \
    BLYNK_READ(pin)  { Blynk.virtualWrite(pin, name); }

#define BLYNK_VAR_LONG(name, pin) \
    long name;  \
    BLYNK_WRITE(pin) { name = param.asLong(); } \
    BLYNK_READ(pin)  { Blynk.virtualWrite(pin, name); }

#ifndef BLYNK_NO_FLOAT
#define BLYNK_VAR_DOUBLE(name, pin) \
    double name;  \
    BLYNK_WRITE(pin) { name = param.asDouble(); } \
    BLYNK_READ(pin)  { Blynk.virtualWrite(pin, name); }
#endif

#ifdef ARDUINO
#define BLYNK_VAR_STRING(name, pin) \
    String name;  \
    BLYNK_WRITE(pin) { name = param.asStr(); } \
    BLYNK_READ(pin)  { Blynk.virtualWrite(pin, name); }
#endif

Відчуваю що розуміння цього якось мені допоможе. Ну хоч трішки.