Перейти к публикации
iT4iT.CLUB

Рекомендованные сообщения

20 часов назад, Dark FeniX сказал:

Конечно, мелковат экран у 1306, надо было брать больший, типа TFT 2.4".

Осмелюсь предложить взглянуть в сторону микросхемы MAX7219 в связке с сегментными индикаторами 8х8.

С простым выводом данных проблем быть не должно. Возможно будут сложности с бегущей строкой из-за нагруженности контроллера другими задачами, но над этим стоит подумать, может я зря нагнетаю. А вообще можно взять вторую ESP8266 и сделать из неё чисто информер. Данные брать напрямую с метеостанции через API или через MQTT протокол.

Ссылка на модули в Китае

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 02.07.2018 в 20:21, Kitsum сказал:

Хорошая задачка. Полагаю, что Вы используете последнюю версия проекта. Решить задачу можно тремя способами и они потребуют физического доступа к контроллеру.

Не доходили руки заглянуть на сайт :) . 

Огромное спасибо за ответ!!!  Сброс пароля не самое главное... а вот описание приведенное в ответе!!!  Теперь, как доберусь, смогу настроить чисто для себя.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Добрый день.

Еще раз выражу свое восхищение данным проектом.

Если кто-то сможет, прошу подсказки. Добавил в данный проект датчик CO2 mh-z19, вроде все скомпилировалось, но данные не приходят с датчика.

Скрытый текст

 

#ifndef USERS_H
#define USERS_H
#define MH_Z19_RX 13 // D7
#define MH_Z19_TX 12 // D6

#include <BME280I2C.h> // https://github.com/finitespace/BME280

// SoftSerial for MH-Z19
#include <SoftwareSerial.h>       // https://github.com/plerup/espsoftwareserial
//#include <MHZ19.h>
SoftwareSerial co2Serial(MH_Z19_RX, MH_Z19_TX); // define MH-Z19

BME280I2C::Settings
settings_out(
  BME280::OSR_X1,
  BME280::OSR_X1,
  BME280::OSR_X1,
  BME280::Mode_Forced,
  BME280::StandbyTime_1000ms,
  BME280::Filter_Off,
  BME280::SpiEnable_False,
  BME280I2C::I2CAddr_0x76
),
settings_in(
  BME280::OSR_X1,
  BME280::OSR_X1,
  BME280::OSR_X1,
  BME280::Mode_Forced,
  BME280::StandbyTime_1000ms,
  BME280::Filter_Off,
  BME280::SpiEnable_False,
  BME280I2C::I2CAddr_0x77
);

BME280I2C BME_OUT(settings_out), BME_IN(settings_in);

/* Параметры индикаторов web интерфейса для плагина Knob
                       Мин  Макс   Шаг    Заголовок      Ед. измер.
|---------------------|----|------|------|--------------|---------| */
knob_t *T = new knob_t( -40,   50, ".1", "Температура", "°C");
knob_t *P = new knob_t(   0,   900, ".1", "Давление",    "mm");
knob_t *H = new knob_t(   0,   100, ".1", "Влажность",   "%");
knob_t *AH = new knob_t(  0,   100, ".1", "Влажность", "г/м&sup3;");
knob_t *PPM = new knob_t(-400, 5000, ".1", "CO2",   "ppm");

/* Функции, описывающие инициализацию датчиков */
void out_init() { BME_OUT.begin(); }
void in_init()  { BME_IN.begin(); }

/* Функции, описывающие как получить от внешнего датчика те или иные данные */
float out_temp() { return BME_OUT.temp(BME280::TempUnit_Celsius); } 
float out_hum()  { return BME_OUT.hum(); }
float out_pres() { return BME_OUT.pres(BME280::PresUnit_torr); }

/* Функции, описывающие как получить от внутреннего датчика те или иные данные */
float in_temp()  { return BME_IN.temp(BME280::TempUnit_Celsius); }
float in_hum()   { return BME_IN.hum(); }
float in_pres()  { return BME_IN.pres(BME280::PresUnit_torr); }

