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

master
SmartUaWIn 2021-03-17 18:45:55 +02:00
parent 25e7c03236
commit 70a5bd4b86
2 changed files with 337 additions and 343 deletions

View File

@ -8,6 +8,7 @@
Диапазон измерения концентрации летучих органических веществ 0 ... 1187 ppb
*/
#include "esp_sleep.h"
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
#include <Preferences.h> //Сохранение настроек хеша прошивки
@ -20,7 +21,8 @@
#include <TimeLib.h> //Внутреннее время
#include <Wire.h> //Библиотека дял I2C
#include "ClosedCube_HDC1080.h" //Температура влажность
#include "Adafruit_CCS811.h" //eco2 Tvoc
//#include "Adafruit_CCS811.h" //eco2 Tvoc
#include "SparkFunCCS811.h"
#include <PubSubClient.h> //Mtqq
#include <ArduinoJson.h> //Упакова в JSon - удобная библиотека
@ -28,6 +30,11 @@
//Наша кнопочка при нажатии на которую произойдет вызов wifi менеджера и перезагрузка в станцию
#define TRIGGER_PIN 39
#define uS_TO_S_FACTOR 1000000
#define TIME_TO_SLEEP 30
#define CCS811_ADDR 0x5B //Default I2C Address
//#define CCS811_ADDR 0x5A //Alternate I2C Address
unsigned int VersionSW = 225; //65536 Версия прошивки
@ -35,13 +42,33 @@ unsigned int VersionSW = 225; //65536 Версия прошивки
//19 - вывод в консоль всех действий, ошибки с обновлнеием - починил, прияногое мигание светодиодом, тест для поиска metrics.
//21 - убран мак из вывода в топике
//22 - поправлено поиск сервера по metrics local.
//23 - добавленн BSID
//23 - добавленн BSID
// #include "driver / rtc_io.h"
// gpio_num_t pin_MOSFET = GPIO_NUM_15;
// void setup () {
// rtc_gpio_init (pin_MOSFET);
// rtc_gpio_set_direction (pin_MOSFET, RTC_GPIO_MODE_OUTPUT_ONLY);
// rtc_gpio_set_level (pin_MOSFET, 0); // GPIO НИЗКИЙ
// задержка (5000);
// rtc_gpio_set_level (pin_MOSFET, 1); // GPIO ВЫСОКИЙ
// esp_sleep_pd_config (ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
// esp_sleep_enable_timer_wakeup (60 * 1000 * 1000);
// esp_deep_sleep_start ();
// }
WiFiManager wm; // обьект менеджера
WiFiManagerParameter custom_field;
Preferences OTApreferences; //Обьект хранения настроек хеша прошивки
Adafruit_CCS811 ccs;
CCS811 ccs(CCS811_ADDR);
ClosedCube_HDC1080 hdc1080;
StaticJsonDocument<200> doc, other;
@ -52,26 +79,26 @@ IPAddress IpMqtt;
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "0.ua.pool.ntp.org", 7200, 60000); //Собственно сервер времени смещение и частоат запроса, но он вручную
const PROGMEM char *willmess = "{\"conn\":\"err\"}";
const char *mqttHostName = "cctv.automation.art"; //Хостнейм брокера metrics.local cctv.automation.art //192.168.89.210
unsigned int mqttPort = 8889; //Порт брокера 1883 8889
String getMacAddress();
String macc = getMacAddress();
String topicTemp = "aastudio/" + macc + "/data/0";
String willTopicTemp = "aastudio/" + macc + "/status";
const PROGMEM char *mqttLogin = "login", *mqttPass = "password";
char bufTopic[140];
char bufWillTopic[150];
// +mac адресс девайса Префикс топика
const PROGMEM char *mqttLogin = "login", //Логин пароль - необходимо сменить код при connect()
*mqttPass = "password";
const char *mqttIPHost;
const char *mqttIPHost; //тут хранится IP хоста по хостнейму
unsigned long timingUpdate, timingReqSensor, timingSendMqtt; //Таймеры для millis()
int PROGMEM nextM5Update = 450000; //каждые 7.5 минут запрос обновления с сервера
int PROGMEM nextReqSensor = 10000; //опрос датчиков раз в 10 секунд
int PROGMEM nextMqttSend = 60000; //Отправка
RTC_DATA_ATTR unsigned long timingUpdate, timingSendMqtt; //Таймеры для millis()
int PROGMEM nextM5Update = 450000; //каждые 7.5 минут запрос обновления с сервера
int PROGMEM nextReqSensor = 10000; //опрос датчиков раз в 10 секунд
int PROGMEM nextMqttSend = 60000; //Отправка
//Поправочные коефициенты для датчиков
//[24A160474D14, 5002919F5450, 5002918A38CC]
@ -86,7 +113,6 @@ byte errorID = 0;
long rssi = 0;
//Кусок кода поправить - так делать нельзя
#define NUM_AVER 5
float averageT, averageH, averageECO, averageTVOC; // перем. среднего
float valArrayT[NUM_AVER], valArrayH[NUM_AVER], valArrayECO[NUM_AVER], valArrayTVOC[NUM_AVER]; // массив
@ -99,87 +125,77 @@ bool flagblink = true;
//Настройки
void setup()
{
btStop();
// esp_bt_controller_disable();
// adc_power_on();
M5.begin(true, false, true);
Wire.begin(25, 21); //Пины для I2c на ATOM
Wire.begin(25, 21); //Пины для I2c на ATOM
pinMode(23, OUTPUT); //Пин датчика для работы
digitalWrite(23, LOW);
pinMode(TRIGGER_PIN, INPUT);
hdc1080.begin(0x40); //14 бит температура и влажность
hdc1080.setResolution(HDC1080_RESOLUTION_11BIT, HDC1080_RESOLUTION_11BIT);
if (!ccs.begin()) //The device's I2C address is 0x5A
{
Serial.println("Failed to start sensor CCS811! ");
}
//ccs.setTempOffset(8.6);
//Установка коеффициентов каллибровки по MAC адресу
// SetCallibrationCoeff();
delay(15);
WiFi.mode(WIFI_STA);
//Serial.begin(115200);
////////////Serial.setDebugOutput(true);
String topicTemp = "/aastudio/" + macc;
String willTopicTemp = topicTemp + "/status";
Serial.begin(115200);
Serial.setDebugOutput(true);
topicTemp.toCharArray(bufTopic, topicTemp.length() + 1);
willTopicTemp.toCharArray(bufWillTopic, willTopicTemp.length() + 1);
////////////Serial.println("\n Starting station");
pinMode(TRIGGER_PIN, INPUT);
Serial.println(bufTopic);
Serial.println(bufWillTopic);
// wm.resetSettings(); // wipe settings
// add a custom input field
// int customFieldLength = 40;
// new (&custom_field) WiFiManagerParameter("customfieldid", "Custom Field Label", "Custom Field Value", customFieldLength,"placeholder=\"Custom Field Placeholder\"");
// test custom html input type(checkbox)
// new (&custom_field) WiFiManagerParameter("customfieldid", "Custom Field Label", "Custom Field Value", customFieldLength,"placeholder=\"Custom Field Placeholder\" type=\"checkbox\""); // custom html type
// test custom html(radio)
const char *custom_radio_str = "<br/><label for='customfieldid'>Custom Field Label</label><input type='radio' name='customfieldid' value='1' checked> One<br><input type='radio' name='customfieldid' value='2'> Two<br><input type='radio' name='customfieldid' value='3'> Three";
new (&custom_field) WiFiManagerParameter(custom_radio_str); // custom html input
wm.addParameter(&custom_field);
wm.setSaveParamsCallback(saveParamCallback);
// custom menu via array or vector
// menu tokens, "wifi","wifinoscan","info","param","close","sep","erase","restart","exit" (sep is seperator) (if param is in menu, params will not show up in wifi page!)
// const char* menu[] = {"wifi","info","param","sep","restart","exit"};
// wm.setMenu(menu,6);
// const char *custom_radio_str = "<br/><label for='customfieldid'>Custom Field Label</label><input type='radio' name='customfieldid' value='1' checked> One<br><input type='radio' name='customfieldid' value='2'> Two<br><input type='radio' name='customfieldid' value='3'> Three";
// new (&custom_field) WiFiManagerParameter(custom_radio_str); // custom html input
// wm.addParameter(&custom_field);
// wm.setSaveParamsCallback(saveParamCallback);
std::vector<const char *> menu = {"wifi", "info", "param", "sep", "restart", "exit"};
wm.setMenu(menu);
// set dark theme
wm.setClass("invert");
//set static ip
// wm.setSTAStaticIPConfig(IPAddress(10,0,1,99), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); // set static ip,gw,sn
// wm.setShowStaticFields(true); // force show static ip fields
// wm.setShowDnsFields(true); // force show dns field always
// wm.setConnectTimeout(20); // how long to try to connect for before continuing
wm.setConfigPortalTimeout(60); // auto close configportal after n seconds
// wm.setCaptivePortalEnable(false); // disable captive portal redirection
// wm.setAPClientCheck(true); // avoid timeout if client connected to softap
// wifi scan settings
// wm.setRemoveDuplicateAPs(false); // do not remove duplicate ap names (true)
// wm.setMinimumSignalQuality(20); // set min RSSI (percentage) to show in scans, null = 8%
// wm.swifietShowInfoErase(false); // do not show erase button on info page
// wm.setScanDispPerc(true); // show RSSI as percentage not graph icons
// wm.setBreakAfterConfig(true); // always exit configportal even if wifi save fails
//wm.setConfigPortalTimeout(60);
wm.setMinimumSignalQuality(20);
wm.setScanDispPerc(true);
wm.setWiFiAutoReconnect(true);
bool res;
// res = wm.autoConnect(); // auto generated AP name from chipid
// res = wm.autoConnect("AutoConnectAP"); // anonymous ap
res = wm.autoConnect("AirQaPortal", "12345678"); // Подключение к анонимной точке доступа
if (!res)
{
////////////Serial.println("Failed to connect or hit timeout");
// ESP.restart();
ESP.restart();
}
else
{
////////////Serial.println("Server AirQaPortal start");
}
if (!ccs.begin()) //The device's I2C address is 0x5A
{
////////////Serial.println("Failed to start sensor CCS811! ");
}
ccs.setTempOffset(8.6);
hdc1080.begin(0x40); //14 бит температура и влажность
hdc1080.setResolution(HDC1080_RESOLUTION_14BIT, HDC1080_RESOLUTION_14BIT);
//Установка коеффициентов каллибровки по MAC адресу
SetCallibrationCoeff();
//Запрос IP сервера MQTT и установка сервера
setMqttServer();
reqNtpTime();
}
}
//Установка сервера и порта
void setMqttServer()
@ -187,104 +203,95 @@ void setMqttServer()
mdns_init();
IPAddress IpMqtt, ipaddr;
ipaddr = MDNS.queryHost(mqttHostName); // .local omitted
// ////////////Serial.println(ipaddr.toString());
ipaddr = MDNS.queryHost(mqttHostName);
if (ipaddr.toString() == "0.0.0.0")
{
//////Serial.println("MDNS.queryHost==0.0.0.0");
Serial.println("MDNS.queryHost==0.0.0.0");
int err = WiFi.hostByName(mqttHostName, IpMqtt);
if (err == 1)
{
setServCall(IpMqtt);
// MqttClient.setServer(IpMqtt, mqttPort);
}
else
{
//////Serial.print("Error code hostByName(): ");
//////Serial.println(err);
Serial.print("Error code hostByName(): ");
Serial.println(err);
}
}
else
{
setServCall(ipaddr);
// MqttClient.setServer(ipaddr, mqttPort);
}
//////Serial.printf("Last Error UPDATE (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
//////Serial.println(ESPhttpUpdate.getLastError());
//////Serial.println(ESPhttpUpdate.getLastErrorString().c_str());
}
void setServCall(IPAddress SetIpaddr)
int setServCall(IPAddress SetIpaddr)
{
//////Serial.println("setServCall");
//////Serial.println(SetIpaddr);
MqttClient.setServer(SetIpaddr, mqttPort);
MqttClient.setCallback(callback);
////////Serial.println("Set MQTT Server - OK");
// MqttClient.setCallback(callback);
////////Serial.println("Set MQTT Server - OK") ;
return 0;
}
//Функция получения данных из MQTT если мы подпишемся на топики
void callback(char *topic, byte *payload, unsigned int length)
{
////////////Serial.print("Message arrived [");
////////////Serial.print(topic);
//////////Serial.print("] ");
for (int i = 0; i < length; i++)
{
//////////Serial.print((char)payload[i]);
}
//////////Serial.println();
}
// void callback(char *topic, byte *payload, unsigned int length)
// {
// ////////////Serial.print("Message arrived [");
// ////////////Serial.print(topic);
// //////////Serial.print("] ");
// for (int i = 0; i < length; i++)
// {
// //////////Serial.print((char)payload[i]);
// }
// //////////Serial.println();
// }
//Запрос времени NTP и установка локлаьного времени
void reqNtpTime()
int reqNtpTime()
{
timeClient.update();
uint32_t timeEpoch = timeClient.getEpochTime();
setTime(timeEpoch);
//////////Serial.print(timeEpoch);
//////////Serial.print(" <=ntp== ==device=> ");
//////////Serial.println(now());
if (timeEpoch < 100000)
if (timeClient.update())
{
errorID = 1;
uint32_t timeEpoch = timeClient.getEpochTime();
setTime(timeEpoch);
Serial.print(timeEpoch);
Serial.print(" <=ntp== ==device=> ");
Serial.println(now());
if (timeEpoch < 100000)
{
Serial.println("Error Time");
}
}
return 0;
}
//Нажатие кнопки для сброса
void checkButton()
int checkButton()
{
//////Serial.println("Button Pressed to RESET");
disconnectMQTT();
Serial.println("Button Pressed to RESET");
wm.resetSettings();
ESP.restart();
// ESP.restart();
//////////Serial.println("Starting config portal");
//wm.setConfigPortalTimeout(120);
wm.setConfigPortalTimeout(120);
// if (!wm.startConfigPortal("AirQaPortal", "12345678")) //Логин и пароль точки доступа
// {
// //////////Serial.println("failed to connect or hit timeout");
if (!wm.startConfigPortal("AirQaPortal", "12345678")) //Логин и пароль точки доступа
{
Serial.println("failed to connect or hit timeout");
// // ESP.restart();
// }
// else
// {
// //////////Serial.println("Clien connected to AP");
// }
ESP.restart();
}
else
{
Serial.println("Clien connected to AP");
}
return 0;
}
void saveParamCallback()
{
//////Serial.println("[CALLBACK] saveParamCallback fired");
//////Serial.println("PARAM customfieldid = " + getParam("customfieldid"));
}
// String getParam(String name)
// {
// String value;
// if (wm.server->hasArg(name))
@ -298,7 +305,7 @@ void saveParamCallback()
void OTAUpdate()
{
//////////Serial.println("OTAUpdate() START");
Serial.println("OTAUpdate() START");
bool flagOTA = false;
String keyOTA;
String payload;
@ -306,21 +313,19 @@ void OTAUpdate()
if (WiFi.status() == WL_CONNECTED)
{
HTTPClient http;
String serverPath = "http://meteosence.s-host.net/airqa/airquality.php?meteopas=e93gme9hAt9nSWaV&mac=" + macc + "&meteodata=gethash";
//////Serial.println(serverPath);
String serverPath = "http://Dmeteosence.s-host.net/airqa/airquality.php?meteopas=e93gme9hAt9nSWaV&mac=" + macc + "&meteodata=gethash";
Serial.println(serverPath);
http.begin(serverPath.c_str());
int httpResponseCode = http.GET();
if (httpResponseCode > 0)
{
////////Serial.print("HTTP Response code: ");
////////Serial.println(httpResponseCode);
Serial.println(httpResponseCode);
payload = http.getString();
////////Serial.print("Data from HTTP request (OTA Hash): ");
////////Serial.println(payload);
Serial.println(payload);
if (payload != "errno" || payload != "errfi")
{
@ -332,29 +337,25 @@ void OTAUpdate()
OTApreferences.putString("md5HashOTA", "undifined");
}
////////Serial.print("md5HashOTA in device: ");
keyOTA = OTApreferences.getString("md5HashOTA");
////////Serial.println(keyOTA);
if (payload != keyOTA)
{
flagOTA = true;
OTApreferences.putString("md5HashOTA", payload);
////////Serial.println("flagOTA = true;");
}
OTApreferences.end();
}
else
{
////////Serial.print("Hosting return error: ");
////////Serial.println(payload);
Serial.print("Host error: ");
Serial.println(payload);
errorID = 3;
}
}
else
{
////////Serial.print("Error HTTP Response code: ");
////////Serial.println(httpResponseCode);
Serial.println(httpResponseCode);
errorID = 2;
}
// Free resources
@ -368,7 +369,6 @@ void OTAUpdate()
if (flagOTA == true)
{
// flagOTA = false;
// ////////Serial.println("flagOTA = false;");
disconnectMQTT();
@ -378,32 +378,31 @@ void OTAUpdate()
//После update ничего не происходит, такая вот особенность.
//Если все прошло хорошо, перезагрузка на новую прошивку
// Если указано значение true, модуль ESP перезагрузится после успешного завершения обновления. В случае ложного , модуль не перезагружается автоматически. Загруженная новая прошивка остается в стадии обновления флэш-памяти на модуле ESP.
// Процесс загрузки во время следующего запуска модуля путем сброса скопирует обновленное микропрограммное обеспечение в фактическую область программы, и запустится новая программа эскиза. Значение по умолчанию верно.
////////Serial.print("ret ");
////////Serial.println(ret);
Serial.println(ret);
switch (ret)
{
case HTTP_UPDATE_FAILED:
////Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
////Serial.println(ESPhttpUpdate.getLastError());
////Serial.println(ESPhttpUpdate.getLastErrorString().c_str());
//////Serial.println("HTTP_UPDATE_FAILD Error");
Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
Serial.println(ESPhttpUpdate.getLastError());
Serial.println(ESPhttpUpdate.getLastErrorString().c_str());
Serial.println("HTTP_UPDATE_FAILD Error");
ESP.restart();
break;
case HTTP_UPDATE_NO_UPDATES:
////Serial.println("HTTP_UPDATE_NO_UPDATES");
Serial.println("HTTP_UPDATE_NO_UPDATES");
ESP.restart();
break;
case HTTP_UPDATE_OK:
////Serial.println("HTTP_UPDATE_OK");
Serial.println("HTTP_UPDATE_OK");
ESP.restart();
break;
@ -412,9 +411,9 @@ void OTAUpdate()
}
//Функция для индикации Led
void ledset(char color, bool blink = false)
void ledset(char color = 't', bool blink = false)
{
M5.dis.setBrightness(120); //Половина яркости
M5.dis.setBrightness(30); //Половина яркости
switch (color)
{
case 'g':
@ -473,91 +472,28 @@ void SetCallibrationCoeff()
}
}
//Ниже отдельные функции средних арифметических для каждого параместра с историей
float middleArifmT(float newVal)
{
valArrayT[idxT] = newVal; // пишем каждый раз в новую ячейку
if (++idxT >= NUM_AVER)
idxT = 0; // перезаписывая самое старое значение
averageT = 0; // обнуляем среднее
for (int i = 0; i < NUM_AVER; i++)
{
averageT += valArrayT[i]; // суммируем
}
averageT /= NUM_AVER; // делим
// ////////Serial.println(averageT);
return averageT; // возвращаем
}
float middleArifmH(float newVal)
{ // принимает новое значение
valArrayH[idxH] = newVal; // пишем каждый раз в новую ячейку
if (++idxH >= NUM_AVER)
idxH = 0; // перезаписывая самое старое значение
averageH = 0; // обнуляем среднее
for (int i = 0; i < NUM_AVER; i++)
{
averageH += valArrayH[i]; // суммируем
}
averageH /= NUM_AVER; // делим
return averageH; // возвращаем
}
float middleArifmECO(float newVal)
{ // принимает новое значение
valArrayECO[idxECO] = newVal; // пишем каждый раз в новую ячейку
if (++idxECO >= NUM_AVER)
idxECO = 0; // перезаписывая самое старое значение
averageECO = 0; // обнуляем среднее
for (int i = 0; i < NUM_AVER; i++)
{
averageECO += valArrayECO[i]; // суммируем
}
averageECO /= NUM_AVER; // делим
return averageECO; // возвращаем
}
float middleArifmTVOC(float newVal)
{ // принимает новое значение
valArrayTVOC[idxTVOC] = newVal; // пишем каждый раз в новую ячейку
if (++idxTVOC >= NUM_AVER)
idxTVOC = 0; // перезаписывая самое старое значение
averageTVOC = 0; // обнуляем среднее
for (int i = 0; i < NUM_AVER; i++)
{
averageTVOC += valArrayTVOC[i]; // суммируем
}
averageTVOC /= NUM_AVER; // делим
return averageTVOC; // возвращаем
}
//Запрос данных с датчиков.
void reqSensorData()
{
delay(15);
float hdc1080Temp = 0, hdc1080Hum = 0;
int eco2 = 0, tvoc = 0;
if (ccs.available())
if (ccs.dataAvailable())
{
if (!ccs.readData())
{
eco2 = ccs.geteCO2();
tvoc = ccs.getTVOC();
}
else
{
eco2 = 0;
tvoc = 0;
errorID = 4;
}
ccs.readAlgorithmResults();
eco2 = ccs.getCO2();
tvoc = ccs.getTVOC();
}
else
{
eco2 = 0;
tvoc = 0;
Serial.println("Error read ECO TVOC");
errorID = 5;
}
hdc1080Temp = hdc1080.readTemperature() + callibrationT;
hdc1080Hum = hdc1080.readHumidity() + callibrationH;
hdc1080Temp = hdc1080.readTemperature();
hdc1080Hum = hdc1080.readHumidity();
if (hdc1080Temp < -40 || hdc1080Temp > 60)
{
@ -568,85 +504,103 @@ void reqSensorData()
{
errorID = 7;
}
// ////////Serial.println("Original data: ");
// ////////Serial.println(hdc1080.readTemperature());
// ////////Serial.println(hdc1080.readHumidity());
// ////////Serial.println("Calibration data: ");
// ////////Serial.print(hdc1080Temp);
// ////////Serial.println(" ");
// ////////Serial.println(hdc1080Hum);
Serial.println("Original data: ");
Serial.print(hdc1080.readTemperature());
Serial.print(" ");
Serial.println(hdc1080.readHumidity());
TempAv = middleArifmT(hdc1080Temp);
HumAv = middleArifmH(hdc1080Hum);
Eco2Av = middleArifmECO(eco2);
TvocAv = middleArifmTVOC(tvoc);
Serial.println("Calibration data: ");
Serial.print(hdc1080Temp);
Serial.print(" ");
Serial.println(hdc1080Hum);
TempAv = hdc1080Temp;
HumAv = hdc1080Hum;
Eco2Av = eco2;
TvocAv = tvoc;
rssi = WiFi.RSSI();
// hall=hallRead();
if (hdc1080Hum > 50 || hdc1080Hum < 39)
{
ledset('r', true);
}
if (hdc1080Temp > 24 || hdc1080Temp < 19)
{
ledset('r', true);
}
if (tvoc > 500)
{
ledset('r', true);
}
if (eco2 > 1000)
{
ledset('r', true);
}
}
//Отправка данных по MQTT
void SendMqttReq()
int SendMqttReq(bool sendVal = true, bool sendStatus = true, byte statusConn = 1)
{
char HumidityInt[8], TemperatureInt[8];
dtostrf(TempAv * 100, 4, 0, TemperatureInt);
dtostrf(HumAv * 100, 4, 0, HumidityInt);
// int tBytes = SPIFFS.totalBytes()/1024;
// int uBytes = SPIFFS.usedBytes()/1024;
doc["swver"] = VersionSW;
doc["t"] = atoi(TemperatureInt);
doc["h"] = atoi(HumidityInt);
doc["eco"] = (int)Eco2Av;
doc["tvoc"] = (int)TvocAv;
doc["rssi"] = rssi;
doc["bsid"] = WiFi.BSSID();
// doc["hall"]= hall;
doc["lasterror"] = errorID; //По умолчанию 0
// doc["memory"][0]= tBytes;
// doc["memory"][1] =uBytes;
doc["time"] = now();
char resultString[200];
String JsonData = "";
serializeJson(doc, JsonData);
Serial.println(JsonData); //Вывод JSON строки в консоль
JsonData.toCharArray(resultString, JsonData.length() + 1);
if (mqttSendFlag == true)
{
MqttClient.publish(bufTopic, resultString, true);
////Serial.println("SentToTopic - ok");
errorID = 0;
char resultString[200];
String JsonData = "";
rssi = WiFi.RSSI();
unsigned long timeNow = now();
if (sendVal == true)
{
doc["t"] = TempAv;
doc["h"] = HumAv;
doc["eco"] = (int)Eco2Av;
doc["tvoc"] = (int)TvocAv;
doc["ligh"] = (int)map(analogRead(33), 0, 4095, 100, 0);
doc["ts"] = timeNow;
serializeJson(doc, JsonData);
doc.remove("t");
doc.remove("h");
doc.remove("eco");
doc.remove("tvoc");
doc.remove("ligh");
doc.remove("ts");
doc.clear();
doc.garbageCollect();
Serial.println(JsonData); //Вывод JSON строки в консоль
JsonData.toCharArray(resultString, JsonData.length() + 1);
MqttClient.publish(bufTopic, resultString, true);
}
if (sendStatus == true)
{
const char *conn;
switch (statusConn)
{
case 1:
conn = "on";
break;
case 2:
conn = "off";
break;
case 3:
conn = "slp";
break;
default:
break;
}
doc["conn"] = conn;
doc["rssi"] = rssi;
doc["bsid"] = WiFi.BSSIDstr();
//doc["lasterror"] = errorID;
doc["ts"] = timeNow;
doc["sv"] = VersionSW;
JsonData = "";
serializeJson(doc, JsonData);
Serial.println(JsonData); //Вывод JSON строки в консоль
doc.clear();
doc.garbageCollect();
JsonData.toCharArray(resultString, JsonData.length() + 1);
MqttClient.publish(bufWillTopic, resultString, true);
}
}
return 0;
}
//Переподключение при петери связи с MQTT
//10 раз проверили и вернулись в общий цикл что бы вдруг что втянуть обновления
void reconnectMqtt()
{
byte circle = 0;
@ -655,7 +609,7 @@ void reconnectMqtt()
////Serial.print("MQTT reconnect...");
circle++;
if (circle == 2)
if (circle == 2)
{
break;
}
@ -666,16 +620,13 @@ void reconnectMqtt()
//const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage
////Serial.println(clientId);
if (MqttClient.connect(clientId, bufWillTopic, 2, true, "OFFLINE"))
{
MqttClient.publish(bufTopic, "CONNECT", true);
MqttClient.publish(bufWillTopic, "ONLINE", true);
////Serial.println("MqttClient.connect() - OK");
if (MqttClient.connect(clientId, bufWillTopic, 2, true, willmess))
{
Serial.println("MqttClient.connect() - OK");
errorID = 8;
//client.subscribe("inTopic");
mqttSendFlag = true;
SendMqttReq(false, true, 1);
}
else
{
@ -704,60 +655,54 @@ void loop()
//Проверка старта сервера
M5.update();
//Если не определен IP то и не будет отправки.
// 40 секунд и происходит сброс настроек WIFI
if (M5.Btn.wasReleasefor(40000))
{
ledset('r', true);
checkButton();
}
//По таймеру запруск обновления прошивки
if (millis() - timingUpdate > nextM5Update)
{
reqNtpTime();
OTAUpdate();
// ////////Serial.print("OTAUpdate() - ");
// ////////Serial.println(millis());
timingUpdate = millis();
}
//Таймер запроса данных с датчиков
if (millis() - timingReqSensor > nextReqSensor)
{
reqSensorData();
ledset('b', true);
// ////////Serial.print("reqSensorData() - ");
// ////////Serial.println(millis());
timingReqSensor = millis();
}
//Таймер отправки данных в брокер
if (millis() - timingSendMqtt > nextMqttSend)
{
SendMqttReq();
ledset('g', true);
timingSendMqtt = millis();
}
//Тут же проверка подключения к MQTT
if (!MqttClient.connected())
{
reconnectMqtt();
ledset('w', true);
}
// ////////Serial.println("=============");
// rssi = WiFi.RSSI();
// ////////Serial.println(rssi);
// ////////Serial.println("=============");
//Если не определен IP то и не будет отправки.
// 40 секунд и происходит сброс настроек WIFI
if (M5.Btn.isPressed())
{
ledset('r', true);
checkButton();
}
if (millis() - timingUpdate > nextM5Update)
{
reqNtpTime();
OTAUpdate();
timingUpdate = millis();
}
reqSensorData();
ledset('g', true);
SendMqttReq(true, true, 3);
MqttClient.loop();
disconnectMQTT();
delay(500);
goToSleep();
}
int disconnectMQTT()
{
MqttClient.publish(bufTopic, "DISCONNECTED", true);
{
MqttClient.disconnect();
return 0;
}
int goToSleep()
{
ledset();
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
// adc_power_off();
esp_wifi_stop();
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
esp_deep_sleep_start();
}

View File

@ -1,5 +1,12 @@
# M5Atom_airqa
https://savjee.be/2019/12/esp32-tips-to-increase-battery-life/
<br/>
1. Подключить питание в USB<br/>
2. Зажать кнопку сверху на 40 секунд (не боковую. Боковая кнопка - это рестарт)<br/>
@ -59,4 +66,46 @@ https://pubsubclient.knolleary.net/api.html
https://ipc2u.ru/articles/prostye-resheniya/chto-takoe-mqtt/#kachestvo
https://www.hivemq.com/blog/mqtt-essentials-part-9-last-will-and-testament/
https://www.hivemq.com/blog/mqtt-essentials-part-9-last-will-and-testament/
САМАЯ ПРАВИЛЬНАЯ СТАТЬЯ ПРО СПЯЩИЙ РЕЖИМ
https://savjee.be/2019/12/esp32-tips-to-increase-battery-life
https://savjee.be/2019/12/esp32-tips-to-increase-battery-life/
Прежде всего, вы заметите, что два датчика дают разные показания. Вы должны знать (цитируя лист данных) «датчики оксидов металлов не дают абсолютных показаний». Да, они делают вид, что используют регистры CO2 и TVOC, но это не так. Они измеряют сопротивление своего слоя оксида металла, а затем проверяют, насколько оно отклоняется от нормального сопротивления, и это отклонение отображается на показаниях CO2 / TVOC. Проблема заключается в этом нормальном сопротивлении, снова цитируя лист данных: «Сопротивление RS изменяется от датчика к датчику (производственные вариации), от варианта использования к варианту использования и с течением времени». В итоге все датчики дают разные показания CO2 / TVOC, но когда они повышаются, по крайней мере, мы знаем, что воздух стал хуже.
Вторая проблема, которую вы поднимаете, - это падение показаний после включения и выключения питания. Это имеет аналогичную предысторию. Снова процитируем таблицу данных о том, что сопротивление чистого (нормального) воздуха изменяется: «Чтобы смягчить эту проблему, выходной сигнал датчика нормализован: RS делится на RA. Значение RA известно как базовое значение. RA не может быть определено с помощью однократной калибровки, она поддерживается на лету в программном обеспечении ». Посредством включения и выключения питания вы эффективно удаляете информацию о чистом воздухе, накопленную датчиком: если вы включаете датчик в плохом воздухе, он имеет это только как эталон и считает его чистым.
См. Раздел «Ручная коррекция базовой линии» в таблице данных.
Тест должен быть:
датчик включен более 20 мин (обкатка) на чистом воздухе, получить базовый уровень
возьмите пустую бутылку и налейте в нее каплю спирта
выключите датчик, положите в бутылку и снова включите.
Внутренняя базовая линия сбрасывается, но не нужно ждать приработки, потому что датчик был всего несколько секунд
прочитал tvoc, будет сообщено как нет / чистый воздух (потому что датчик проснулся в грязной бутылке)
Установите базовый уровень и прочтите снова tvoc, теперь он должен быть очень высоким.
https://learn.adafruit.com/adafruit-ccs811-air-quality-sensor?view=all
INT - это вывод прерывания-вывода. Это логика 3 В, и вы можете использовать ее, чтобы определить, когда готово новое показание или когда показание становится слишком высоким или слишком низким.
WAKE - это штифт для пробуждения датчика. Для связи с датчиком его необходимо заземлить. Этот вывод смещен по уровню, поэтому вы можете использовать логику 3-5 В постоянного тока.
RST - это вывод сброса. Когда его тянут на землю, датчик сбрасывается. Этот вывод смещен по уровню, поэтому вы можете использовать логику 3-5 В постоянного тока.
Лучший способ откалибровать HDC1080 - держать его в контролируемой среде (например, в климатической камере) вместе с эталонным датчиком высокой точности (например, с зеркалом точки росы RH Systems 473), оценивать смещение между HDC1080 и эталонный датчик и удалите это смещение в микропрограмме микроконтроллера.