float readCO2()
{

  byte cmd[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
  // command to ask for data
  byte response[9]; // for answer

  co2Serial.write(cmd, 9); //request PPM CO2

  // The serial stream can get out of sync. The response starts with 0xff, try to resync.
  while (co2Serial.available() > 0 && (unsigned char)co2Serial.peek() != 0xFF) {
    co2Serial.read();
  }

  memset(response, 0, 9);
  co2Serial.readBytes(response, 9);

  if (response[1] != 0x86)
  {
    //Serial.println("Invalid response from co2 sensor!");
    return -1;
  }

  byte crc = 0;
  for (int i = 1; i < 8; i++) {
    crc += response;
  }
  crc = 255 - crc + 1;

  if (response[8] == crc) {
    int responseHigh = (int) response[2];
    int responseLow = (int) response[3];
    int ppm = (256 * responseHigh) + responseLow;
    return ppm;
  } else {
    //Serial.println("CRC error!");
    return -1;
  }
}

/* Добавление датчиков в систему */
void sensors_config() {
  co2Serial.begin(9600); //Init sensor MH-Z19(14)
  Wire.begin(4, 5);
    sensors.add(AH, device::out, "out_absoluteHumidity", [&](){ return absoluteHumidity(out_temp(), out_hum()); }
  );
    sensors.add(new knob_t(-100, 0, "1", "RSSI", "dbm"), device::in, "rssi",[&](){ 
    return wifi.isConnected() ? WiFi.RSSI() : 0; 
  });
  
    sensors.add(PPM, device::in, "CO2 ppm",[&](){ 
    return readCO2(); 
  });
  /* Внешний датчик */
  sensors.add(P, device::out, 0x76, "out_pressure",    out_pres, true);
  sensors.add(H, device::out, 0x76, "out_humidity",    out_hum,  true);  
  sensors.add(T, device::out, 0x76, "out_temperature", out_init, out_temp, true);
  
  /* Внутренний датчик */
  sensors.add(P, device::in, 0x77, "in_pressure",    in_pres, true);
  sensors.add(H, device::in, 0x77, "in_humidity",    in_hum,  true);
  sensors.add(T, device::in, 0x77, "in_temperature", in_init, in_temp, true);
}

#endif

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Еще хотел спросить у автора, где находятся настройки для построения графиков, как добавить туда дополнительные переменные?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Доброе время суток

28.09.2018 в 15:07, Devilisimo сказал:

Добавил в данный проект датчик CO2 mh-z19, вроде все скомпилировалось, но данные не приходят с датчика.

Обратите внимание, что используемые Вами порты для SoftwareSerial уже задействованы под управление нагрузкой при превышение определенных показаний. Найти их можно в файле gpio.h и в настройках web интерфейса, раздел "Контроль состояния GPIO". Для начала уберите управление нагрузкой с этих портов, закомментируйте в основном файле программы вызов функции

gpio_12_13();

Далее я порекомендую проконтролировать что приходит в ответ на запрос данных с сенсоров. Для этого в браузере откройте режим разработчика и загрузите страницу метеостанции. Смотрите на запрос "sensors". Выглядеть это должно примерно так.

image.png

Можно вывести в консоль данные о поэтапной работе функции чтения данных с сенсора mh-z19

readCO2();

Также можно упростить инициализацию датчика CO2 и выбросить лямбда-выражение указав в качестве последнего аргумента функцию чтения данных с сенсора.

sensors.add(PPM, device::in, "co2_ppm", readCO2);

И не используйте пробельные символы для задания внутреннего имени датчика в web интерфейсе. В Вашем случае замените "CO2 ppm" на "co2_ppm", как это было показано выше при инициализации датчика. Допустимо использовать пробельные символы только для указания видимого имени сенсора, это делается через объект knob_t

knob_t *PPM = new knob_t(-400, 5000, ".1", "CO2", "ppm");

Идентификатор датчика указывается как класс для объекта сенсора в web интерфейсе, а имена классов не допускают наличия пробельных символов т.к они являются разделителями имен. Таким образом задав имя "CO2 ppm" у нашего сенсора появятся два отдельных класса, это "CO2" и "ppm", что не позволит найти интересующий нас объект.

Внесите эти поправки, и я уверен, что данные появятся.

28.09.2018 в 15:10, Devilisimo сказал:

Еще хотел спросить у автора, где находятся настройки для построения графиков, как добавить туда дополнительные переменные?

В первую очередь за ведение логов с сенсора отвечает последний параметр метода add от класса sensors, посмотрите файл sensors.h

class sensors {    
  public:  
    bool add(knob_t *knob, device::list_t list, byte address, const char *name, device::initFn_t init, device::dataFn_t data, bool log);
    bool add(knob_t *knob, device::list_t list, byte address, const char *name, device::dataFn_t data, bool log);

    bool add(knob_t *knob, byte address, const char *name, device::initFn_t init, device::dataFn_t data, bool log);
    bool add(knob_t *knob, byte address, const char *name, device::dataFn_t data, bool log);

    bool add(knob_t *knob, device::list_t list, const char *name, device::dataFn_t data, bool log);

    bool add(knob_t *knob, const char *name, device::dataFn_t data, bool log);
  
  /* ... */
  byte logSize = 144;
} sensors;

Если параметр

bool log

принимает значение true, то будет выделена память для массива типа float с размером, указанным в переменной logSize. Каждый новый сенсор является объектом типа device. По умолчанию память не выделяется.

class device {
  public:
    /* ... */
    device(knob_t *knob, list_t list, byte address, const char *name, initFn_t init, dataFn_t data, byte log, device *next) {
      /* ... */      
      this->log = log ? new float[log]{0} : 0;      
      /* ... */
    }
    /* ... */  
    float *log;
    /* ... */
};

За автоматическое наполнение массива данных отвечает задача в планировщике вызывающая метод logUpdate класса sensors.

cron.add(cron::time_10m, [&](){ sensors.logUpdate();  }, "httpSensorsLog"); // Обновление журнала (httpSensorsLog - не обязательный уникальный ID для быстрого поиска задания другими программными модулями)

По сути происходит перебор всех сенсоров, запись новых значений в логический конец массива и смещение логического конца массива.

Теперь переходим к самому сложному, это web интерфейс и построение суточного графика.

В файле index.htm имеется функция описывающая модель графика с помощью плагина Highcharts

function chart() {
    graph = Highcharts.chart('graph24h', {
        yAxis: [
            /* ... */
        ],
        series: [
            /* ... */
        ]
    });
}

По аналогии с уже описанными линиями данных для других сенсоров можно добавить новый параметр. Обратите внимание на параметр yAxis для объекта series, он уникален для каждой линии данных и содержит порядковый номер соответствующего ему объекта yAxis описанного в начале функции. Это может выглядеть сложно, но это не так. Вы можете найти всю документацию по плагину на официальном сайте https://www.highcharts.com/

Теперь останется только наполнить данными суточный график. За это отвечает обработчик висящий на событии клика по иконке суточного графика.

$("#graph").click(function() {
	/* ... */
});

Добавление массива данных для всех сенсоров идентичны и выглядит примерно так, я приведу пример из своей домашней метеостанции для датчика eCO2 с идентификатором out_co2

graph.series[4].update({
    animation: animation,
    data: obj.out_co2,
    pointStart: pointStart,
    pointInterval: pointInterval
}, false);

Самое главное, на что стоит обратить внимание, это порядковый номер series для которого предназначены эти данные. В данном случае

series[4]

Нумерация начинается с 0 и описывалась в упомянутой ранее функции chart() в секции series

PS: отмечу, что в коде я не умышленно оставил опечатки, за что искренне прошу прощения и советую внимательно все перепроверять.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Добрый день!

Прочитал  вчера все 20 страниц этой темы, круто, голова распухла. Хочу собрать метеостанцию для дома , улицы и теплицы в одном флаконе. Ответьте, пожалуйтста, на вопрос - получится ли собрать метеостанцию без исполнительных модулей на основе модели в этой теме в следующей конфигурации:

1.esp8266,

2. датчик давления ESP180 -1шт. (через провод),

3. четыре датчика температуры и влажности hdc1080 (из них 2 собраны на Ардуино Мини каждый и передают данные через NRF24L01),

4. два датчика температуры DS18B20 (через провод),

5. датчик скорости и направленя ветра (собраны на Ардуино Мини и передают данные через NRF24L01),

6. модуль RTC DS3231 и синхронизация времени через интернет,

7. еще один датчик температуры на Ардуино Мини на DS18B20 и анализом наличия сети 220В на 3-х каналах (генератор, обычная сеть и бесперебойник) с передачей через NRF24L01.

8. датчик осадков (либо через провод, либо через NRF24L01)

8. Дисплей c интерфейсом I2C

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

10. для сохранения логов хотелось бы воспользваться SDкартой через Micro SD SPI адаптер

10. Если вдруг хватит входов еще 2 отдельных датчика DS18B20 через NRF24L01.

Вопрос достаточно абстрактный - хватит ли входов и памяти у esp8266 для реализации этого. Если такое возможно, начну изучать тему и пробовать. Сам оценить такую возможность не в состоянии,т.к. опыт в ардуине практически нулевой.

Заранее благодарен за ответ

Изменено пользователем post125

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
29.09.2018 в 19:56, Kitsum сказал:

Доброе время суток

Обратите внимание, что используемые Вами порты для SoftwareSerial уже задействованы под управление нагрузкой при превышение определенных показаний. Найти их можно в файле gpio.h и в настройках web интерфейса, раздел "Контроль состояния GPIO". Для начала уберите управление нагрузкой с этих портов, закомментируйте в основном файле программы вызов функции


gpio_12_13();

Далее я порекомендую проконтролировать что приходит в ответ на запрос данных с сенсоров. Для этого в браузере откройте режим разработчика и загрузите страницу метеостанции. Смотрите на запрос "sensors". Выглядеть это должно примерно так.

 

Можно вывести в консоль данные о поэтапной работе функции чтения данных с сенсора mh-z19


readCO2();

Также можно упростить инициализацию датчика CO2 и выбросить лямбда-выражение указав в качестве последнего аргумента функцию чтения данных с сенсора.


sensors.add(PPM, device::in, "co2_ppm", readCO2);

 

Спасибо за подробный ответ.

Все сделал по рекомендациям. В режиме разработчика, ответ есть:

{"in_temperature":22.50,"in_humidity":0.00,"in_pressure":744.82,"out_temperature":22.06,"out_humidity":43.84,"out_pressure":744.59,"co2_ppm":510.00,"rssi":-63.00,"out_absoluteHumidity":8.55}

  1. {in_temperature: 22.49, in_humidity: 0, in_pressure: 744.79, out_temperature: 22.07,…}
    1. co2_ppm: 512
    2. in_humidity: 0
    3. in_pressure: 744.79
    4. in_temperature: 22.49
    5. out_absoluteHumidity: 8.59
    6. out_humidity: 44.18
    7. out_pressure: 744.64
    8. out_temperature: 22.07
    9. rssi: -61

Отображения нет на графике, подскажите куда копать.

image.thumb.png.3dff4944f088f1cd704bda610ff88604.png

Хотя беру свои слова обратно, отображение появилось после нескольких обновлений страницы!!!

Спасибо.

image.thumb.png.267f89af9bf850df96a3e22e68b2d334.png

Изменено пользователем Devilisimo
изменение

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Прошу подсказать автора о настройках страниц.

Хотелось бы сделать несколько вкладок для разных комнат. Сейчас есть переключение наружные/внутренние датчики.

В каком месте это настраивается?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Доброе время суток.

22 часа назад, post125 сказал:

Вопрос достаточно абстрактный - хватит ли входов и памяти у esp8266 для реализации этого.

@post125 Я не вижу причин не позволяющих реализовать то, что Вы задумали. Конечно есть нюансы, но они будут всегда.

В первую очередь стоит разбить весь перечень датчиков на группы соответствующие той шине которую будет использовать тот или иной датчик. Это даст представление о количестве необходимых портов микроконтроллера. В Вашем случае используется:

  1. I2C (2 порта)
  2. 1-Wire (1 порт)
  3. NRF (зависит от реализации подключения)

С первыми двумя все понятно, главное помнить что на шине I2C не могут работать два устройства с одним адресом.

А вот с NRF все не так просто т.к используется SPI шина и она подразумевает наличие 4-х свободных портов, но если мы будем только слушать, то в теории можно задействовать только 2. Также скорее всего понадобится еще один порт для IRQ сигнала, так мы будем работать с NRF только в том случае, если что-то есть в эфире. При такой реализации Вам придется отказаться от управления нагрузкой со стороны ESP8266.

Другой вариант подключения NRF24 и ESP8266, который я бы использовал в рамках данного проекта, это отказ от SPI шины в пользу I2C. Но для этого понадобится контроллер посредник, например ATmega328 к которому по SPI шине подключается NRF24, а сам контроллер ATmega висит в качестве Slave устройства на I2C шине ESP8266. Логику работы вижу в виде сбора данных контроллером посредником со всех устройств в эфире которые передают телеграмму определенного формата.

В телеграмме должны передаваться как минимум:

  1. Уникальный идентификатор устройства, например значение с типом uint8_t
  2. Уникальный идентификатор сенсора (uint8_t), если их несколько, например гирлянда из датчиков DS18B20
  3. Данные с сенсора, пусть это будет int16_t

Дополнительно можно передавать:

  1. Тип сенсора, но необходимо заранее составить таблицу типов и придерживаться ею в будущем при добавлении новых устройств в эфир, при необходимости расширять таблицу
  2. Информацию о заряде аккумулятора, если таковой используется
  3. Контрольную сумму

Сам контроллер посредник при получении телеграммы обновляет в оперативной памяти данные по передающему сенсору. Если сенсор раньше не появлялся в эфире, то под него выделяется память. Если сенсор долгое время не передает показания, допустим три дня, он удаляется из памяти. Конечно понадобится ограничение на размер самой "таблицы", допустим 100 передатчиков, а при достижении этого порога игнорировать новые устройства, а то оперативная память может закончиться.

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

В таком варианте весь текущий функционал проекта останется в работоспособном состоянии, в том числе и управление нагрузкой. Дополнительных портов выделять не потребуется, как и освобождать уже задействованные. Программу для посредника обновлять не потребуется, а добавление новых устройств также сведется к созданию самих устройств и добавлению их со стороны ESP. Добавление можно автоматизировать, но это кому как удобно.

Что касаемо хранения логов, то от SD карты я бы посоветовал отказаться в пользу центрального сервера, который Вы упомянули в п.9. Тем более, при наличии сервера, можно хранить данные в полноценной СУБД, той же MySQL, с удобными выборками и онлайн доступом откуда угодно. А вот SD карта опять потребует использования SPI, возвращаемся к дележке портов, на обработку логов потребуется время, да и сама карточка может выйти из строя, что само по себе не приятно и может привести к сбоям в работе программы ESP8266.

В общем памяти у Вас на все это хватит, при условии, что Вы разумно подойдете к логированию показаний для которых строятся графики силами самой метеостанции. И присмотритесь ко второму варианту подключения NRF, он интереснее и намного более практичнее в долгосрочной перспективе.

 

6 часов назад, Devilisimo сказал:

Хотя беру свои слова обратно, отображение появилось после нескольких обновлений страницы!!!

@Devilisimo рад, что у Вас все получилось.

4 часа назад, Devilisimo сказал:

Хотелось бы сделать несколько вкладок для разных комнат. Сейчас есть переключение наружные/внутренние датчики.

В каком месте это настраивается?

@Devilisimo Вам потребуется модифицировать интерфейс web страницы, в принципе это не сложно, главное придумать как визуализировать выбор списка датчиков.

Но для начала давайте разберемся как реализован выбор в коде микроконтроллера. Вот пример одного из программных сенсоров метеостанции, отображающих уровень WiFi сигнала.

sensors.add(new knob_t(-100, 0, "1", "RSSI", "dbm"), device::in, "rssi",[&](){ 
    return wifi.isConnected() ? WiFi.RSSI() : 0; 
});

За выбор страницы где будет отображен индикатор отвечает значение одного из параметров, в данном случае это

device::in

Что указывает на принадлежность сенсора к внутренней группе датчиков.

Список доступных обозначений описан в классе device в файле sensors.h как тип list_t

class device {
  public:
    typedef enum list_t {out = 1, in = 2};
	/* ... */
};

это сделано для того, чтобы исключить ошибку с указанием порядкового номера для не существующего списка сенсоров в самом web интерфейсе. Вам необходимо расширить его с указанием порядковых номеров для новых групп (помните, что они должны быть описаны в файле index.htm).

Теперь переходим к самому web интерфейсу, описанному в файле index.htm

Слои (группы) на которых располагаются индикаторы в первую очередь описаны в секции с html кодом в блоке div с классом mainContainer

<div class="mainContainer">
    <!-- лишнее удалено -->
    <div class="sensorsContent" hidden>
        <!-- лишнее удалено -->
        <div id="list1"></div>
        <div id="list2" hidden></div>
        <!-- лишнее удалено -->
    </div>
    <!-- лишнее удалено -->
</div>

В данном случае числовая часть имен list1 и list2 соответствует числовому значению, которое скрыто за именами out и in см. чуть выше. Если вы добавите новое значение, например, какую ни-ть комнату, пусть это будет ванная

typedef enum list_t {out = 1, in = 2, bathroom = 3};

то необходимо добавить новый слой для визуализации

<div id="list1"></div>
<div id="list2" hidden></div>
<div id="list3" hidden></div>

Далее отработает java функция sensorsStructure которая разместит сенсоры помеченные как device::bathroom на слое с идентификатором list3

Это реализовано через обновление содержимого div

$(".sensorsContent #list" + param.list).append(sensor);

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

$(".menu #sensors").click(function() {
    var list = $(this).attr("class");
    switch (list) {
        case 'list1': $("#list1").fadeToggle('slow', function(){ $("#list2").fadeToggle('slow'); }); break;
        case 'list2': $("#list2").fadeToggle('slow', function(){ $("#list1").fadeToggle('slow'); }); break;
    }
    $(this).toggleClass("list1", !$(this).hasClass("list1")).toggleClass("list2", !$(this).hasClass("list2"));
});

Но это вариант Вам не подойдет и необходимо придумать иной способ визуализации. Или модифицировать имеющийся переключатель с добавлением нового пункта и реализовать это все в виде циклического перебора всего списка.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
08.10.2018 в 12:04, Kitsum сказал:

то вариант Вам не подойдет и необходимо придумать иной способ визуализации. Или модифицировать имеющийся переключатель с добавлением нового пункта и реализовать это все в виде циклического перебора всего списка.

Еще раз благодарю за развернутый ответ.

В связи с экспериментами с датчиками качества воздуха, в частности сейчас пробую BME680, встал вопрос как сделать строку с меняющимся значением не числовым.

Например:

knob_t *GAS = new knob_t( 0, 300, ".1", "Gas",   CalculateIAQ(bme680.gas_resistance / 1000.0));

Компилятор ругается: 'CalculateIAQ' was not declared in this scope

Хотя создал процедуру.

String CalculateIAQ(float score){
  String IAQ_text = "IAQ ";
  score = (100-score)*5;
  if      (score >= 301)                  IAQ_text += "Hazardous";
  else if (score >= 201 && score <= 300 ) IAQ_text += "Very Unhealthy";
  else if (score >= 176 && score <= 200 ) IAQ_text += "Unhealthy";
  else if (score >= 151 && score <= 175 ) IAQ_text += "Unhealthy for Sensitive Groups";
  else if (score >=  51 && score <= 150 ) IAQ_text += "Moderate";
  else if (score >=  00 && score <=  50 ) IAQ_text += "Good";
  return IAQ_text;
}

Порекомендуйте красивое решение.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@Devilisimo давайте разбираться.

Для начала исправим ошибки. У Вас все перемешалось поэтому предлагаю разобрать процесс объявления нового сенсора на каком ни-ть примере. Я опять возьму за основу программный сенсор для сбора и отображения данных по уровню сигнала базовой станции к которой подключается ESP8266. Это очень простой пример, и он не перегружен лишним кодом.

В коде метеостанции сенсор описан небольшим блоком. Он совсем маленький и записать его можно вообще в одну строчку, но это полноценный, законченный сенсор со всем необходимым списком параметров для его автоматической визуализации на странице web сервера микроконтроллера.

sensors.add(new knob_t(-100, 0, "1", "RSSI", "dbm"), device::in, "rssi",[&](){ 
    return wifi.isConnected() ? WiFi.RSSI() : 0; 
});

Выделим в отдельные элементы компоненты, указанные в качестве параметров.

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

knob_t *R = new knob_t(-100, 0, "1", "RSSI", "dbm");

Объект knob_t представляет из себя небольшой контейнер в котором хранятся все характеристики Вашего сенсора. Его можно создать один для целой группы сенсоров, например, датчиков DS18B20. Но в данном случае нам это не интересно. Посмотрим, что из себя представляют все параметры, кстати, посмотреть их можно в файле sensors.h

knob_t(int min, int max, const char *step, const char *title, const char *unit)

Параметры:

  1. min - минимальное значение шкалы
  2. max - максимальное значение шкалы
  3. step - шаг с которым будет произведена визуализация изменения показаний (это не числа!): "1" - единица, ".1" - одна десятая, ".01" - одна сотая и т.д
  4. title - заголовок, по сути название сенсора, не используется нигде кроме визуальной составляющей
  5. unit - описание, задумывался как индикатор единиц измерения

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

float get_rssi() {
    return wifi.isConnected() ? WiFi.RSSI() : 0;
}

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

float get_rssi() {
    return WiFi.RSSI();
}

К данной функции есть очень строгие требования и это не просто так:

  1. Функция обязана возвращать числовое значение с типом float
  2. Функция не может принимать никаких параметров. Все с чем она работает должно быть объявлено в глобальной области видимости (в основном файле и ВНЕ функций setup и loop, для простоты понимания) или в самой функции.

С чем связаны эти тонкости. 

В первую очередь мы работаем с числовыми данными, мы можем использовать их для каких-либо расчетов и т.п. Позволю себе небольшое отступление - вообще использование типа float это плохой тон, но в первой версии метеостанции, где использовался тип int и ему подобные, люди сталкивались с большими трудностями и много путались. Все данные, в том числе и с плавающей точкой хранились как целые числа и на определенном этапе работы с ними требовалось произвести математические действия, по сути умножение и деление на нужное для каждого сенсора значение - 10, 100, 1000 и т.д Хранимые и обрабатываемые данные микроконтроллером преобразовывались в целочисленные, это позволяло производить все операции максимально быстро и требовало меньше затрат памяти, а в web интерфейсе производилось их преобразование в значения с типом float, если вообще это преобразование требовалось. Перейдя в дальнейшем на тип float мы усложнили жизнь микроконтроллеру, но лично мое субъективное мнение, что это допустимая жертва в пользу упрощения кода для других людей. И замечу, что все вопросы по ошибкам преобразования и хранения данных ушли.

Что касаемо параметров функции. Их нет потому что не реально предсказать какие данные захочет передать человек. Конечно есть различного рода хитрости, но они не тянут на полноценное решение. Возможно более опытные товарищи смогут задать вектор мысли, но на мой взгляд, проще придерживаться простых правил.

Осталось затронуть метод add принадлежащий объекту sensors, но т.к метод имеет много переопределений, которые можно посмотреть в том же файле sensors.h, мы рассмотрим его совместно с описанным выше кодом.

/* Описание сенсора для его визуализации плагином knob в web интерфейсе */
knob_t *R = new knob_t(-100, 0, "1", "RSSI", "dbm");

/* Функция, описывающая как получить полезные данные от сенсора */
float get_rssi() {
    return wifi.isConnected() ? WiFi.RSSI() : 0;
}

/* Так мы объявляем новый сенсор и указываем основной программе, что это и как с этим работать */
sensors.add(R, device::in, "rssi", get_rssi);

Что мы передаем в параметрах метода add:

  1. R - указатель на объект knob с описанием всего необходимого для отрисовки сенсора в web интерфейсе одноименным плагином
  2. device::in - идентификатор указывающий к какой группе сенсоров относится этот
  3. rssi - идентификатор датчика, может содержать только латинские буквы, цифры и знак подчеркивания. Используется java скриптами web интерфейса.
  4. get_rssi - имя функции которая будет вызываться для обновления данных

Когда нет необходимости в создании отдельной функции для сбора данных с сенсора, как с данным сенсором ведь его код очень мал и не требует дополнительных библиотек или математических преобразований, можно заменить имя функции на лямбда-выражение.

[&](){ return wifi.isConnected() ? WiFi.RSSI() : 0; }

И получим что-то похожее на начальный код

/* Описание сенсора для его визуализации плагином knob в web интерфейсе */
knob_t *R = new knob_t(-100, 0, "1", "RSSI", "dbm");

/* Так мы объявляем новый сенсор и указываем основной программе, что это и как с этим работать */
sensors.add(R, device::in, "rssi", [&](){ return wifi.isConnected() ? WiFi.RSSI() : 0; });

Это один из множеств вариантов как добавить новый датчик или что-то еще в код метеостанции.

Я настоятельно советую просмотреть

  1. Примеры использования плагина knob http://anthonyterrien.com/demo/knob/
  2. Исходники с описанием плагина knob https://github.com/aterrien/jQuery-Knob
  3. Немного С++ с описанием лямбда-выражений https://msdn.microsoft.com/ru-ru/library/dd293608.aspx
  4. И обязательно изучите файл sensors.h в исходниках метеостанции, там много важной информации.

Уверен, что теперь Вы увидите ошибки и сможете их поправить.

3 часа назад, Devilisimo сказал:

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

Силами плагина Knob никак, он предназначен только для визуализации числовых данных, но Вы можете схитрить. Смотрите в сторону обработки вашей функции на стороне браузера. В файле index.htm имеется описание функции, вызываемой каждый раз, когда требуется обновить данные сенсоров в web интерфейсе. Простите за давнишнюю опечатку в имени функции, но это тот момент, когда исправление только навредит.

function chenge(fast) {
    if(allowAjaxConnection || fast) {
        $.ajax({
            dataType: "json",
            url:  domain + "api/sensors" + ($(".settings #sl-system").is(":visible") ? "?system=true" : ""),
            type: "GET",
            cache: false,
            timeout: 3000,
            success: function(data) {
                $.each(data, function(name, value) { if (name !== 'system') animate("." + name, value); });
                if (data.system) apiSetSystemInfo(data.system, true);
                //$('.out_temperature').trigger('configure', {"fgColor":"#FF0000"});
            }
        });
    }
    setTimeout(chenge, 5000);
}

Это примитивная функция, в которой нас интересует цикл во время работы которого происходит обращение к каждому графическому элементу, отвечающему за отображение данных. Я выделю её визуально чуть подробнее.

$.each(data, function(name, value) { 
  if (name !== 'system') animate("." + name, value);
});

В данной коде мы получаем имя (идентификатор) каждого сенсора и его последние показания. Вы можете видеть, что имеется проверка на имя, совпадающее с 'system', если совпадение найдено, то функция animate вызвана НЕ будет. Это прекрасный пример того, как можно выловить нужный Вам сенсор.

$.each(data, function(name, value) { 
  if (name !== 'system') animate("." + name, value);
  
  /* Ищем нужный нам сенсор */
  if (name === 'rssi') {    
    var description;
    if (value > 50) description = 'плохой'; else description = 'хороший';
    /* Выводим текст куда ни-ть */
    $("input." + .name).parent(".sensor").find(".unit").text(description);
  }  
});

В теории текст должен появиться в области описания единиц измерения, но это нужно перепроверять т.к код написан в слепую.

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

Ну и наконец я дам Вам еще одну идею. Не всегда текст бывает наглядным выводом информации, особенно если он на определенном удалении от наблюдателя. Воспользуйтесь цветовой индикацией. Цвета от зеленого до красного прекрасно сигнализируют о качестве воздуха и очень наглядны. А в коде функции chenge (опять извиняюсь за её имя) имеется подсказка как менять цвет визуального элемента сенсора в web интерфейсе.

//$('.out_temperature').trigger('configure', {"fgColor":"#FF0000"});

Все, что Вам требуется, это изменить указанный чуть ранее код таким образом, чтобы можно было заменить

"#FF0000"

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

var color = "#FF0000";
$('.' + name).trigger('configure', {"fgColor":color});

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
20 часов назад, Kitsum сказал:

В общем памяти у Вас на все это хватит

Премного благодарен за подробное объяснение. Понял, что малое количество портов на ESP8266 не проблема. Продумаю конфигурацию, начну пробовать. Еще раз спасибо!

Есть плата 2в1 Мега+ESP

https://robotdyn.ru/catalog/arduino/boards/mega_wifi_r3_atmega2560_esp8266_flash_32mb_usb_ttl_ch340g_micro_usb.html

Может на ней собрать? Мега будет собирать данные с со всех датчиков, а ЕСП делать всё остальное? Или лучше отдельно Мегу и отдельно ESP?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@post125 Это хороший и довольно интересный вариант.

Вам будут доступны несколько интерфейсов для связи. Разработчик заложил связь через UART, но Вы вполне можете связать ATmega 2560 и ESP8266 через I2C, порты GPIO4 и GPIO5 доступны и выведены на колодку #1.

image.png

Указано, что на плате распаяна флешь на 32 мегабайта, это хорошо т.к на старых ревизиях с 1-м мегабайтом было бы совсем грустно и пришлось бы облегчать оформление web интерфейса ESP.

Из особенностей отмечу, что управление внешними исполнительными механизмами полностью ложиться на ATmega 2560, если вообще этот функционал будет востребован.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Добрый день. 

Хотел спросить у автора. У Вас описана реализация датчика ccs811. Начал с ним работать и выяснил неприятный момент, даже два. Сначала он вообще не стал работать и утащил за собой bme680, при этом bme280 исправно давал данные. Начал копать и нашел тонкость - нужно добавить код: 

#if SENSOR_CCS811
  #include <ccs811.h>
  //CCS811 ccs811;   - так не работает
  CCS811 ccs811(D3); // nWAKE to D3
#endif

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

Может Вы уже столкнулись и решили проблемы работы с данным датчиком? Чтение данных взято из Вашего примера:

/* датчики CO2 CCS811 */
#if SENSOR_CCS811
  sensors.add(C, device::in, 0x5A, "CCS811_ppm", [&](){
    ccs811.begin();
    ccs811.start(CCS811_MODE_1SEC);
  }, [&](){ 
    uint16_t eco2, etvoc, errstat, raw;
    ccs811.read(&eco2, &etvoc, &errstat, &raw); 
    return eco2; 
  }, true);
#endif

В инструкции написано:

Connect the WAKE pin to ground.

Так работает.

image.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@Devilisimo К сожалению, Вы не предоставили схему подключения датчика или подробное фото. Мне кажется, что проблема может скрываться как раз в подключении. Возможно не подключен порт 7 он же nWAKE (на платах часто отмечен как WAK). В официальной документации к датчику ccs811 на четвертой странице указано, что порт nWAKE должен быть подтянут к низкому логическому уровню до начала передачи данных по I2C шине. Я не стал занимать порт микроконтроллера для этих целей т.к у меня не автономное устройство, а просто кинул перемычку с nWAKE к соседнему GND.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
18 часов назад, Kitsum сказал:

@Devilisimo К сожалению, Вы не предоставили схему подключения датчика или подробное фото. Мне кажется, что проблема может скрываться как раз в подключении. Возможно не подключен порт 7 он же nWAKE (на платах часто отмечен как WAK). В официальной документации к датчику ccs811 на четвертой странице указано, что порт nWAKE должен быть подтянут к низкому логическому уровню до начала передачи данных по I2C шине. Я не стал занимать порт микроконтроллера для этих целей т.к у меня не автономное устройство, а просто кинул перемычку с nWAKE к соседнему GND.

Да, так все работает.

Хотел уточнить по настройке     mqtt

// баг при прямой передаче значения (c_str) из конфига в setServer (не забыть поправить!)
String server = conf.param("mqtt_server");
mqttAPI.setServer(server.c_str(), 1883);
mqttAPI.connect(WiFi.hostname().c_str(),
  (conf.param("mqtt_login").length() ? conf.param("mqtt_login").c_str() : 0),
  (conf.param("mqtt_pass").length() ? conf.param("mqtt_pass").c_str() : 0)
);

Решил воспользоваться сервером https://www.cloudmqtt.com/

Хотел уточнить что нужно исправить и где указать порт, так понимаю в программе порт  1883?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
12 минут назад, Devilisimo сказал:

Хотел уточнить что нужно исправить и где указать порт, так понимаю в программе порт  1883?

Да, Вы совершенно правы, порт 1883. Я не добавлял выбор порта через web интерфейс т.к не видел в этом необходимости, но это легко можно исправить. О том, как добавлять свои параметры так чтобы ESP8266 их "запоминал" уже упоминалось в теме, но если вдруг будут сложности, дайте мне знать об этом и я постараюсь описать как это сделать.

Если это не требуется, то просто замените в коде порт 1883 на тот, который Вам предоставит CloudMQTT.

https://www.cloudmqtt.com/docs.html

instance-details[1].png

Помните, что шифрование не поддерживается метеостанцией (но возможно) и выбирайте соответствующий порт. Все остальные настройки производятся через Web интерфейс ESP8266.

PS: прошу Вас не пренебрегать разметкой, в частности блоком "Код", когда публикуете части исходников, а то совсем не удобно читать без подсветки синтаксиса.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Добрый день. Появились еще глупые вопросы.

Решил подключить к станции дисплей SSD1306 128x64 I2C. Позаимствовал часть кода создал функцию.

void draw() {
        u8g2.clearBuffer();
        // test
        const char pi[] {"HI pipi"};
          u8g2.setFont(u8g2_font_6x12_mf);
          x = (128 - u8g2.getStrWidth(pi)) / 2;
          y = y + 2 + u8g2.getAscent() - u8g2.getDescent();
          u8g2.drawStr(x, y, pi);
        // Cycle other meauserments
        String measurement {"..."};
        const char degree {176};

        // Switch every 3 seconds
        switch((millis() / 3000) % 3) {
        case 0:
                { measurement = "T: " + String(sensors.get("out_temperature")) + degree + "C"; }
                break;
        case 1:
                { measurement = "H: " + String(sensors.get("out_humidity")) + "%"; }
                break;
        default:
                { measurement =  "P: " + String( sensors.get("out_pressure")) + " mmHg"; }
        }

        char measurementa [12];
        measurement.toCharArray(measurementa, 12);

        u8g2.setFont(u8g2_font_9x18_mf);
        x = (128 - u8g2.getStrWidth(measurementa))/2;
        y = 64 + u8g2.getDescent();
        u8g2.drawStr(x, y, measurementa);
        u8g2.sendBuffer();
}

добавил

 // Init display
  u8g2.begin();

 /* Добавление в планировщик заданий отрисовкe данных */
  cron.add(cron::time_1m, draw);       // Вывод на экран
// GPIO Defines
#define I2C_SDA 5 // D1
#define I2C_SCL 4 // D2
// Use U8g2 for i2c OLED Lib
#include <SPI.h>
#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, I2C_SCL, I2C_SDA, U8X8_PIN_NONE);

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Прошу помощи по второму вопросу.

Как реализовать функцию чтения данных с сервера MQTT, для дальнейшего вывода на дисплей.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
12.10.2018 в 09:20, Devilisimo сказал:

Как реализовать функцию чтения данных с сервера MQTT, для дальнейшего вывода на дисплей.

Используйте возможности библиотеки PubSubClient, в её примерах есть интересующий Вас код. Сама библиотека используется метеостанцией и объект, через который необходимо работать, уже объявлен в файле services.h

PubSubClient mqttAPI(wifiClient);

Создайте функцию, отвечающую за обработку данных преступаемых от брокера (mqtt сервера) и опишите в ней весь необходимый функционал для обработки сообщений. Опишите её в основной (.ino) файле или в фале services.h, что более правильно.

void callback(char* topic, byte* payload, unsigned int length) {
  /* Ваш код, подсказки смотрите в библиотеке PubSubClient */
}

В функции setup, описанной в основном файле, необходимо добавить вызвать два метода объекта mqttAPI с помощью которых укажем к какому серверу подключиться и какую функцию вызывать при наличии входящего сообщения от брокера.

void setup() {
	/* ... */
  mqttAPI.setServer("mqtt.it4it.club", 1883);
  mqttAPI.setCallback(callback);
}

В функции loop необходимо добавить вызов обработчика, который будет отслеживать появление новых сообщений

void loop() {
  /* ... */
  
  /* Тут не хватает одной функции для подключения/переподключения к брокеру */
  /* Обработчик MQTT */
  mqttAPI.loop();
}

Также Вам необходимо реализовать функцию, отвечающую за подключение и переподключение к брокеру. Без неё связь не будет установлена. Не стоит использовать функцию переподключения описанную в примерах библиотеки т.к в случае отсутствия связи с сервером вы получите практически постоянно висящий контроллер, что явно убьет весь остальной функционал. Я советую использовать планировщик задач с интервалом в 1, а лучше в 5 минут, который будет вызывать функцию проверки связи и подключаться к серверу если это необходимо.

cron.add(cron::time_5m, [&](){
    if (!mqttAPI.connected() and wifi.transferDataPossible()) {
        if(mqttAPI.connect(WiFi.hostname().c_str())) {
            mqttAPI.subscribe("weather_station/lcd/topic_name");
        }
    }
}, false);

Топики, на которые необходимо оформить подписку указываются через метод subscribe

mqttAPI.subscribe("weather_station/lcd/topic_name_1");
mqttAPI.subscribe("weather_station/lcd/topic_name_2");
mqttAPI.subscribe("weather_station/lcd/topic_name_3");

Обратите внимание, что я указал false в качестве последнего параметра метода add. Это запрет холодного старта, хоть он по умолчанию и не используется, мы оставляем явное указание для себя в будущем, чтобы не допустить вызова этой задачи до того момента пока контроллер не перейдет к циклическому вызову всех обработчиков. Ведь на раннем этапе выполнения кода ESP8266 даже не имеет подключения к базовой станции. Для аналогичной защиты используется проверка с вызовом функции

wifi.transferDataPossible()

Данный код я описываю без его проверки и в нем могут содержаться ошибки. Все внимательно проверяйте без лишней спешки. Если у Вас будет иная реализация, не стесняйтесь делиться кодом.

PS: Забыл упомянуть. Я бы советовал Вам не выводить на дисплей данные сразу после их поступления. Лучше их накапливать. Далее в планировщик задач добавить функция вызываемую, например, каждую минуту и проверяющую отличаются ли поступившие данные от тех, что уже выведены на дисплей. Если да, то выводить новые данные. Таким образом Вы будите экономит процессорное время и избавите контроллер от лишних задач по выводу одинаковых данных на дисплей.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Здравствуйте. А на esp01 никто не делал станцию? вроде кто-то писал, никак кне могу найти

Изменено пользователем pasha413

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@pasha413 esp01 отличается от, например, esp12 только количество портов разведенных на плате и которыми Вы можете пользоваться. Во всем остальном это один и тот же контроллер. Все, что Вам нужно проконтролировать, так это чтобы на плате esp01 была распаяна flash память объемом не менее 4Mb.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@Kitsum стоит P25Q80H, но у мена папка дата не грузится, пишет память заполнена

Изменено пользователем pasha413

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@pasha413 Судя по документации это flash на 8Mb, но в интернете есть упоминания, что с P25Q80H много проблем. Вопрос досконально не изучал, но вот интересная тема на Хабре: https://habr.com/post/409911/

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Пожалуйста, войдите для комментирования

Вы сможете оставить комментарий после входа



Войти сейчас

  • Похожие публикации

    • Автор: Kitsum
      Хотите помочь проекту или спонсировать новый?
      Yandex.Money PayPal.me Тема проекта
      Arduino IDE + Project + Libraries + tools: https://yadi.sk/d/jseefFB50NMhAg
    • Автор: Kitsum
      Просмотреть файл [esp8266] Библиотека CMD, реализует настройку микроконтроллера и управление вашей программой через терминал.
      Основная задача библиотеки, это прием пользовательских команд через UART интерфейс, их обработка и выполнение пользовательского кода, связанного с той или иной командой.
      Данная библиотека позволяет реализовать:
      Управление микроконтроллером Любую настройку, будь то WiFi, другие библиотеки или часть Вашей программы Вызывать Ваши задачи (функции) из терминала по команде и передавать им требуемые параметры Использовать контроллер в качестве шлюза между датчиками и программами на PC Внимание: любая команда, передаваемая в терминал обязана заканчиваться символом перевода строки "\n".
      Подключение библиотеки
      #include <cmd.h> Инициализация объекта, к которому мы будем обращаться для добавления команд. В качестве параметра объекту необходимо передать указатель на объект Serial или любой другой схожий по типу интерфейс.
      cmd command(&Serial); В функции Setup описываем какие команды требуется обрабатывать. Например, по команде "test" вызывать пользовательскую функцию с именем "myFunctionName". Имя пользовательской функции может быть абсолютно любым.
      void Setup() { Serial.begin(115200); command.add("test", myFunctionName); } Пользовательская функция будет вызываться каждый раз, когда по интерфейсу Serial поступит команда "test". Если команда будет передана с параметрами, то эти параметры будут переданы в качестве аргументов пользовательской функции.
      В функции loop должна находится команда вызова обработчика.
      void loop() { command.handleEvents(); } Пользовательская функция обязана соответствовать ряду требований:
      Не возвращать никакого результата (быть объявленной с типом void) Принимать в качестве первого аргумента переменную с типом byte в которой будет храниться число равное количеству переданных параметров Принимать в качестве второго параметра переменную с типом char** в которой будет храниться указатель на массив со всеми указателями (char*) на переданные параметры void myFunctionName(byte argc, char** argv) { /* ... */ } Функция всегда должна иметь такой вид, даже если не подразумевается, что ей будут передаваться какие-либо параметры.
      Чтобы перебрать все переданные параметры и вывести их в консоль, можно воспользоваться следующим примером
      void myFunctionName(byte argc, char** argv) { if (0 < argc) { for (uint8_t i = 0; i < argc; i++) { Serial.printf("%i. %s\n", i, argv[i]); } } } Пример вызова пользовательской функции без параметров и с ними
      # test No parameter was passed # test p1 p2 p3 p4 p5 0. p1 1. p2 2. p3 3. p4 4. p5 Помните, что параметры представлены в виде указателей и работать с ними нужно как с обычными переменными не получится т.к указатель содержит не значение переменной (переданный параметр), а указатель на ту область памяти микроконтроллера в которой это значение находится.
      Чтобы сравнить два значения, например, параметр под индексом 0 (идет первым в списке) с каким-либо значением в программе, воспользуйтесь функцией strcmp, которая возвращает целочисленное значение, указывающее на лексическое расхождение строк. Если строки равны, то возвращаемое значение равно 0.
      if (!strcmp(argv[0], "wifi")) { Serial.println(F("Первый аргумент WiFi")); } else { Serial.println(F("Первый аргумент НЕ WiFi!!!")); } Для копирования значения указателя в другую переменную с типом char можно воспользоваться функцией strcpy
      char myVar[20]; strcpy(myVar, argv[0]); if (myVar == "123456") { Serial.prinln(F("ok")); } Также можно обернуть указатель объектом String и получить весь функционал этого объекта, который будет содержать значение параметра
      String param1(argv[0]); // String param1 = argv[0]; Serial.printf("argv[0] length: %i\n", param1.length()); Serial.printf("argv[0] is integer?: %s\n", param1.toInt() ? "YES" : "NO"); if (param1 == "qwerty") { Serial.println(F("Hello QWERTY!")); } С библиотекой идут несколько примеров, в том числе и пример конфигурации WiFi в режиме STA.
      Автор Kitsum Добавлен 05.12.2018 Категория Библиотеки  
    • Автор: Kitsum
      Просмотреть файл [esp8266] Библиотека smartBlink, реализует умное управление штатным светодиодом, что позволяет добавить индикацию состояния вашей программы или микроконтроллера.
      Основная задача библиотеки, это добавление индикации состояния Вашей программы или микроконтроллера. Отображение состояния производится посредством светодиода. Что самое важное, работа библиотеки через прерывание, это позволяет ей поддерживать индикацию даже в то время, когда выполняется длительный код основной программы. Например, Вы можете использовать её для отображения в каком режиме сейчас работает WiFi микроконтроллера, STA или AP и т.д. Или ход выполнения какой-либо операции, например, передача данных на внешний сервер.
      Подключение библиотеки
      #include <smartBlink.h> Чтобы инициализировать управление светодиодом необходимо создать объект, через который мы буем задавать режимы работы индикации.
      smartBlink::smartBlink(byte gpio, bool on = LOW); Объекту необходимо передать два параметра, первый это номер порта, на котором находится светодиод, а второй это уровень логического сигнала, который заставит светодиод работать. Сигнал может быть низким (LOW) или высоким (HIGH), это зависит от схемотехники подключения светодиода.
      Например, штатный светодиод модуля ESP12, использующий GPIO2 (порт 2) можно объявить следующим образом.
      #define led2_pin 2 #define led2_on_signal LOW smartBlink led2(led2_pin, led2_on_signal); Теперь можно в основной программе использовать метод устанавливающий какой режим индикации использовать.
      smartBlink::setMode(mode_t mode); Например, зададим режим светодиода led2 в котором светодиод будет давать одну короткую вспышку раз в секунду.
      led2.setMode(smartBlink::mode_flash1); Режимов работы может быть несколько.
      led2.setMode(smartBlink::mode_off); led2.setMode(smartBlink::mode_flash1); led2.setMode(smartBlink::mode_flash2); led2.setMode(smartBlink::mode_flash3); led2.setMode(smartBlink::mode_flash4); led2.setMode(smartBlink::mode_burn); led2.setMode(smartBlink::mode_inhalf); Чтобы вернуть предыдущий режим индикации для ранее объявленного светодиода led2 используйте следующий метод
      led2.previous(); Благодаря работе библиотеки через прерывания по таймеру, индикация будет работать даже в тех случаях, когда выполняется долгий код.
      С библиотекой идут несколько примеров.
      Автор Kitsum Добавлен 10.12.2018 Категория Библиотеки  
    • Автор: Kitsum
      Основная задача библиотеки, это добавление индикации состояния Вашей программы или микроконтроллера. Отображение состояния производится посредством светодиода. Что самое важное, работа библиотеки через прерывание, это позволяет ей поддерживать индикацию даже в то время, когда выполняется длительный код основной программы. Например, Вы можете использовать её для отображения в каком режиме сейчас работает WiFi микроконтроллера, STA или AP и т.д. Или ход выполнения какой-либо операции, например, передача данных на внешний сервер.
      Подключение библиотеки
      #include <smartBlink.h> Чтобы инициализировать управление светодиодом необходимо создать объект, через который мы буем задавать режимы работы индикации.
      smartBlink::smartBlink(byte gpio, bool on = LOW); Объекту необходимо передать два параметра, первый это номер порта, на котором находится светодиод, а второй это уровень логического сигнала, который заставит светодиод работать. Сигнал может быть низким (LOW) или высоким (HIGH), это зависит от схемотехники подключения светодиода.
      Например, штатный светодиод модуля ESP12, использующий GPIO2 (порт 2) можно объявить следующим образом.
      #define led2_pin 2 #define led2_on_signal LOW smartBlink led2(led2_pin, led2_on_signal); Теперь можно в основной программе использовать метод устанавливающий какой режим индикации использовать.
      smartBlink::setMode(mode_t mode); Например, зададим режим светодиода led2 в котором светодиод будет давать одну короткую вспышку раз в секунду.
      led2.setMode(smartBlink::mode_flash1); Режимов работы может быть несколько.
      led2.setMode(smartBlink::mode_off); led2.setMode(smartBlink::mode_flash1); led2.setMode(smartBlink::mode_flash2); led2.setMode(smartBlink::mode_flash3); led2.setMode(smartBlink::mode_flash4); led2.setMode(smartBlink::mode_burn); led2.setMode(smartBlink::mode_inhalf); Чтобы вернуть предыдущий режим индикации для ранее объявленного светодиода led2 используйте следующий метод
      led2.previous(); Благодаря работе библиотеки через прерывания по таймеру, индикация будет работать даже в тех случаях, когда выполняется долгий код.
      С библиотекой идут несколько примеров.
  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу.

×
×
  • Создать...