2021-01-19 18:26:06 +02:00
/*
П и т а н и е 3 , 3 В
Л о г и ч е с к и е у р о в н и 3 , 3 В
Т о ч н о с т ь и з м е р е н и я в л а ж н о с т и ± 2 %
Т о ч н о с т ь и з м е р е н и я т е м п е р а т у р ы ± 0 , 2 ° C
Р а з р е ш а ю щ а я с п о с о б н о с т ь п о к а з а н и й д а т ч и к а HDC1080 14 б и т
Д и а п а з о н и з м е р е н и я к о н ц е н т р а ц и и CO2 : 400 . . . 8192 ppm
Д и а п а з о н и з м е р е н и я к о н ц е н т р а ц и и л е т у ч и х о р г а н и ч е с к и х в е щ е с т в 0 . . . 1187 ppb
*/
2021-01-14 23:27:49 +02:00
# include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
# include <Preferences.h> //Сохранение настроек хеша прошивки
# include <HTTPClient.h>
2021-01-21 17:54:46 +02:00
# include <ESP32httpUpdate.h> //Библиотека О Т А обновлений
# include "M5Atom.h" //Библиотека атома для функции Led и Кнопки, можно упразднить и убрать
2021-01-19 18:26:06 +02:00
2021-02-09 20:29:13 +02:00
# include <WiFiUdp.h> //Udp клиент
# include <NTPClient.h> //NTP запрос времени
# include <TimeLib.h> //Внутреннее время
# include <Wire.h> //Библиотека дял I2C
# include "ClosedCube_HDC1080.h" //Температура влажность
# include "Adafruit_CCS811.h" //eco2 Tvoc
# include <PubSubClient.h> //Mtqq
# include <ArduinoJson.h> //Упакова в JSon - удобная библиотека
# include <ESPmDNS.h>
2021-01-14 23:27:49 +02:00
//Наша кнопочка при нажатии на которую произойдет вызов wifi менеджера и перезагрузка в станцию
# define TRIGGER_PIN 39
2021-02-24 15:20:49 +02:00
unsigned int VersionSW = 225 ; //65536 Версия прошивки
2021-02-09 20:29:13 +02:00
//15 - добавлено то, с е , забыл вообще дописать что до б а вле но Serial
//19 - вывод в консоль всех действий, ошибки с обновлнеием - починил, прияногое мигание светодиодом, тест для поиска metrics.
2021-02-24 15:20:49 +02:00
//21 - убран мак из вывода в топике
2021-02-18 20:05:03 +02:00
//22 - поправлено поиск сервера по metrics local.
2021-01-20 21:27:05 +02:00
2021-01-14 23:27:49 +02:00
WiFiManager wm ; // обьект менеджера
WiFiManagerParameter custom_field ;
2021-02-09 20:29:13 +02:00
Preferences OTApreferences ; //Обьект хранения настроек хеша прошивки
2021-01-14 23:27:49 +02:00
2021-01-19 18:26:06 +02:00
Adafruit_CCS811 ccs ;
ClosedCube_HDC1080 hdc1080 ;
2021-02-09 20:29:13 +02:00
StaticJsonDocument < 200 > doc , other ;
2021-01-19 18:26:06 +02:00
WiFiClient espClient ;
PubSubClient MqttClient ( espClient ) ;
2021-02-25 16:22:57 +02:00
2021-01-19 18:26:06 +02:00
IPAddress IpMqtt ;
2021-01-20 21:27:05 +02:00
WiFiUDP ntpUDP ;
2021-02-09 20:29:13 +02:00
NTPClient timeClient ( ntpUDP , " 0.ua.pool.ntp.org " , 7200 , 60000 ) ; //Собственно сервер времени смещение и частоат запроса, но он вручную
2021-01-20 21:27:05 +02:00
2021-02-25 16:22:57 +02:00
const char * mqttHostName = " cctv.automation.art " ; //Хостнейм брокера metrics.local cctv.automation.art //192.168.89.210
unsigned int mqttPort = 8889 ; //Порт брокера 1883 8889
2021-02-24 15:20:49 +02:00
String getMacAddress ( ) ;
String macc = getMacAddress ( ) ;
2021-02-25 16:22:57 +02:00
char bufTopic [ 140 ] ;
char bufWillTopic [ 150 ] ;
2021-02-24 15:20:49 +02:00
// +mac адресс девайса Префикс топика
const PROGMEM char * mqttLogin = " login " , //Логин пароль - необходимо сменить код при connect()
2021-02-09 20:29:13 +02:00
* mqttPass = " password " ;
2021-02-24 15:20:49 +02:00
2021-02-09 20:29:13 +02:00
const char * mqttIPHost ; //тут хранится IP хоста по хостнейму
2021-01-19 18:26:06 +02:00
2021-02-09 20:29:13 +02:00
unsigned long timingUpdate , timingReqSensor , timingSendMqtt ; //Таймеры для millis()
int PROGMEM nextM5Update = 450000 ; //каждые 7.5 минут запрос обновления с сервера
int PROGMEM nextReqSensor = 10000 ; //опрос датчиков раз в 10 секунд
int PROGMEM nextMqttSend = 60000 ; //Отправка
2021-01-19 18:26:06 +02:00
2021-01-21 17:54:46 +02:00
//Поправочные коефициенты для датчиков
2021-01-19 18:26:06 +02:00
//[24A160474D14, 5002919F5450, 5002918A38CC]
//tcoeff[0,1,2]
//hcoeff[0,1,2]
2021-02-09 20:29:13 +02:00
float PROGMEM tcoeff [ 3 ] = { - 11.18 , - 9.62 , - 10.6 } ; //Температура
float PROGMEM hcoeff [ 3 ] = { 13.77 , 14.07 , 15.56 } ; //Влажность
2021-01-19 18:26:06 +02:00
float callibrationT = 0 , callibrationH = 0 ;
float TempAv , HumAv , Eco2Av , TvocAv ;
2021-02-09 20:29:13 +02:00
byte errorID = 0 ;
2021-01-19 18:26:06 +02:00
2021-02-09 20:29:13 +02:00
long rssi = 0 ;
2021-01-21 17:54:46 +02:00
//Кусок кода поправить - так делать нельзя
2021-01-20 21:27:05 +02:00
# define NUM_AVER 5
2021-02-25 16:22:57 +02:00
float averageT , averageH , averageECO , averageTVOC ; // перем. среднего
float valArrayT [ NUM_AVER ] , valArrayH [ NUM_AVER ] , valArrayECO [ NUM_AVER ] , valArrayTVOC [ NUM_AVER ] ; // массив
byte idxT = 0 , idxH = 0 , idxECO = 0 , idxTVOC = 0 ;
2021-01-19 18:26:06 +02:00
bool mqttSendFlag = false ;
int reqCounter = 0 ;
bool flagblink = true ;
2021-01-14 23:27:49 +02:00
2021-01-21 17:54:46 +02:00
//Настройки
2021-01-14 23:27:49 +02:00
void setup ( )
{
2021-01-19 18:26:06 +02:00
M5 . begin ( true , false , true ) ;
2021-02-09 20:29:13 +02:00
Wire . begin ( 25 , 21 ) ; //Пины для I2c на ATOM
2021-01-19 18:26:06 +02:00
2021-02-09 20:29:13 +02:00
pinMode ( 23 , OUTPUT ) ; //Пин датчика для работы
2021-01-19 18:26:06 +02:00
digitalWrite ( 23 , LOW ) ;
2021-01-14 23:27:49 +02:00
WiFi . mode ( WIFI_STA ) ;
2021-02-25 16:22:57 +02:00
//Serial.begin(115200);
////////////Serial.setDebugOutput(true);
String topicTemp = " /aastudio/ " + macc ;
String willTopicTemp = topicTemp + " /status " ;
2021-02-24 15:20:49 +02:00
2021-02-25 16:22:57 +02:00
topicTemp . toCharArray ( bufTopic , topicTemp . length ( ) + 1 ) ;
willTopicTemp . toCharArray ( bufWillTopic , willTopicTemp . length ( ) + 1 ) ;
2021-01-21 17:54:46 +02:00
2021-02-25 16:22:57 +02:00
////////////Serial.println("\n Starting station");
2021-02-09 20:29:13 +02:00
pinMode ( TRIGGER_PIN , INPUT ) ;
2021-01-14 23:27:49 +02:00
// wm.resetSettings(); // wipe settings
// add a custom input field
2021-02-25 16:22:57 +02:00
// int customFieldLength = 40;
2021-01-14 23:27:49 +02:00
// 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);
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
2021-02-25 16:22:57 +02:00
wm . setConfigPortalTimeout ( 60 ) ; // auto close configportal after n seconds
2021-01-14 23:27:49 +02:00
// 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%
2021-02-18 20:05:03 +02:00
// wm.swifietShowInfoErase(false); // do not show erase button on info page
2021-01-14 23:27:49 +02:00
// wm.setScanDispPerc(true); // show RSSI as percentage not graph icons
// wm.setBreakAfterConfig(true); // always exit configportal even if wifi save fails
bool res ;
// res = wm.autoConnect(); // auto generated AP name from chipid
// res = wm.autoConnect("AutoConnectAP"); // anonymous ap
2021-02-09 20:29:13 +02:00
res = wm . autoConnect ( " AirQaPortal " , " 12345678 " ) ; // Подключение к анонимной точке доступа
2021-01-14 23:27:49 +02:00
if ( ! res )
{
2021-02-25 16:22:57 +02:00
////////////Serial.println("Failed to connect or hit timeout");
2021-01-14 23:27:49 +02:00
// ESP.restart();
}
else
{
2021-02-25 16:22:57 +02:00
////////////Serial.println("Server AirQaPortal start");
2021-01-14 23:27:49 +02:00
}
2021-01-19 18:26:06 +02:00
if ( ! ccs . begin ( ) ) //The device's I2C address is 0x5A
{
2021-02-25 16:22:57 +02:00
////////////Serial.println("Failed to start sensor CCS811! ");
2021-01-19 18:26:06 +02:00
}
ccs . setTempOffset ( 8.6 ) ;
hdc1080 . begin ( 0x40 ) ; //14 бит температура и влажность
hdc1080 . setResolution ( HDC1080_RESOLUTION_14BIT , HDC1080_RESOLUTION_14BIT ) ;
//Установка коеффициентов каллибровки по MAC адресу
SetCallibrationCoeff ( ) ;
//Запрос IP сервера MQTT и установка сервера
setMqttServer ( ) ;
2021-01-20 21:27:05 +02:00
reqNtpTime ( ) ;
2021-01-19 18:26:06 +02:00
}
2021-01-21 17:54:46 +02:00
//Установка сервера и порта
2021-01-19 18:26:06 +02:00
void setMqttServer ( )
2021-02-09 20:29:13 +02:00
{
mdns_init ( ) ;
2021-02-24 15:20:49 +02:00
IPAddress IpMqtt , ipaddr ;
ipaddr = MDNS . queryHost ( mqttHostName ) ; // .local omitted
2021-02-25 16:22:57 +02:00
// ////////////Serial.println(ipaddr.toString());
2021-02-24 15:20:49 +02:00
if ( ipaddr . toString ( ) = = " 0.0.0.0 " )
{
2021-02-25 16:22:57 +02:00
//////Serial.println("MDNS.queryHost==0.0.0.0");
2021-02-24 15:20:49 +02:00
int err = WiFi . hostByName ( mqttHostName , IpMqtt ) ;
if ( err = = 1 )
{
setServCall ( IpMqtt ) ;
2021-02-25 16:22:57 +02:00
// MqttClient.setServer(IpMqtt, mqttPort);
2021-02-24 15:20:49 +02:00
}
else
{
2021-02-25 16:22:57 +02:00
//////Serial.print("Error code hostByName(): ");
//////Serial.println(err);
2021-02-24 15:20:49 +02:00
}
}
else
{
setServCall ( ipaddr ) ;
2021-02-25 16:22:57 +02:00
// MqttClient.setServer(ipaddr, mqttPort);
2021-02-24 15:20:49 +02:00
}
2021-02-25 16:22:57 +02:00
//////Serial.printf("Last Error UPDATE (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
//////Serial.println(ESPhttpUpdate.getLastError());
//////Serial.println(ESPhttpUpdate.getLastErrorString().c_str());
2021-02-24 15:20:49 +02:00
}
void setServCall ( IPAddress SetIpaddr )
{
2021-02-25 16:22:57 +02:00
//////Serial.println("setServCall");
//////Serial.println(SetIpaddr);
2021-02-24 15:20:49 +02:00
MqttClient . setServer ( SetIpaddr , mqttPort ) ;
MqttClient . setCallback ( callback ) ;
2021-02-25 16:22:57 +02:00
////////Serial.println("Set MQTT Server - OK");
2021-01-19 18:26:06 +02:00
}
2021-01-21 17:54:46 +02:00
//Функция получения данных из MQTT если мы подпишемся на топики
2021-01-19 18:26:06 +02:00
void callback ( char * topic , byte * payload , unsigned int length )
{
2021-02-25 16:22:57 +02:00
////////////Serial.print("Message arrived [");
////////////Serial.print(topic);
//////////Serial.print("] ");
2021-01-19 18:26:06 +02:00
for ( int i = 0 ; i < length ; i + + )
{
2021-02-25 16:22:57 +02:00
//////////Serial.print((char)payload[i]);
2021-01-19 18:26:06 +02:00
}
2021-02-25 16:22:57 +02:00
//////////Serial.println();
2021-01-14 23:27:49 +02:00
}
2021-01-21 17:54:46 +02:00
//Запрос времени NTP и установка локлаьного времени
2021-01-20 21:27:05 +02:00
void reqNtpTime ( )
{
timeClient . update ( ) ;
2021-02-09 20:29:13 +02:00
uint32_t timeEpoch = timeClient . getEpochTime ( ) ;
setTime ( timeEpoch ) ;
2021-02-25 16:22:57 +02:00
//////////Serial.print(timeEpoch);
//////////Serial.print(" <=ntp== ==device=> ");
//////////Serial.println(now());
2021-02-09 20:29:13 +02:00
if ( timeEpoch < 100000 )
{
errorID = 1 ;
}
2021-01-20 21:27:05 +02:00
}
2021-01-21 17:54:46 +02:00
//Нажатие кнопки для с б р о с а
2021-01-14 23:27:49 +02:00
void checkButton ( )
{
2021-02-25 16:22:57 +02:00
//////Serial.println("Button Pressed to RESET");
2021-02-24 15:20:49 +02:00
disconnectMQTT ( ) ;
2021-02-25 16:22:57 +02:00
wm . resetSettings ( ) ;
ESP . restart ( ) ;
2021-02-24 15:20:49 +02:00
2021-02-25 16:22:57 +02:00
//////////Serial.println("Starting config portal");
//wm.setConfigPortalTimeout(120);
2021-02-09 20:29:13 +02:00
2021-02-25 16:22:57 +02:00
// if (!wm.startConfigPortal("AirQaPortal", "12345678")) //Логин и пароль точки доступа
// {
// //////////Serial.println("failed to connect or hit timeout");
2021-01-14 23:27:49 +02:00
2021-02-25 16:22:57 +02:00
// // ESP.restart();
// }
// else
// {
// //////////Serial.println("Clien connected to AP");
// }
2021-01-14 23:27:49 +02:00
}
void saveParamCallback ( )
{
2021-02-25 16:22:57 +02:00
//////Serial.println("[CALLBACK] saveParamCallback fired");
//////Serial.println("PARAM customfieldid = " + getParam("customfieldid"));
2021-01-14 23:27:49 +02:00
}
2021-02-25 16:22:57 +02:00
// String getParam(String name)
// {
// String value;
// if (wm.server->hasArg(name))
// {
// value = wm.server->arg(name);
// }
// return value;
// }
2021-01-21 17:54:46 +02:00
//Обновление прошивки, происходит проверка и загрузка
2021-02-09 20:29:13 +02:00
2021-01-14 23:27:49 +02:00
void OTAUpdate ( )
{
2021-02-25 16:22:57 +02:00
//////////Serial.println("OTAUpdate() START");
2021-01-14 23:27:49 +02:00
bool flagOTA = false ;
String keyOTA ;
String payload ;
if ( WiFi . status ( ) = = WL_CONNECTED )
2021-01-21 17:54:46 +02:00
{
2021-01-14 23:27:49 +02:00
HTTPClient http ;
2021-02-24 15:20:49 +02:00
String serverPath = " http://meteosence.s-host.net/airqa/airquality.php?meteopas=e93gme9hAt9nSWaV&mac= " + macc + " &meteodata=gethash " ;
2021-02-09 20:29:13 +02:00
2021-02-25 16:22:57 +02:00
//////Serial.println(serverPath);
2021-02-09 20:29:13 +02:00
2021-01-14 23:27:49 +02:00
http . begin ( serverPath . c_str ( ) ) ;
int httpResponseCode = http . GET ( ) ;
if ( httpResponseCode > 0 )
{
2021-02-25 16:22:57 +02:00
////////Serial.print("HTTP Response code: ");
////////Serial.println(httpResponseCode);
2021-01-14 23:27:49 +02:00
payload = http . getString ( ) ;
2021-02-25 16:22:57 +02:00
////////Serial.print("Data from HTTP request (OTA Hash): ");
////////Serial.println(payload);
2021-01-14 23:27:49 +02:00
2021-02-09 20:29:13 +02:00
if ( payload ! = " errno " | | payload ! = " errfi " )
2021-01-14 23:27:49 +02:00
{
2021-02-24 15:20:49 +02:00
OTApreferences . begin ( " ota-config " ) ;
2021-02-09 20:29:13 +02:00
keyOTA = OTApreferences . getString ( " md5HashOTA " ) ;
if ( keyOTA . length ( ) < = 0 )
{
OTApreferences . putString ( " md5HashOTA " , " undifined " ) ;
}
2021-02-25 16:22:57 +02:00
////////Serial.print("md5HashOTA in device: ");
2021-02-09 20:29:13 +02:00
keyOTA = OTApreferences . getString ( " md5HashOTA " ) ;
2021-02-25 16:22:57 +02:00
////////Serial.println(keyOTA);
2021-01-14 23:27:49 +02:00
2021-02-09 20:29:13 +02:00
if ( payload ! = keyOTA )
{
flagOTA = true ;
OTApreferences . putString ( " md5HashOTA " , payload ) ;
2021-02-25 16:22:57 +02:00
////////Serial.println("flagOTA = true;");
2021-02-09 20:29:13 +02:00
}
2021-02-24 15:20:49 +02:00
OTApreferences . end ( ) ;
2021-02-09 20:29:13 +02:00
}
else
2021-01-14 23:27:49 +02:00
{
2021-02-25 16:22:57 +02:00
////////Serial.print("Hosting return error: ");
////////Serial.println(payload);
2021-02-09 20:29:13 +02:00
errorID = 3 ;
2021-01-14 23:27:49 +02:00
}
}
else
{
2021-02-25 16:22:57 +02:00
////////Serial.print("Error HTTP Response code: ");
////////Serial.println(httpResponseCode);
2021-02-09 20:29:13 +02:00
errorID = 2 ;
2021-01-14 23:27:49 +02:00
}
// Free resources
http . end ( ) ;
}
else
{
2021-02-25 16:22:57 +02:00
////////Serial.println("WHY WiFi is Disconnected??");
2021-01-14 23:27:49 +02:00
}
if ( flagOTA = = true )
{
2021-02-24 15:20:49 +02:00
// flagOTA = false;
2021-02-25 16:22:57 +02:00
// ////////Serial.println("flagOTA = false;");
2021-02-24 15:20:49 +02:00
disconnectMQTT ( ) ;
ESPhttpUpdate . rebootOnUpdate ( true ) ;
2021-01-14 23:27:49 +02:00
t_httpUpdate_return ret = ESPhttpUpdate . update ( " http://meteosence.s-host.net/airqa/airatoms.bin " ) ;
2021-02-09 20:29:13 +02:00
2021-01-21 17:54:46 +02:00
//После update ничего не происходит, такая вот особенность.
//Если все прошло хорошо, перезагрузка на новую прошивку
2021-01-14 23:27:49 +02:00
2021-02-24 15:20:49 +02:00
// Если указано значение true, модуль ESP перезагрузится после успешного завершения обновления. В случае ложного , модуль не перезагружается автоматически. Загруженная новая прошивка остается в стадии обновления флэш-памяти на модуле ESP.
// Процесс загрузки во время следующего запуска модуля путем с б р о с а скопирует обновленное микропрограммное обеспечение в фактическую область программы, и запустится новая программа эскиза. Значение по умолчанию верно.
2021-02-25 16:22:57 +02:00
////////Serial.print("ret ");
////////Serial.println(ret);
2021-01-14 23:27:49 +02:00
switch ( ret )
{
case HTTP_UPDATE_FAILED :
2021-02-25 16:22:57 +02:00
////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");
2021-01-14 23:27:49 +02:00
ESP . restart ( ) ;
break ;
case HTTP_UPDATE_NO_UPDATES :
2021-02-25 16:22:57 +02:00
////Serial.println("HTTP_UPDATE_NO_UPDATES");
2021-01-14 23:27:49 +02:00
ESP . restart ( ) ;
break ;
case HTTP_UPDATE_OK :
2021-02-25 16:22:57 +02:00
////Serial.println("HTTP_UPDATE_OK");
2021-01-14 23:27:49 +02:00
ESP . restart ( ) ;
break ;
}
}
}
2021-02-09 20:29:13 +02:00
//Функция для индикации Led
2021-01-19 18:26:06 +02:00
void ledset ( char color , bool blink = false )
{
2021-02-25 16:22:57 +02:00
M5 . dis . setBrightness ( 120 ) ; //Половина яркости
2021-01-19 18:26:06 +02:00
switch ( color )
{
case ' g ' :
M5 . dis . drawpix ( 0 , 0xf00000 ) ; //Зеленый
break ;
case ' r ' :
M5 . dis . drawpix ( 0 , 0x00f000 ) ; //Красный
break ;
case ' b ' :
M5 . dis . drawpix ( 0 , 0x0000f0 ) ; //Синий
break ;
case ' w ' :
M5 . dis . drawpix ( 0 , 0x707070 ) ; //Белый
break ;
default :
M5 . dis . clear ( ) ;
break ;
}
}
2021-01-21 17:54:46 +02:00
//Получение мак адреса
2021-01-19 18:26:06 +02:00
String getMacAddress ( )
{
uint8_t baseMac [ 6 ] ;
esp_read_mac ( baseMac , ESP_MAC_WIFI_STA ) ;
char baseMacChr [ 18 ] = { 0 } ;
sprintf ( baseMacChr , " %02X%02X%02X%02X%02X%02X " , baseMac [ 0 ] , baseMac [ 1 ] , baseMac [ 2 ] , baseMac [ 3 ] , baseMac [ 4 ] , baseMac [ 5 ] ) ;
return String ( baseMacChr ) ;
}
2021-01-21 17:54:46 +02:00
//Установка коефициентов калибровки
2021-01-19 18:26:06 +02:00
void SetCallibrationCoeff ( )
{
2021-02-25 16:22:57 +02:00
// ////////Serial.print("Mac: ");
// ////////Serial.println(getMacAddress());
2021-01-19 18:26:06 +02:00
//[24A160474D14, 5002919F5450, 5002918A38CC]
//tcoeff[0,1,2]
//hcoeff[0,1,2]
if ( macc = = " 24A160474D14 " )
{
callibrationT = tcoeff [ 0 ] ;
callibrationH = hcoeff [ 0 ] ;
}
if ( macc = = " 5002919F5450 " )
{
callibrationT = tcoeff [ 1 ] ;
callibrationH = hcoeff [ 1 ] ;
}
if ( macc = = " 5002918A38CC " )
{
callibrationT = tcoeff [ 2 ] ;
callibrationH = hcoeff [ 2 ] ;
}
}
2021-02-09 20:29:13 +02:00
//Ниже отдельные функции средних арифметических для каждого параместра с историей
2021-01-19 18:26:06 +02:00
float middleArifmT ( float newVal )
2021-01-20 21:27:05 +02:00
{
2021-01-19 18:26:06 +02:00
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 ; // делим
2021-01-20 21:27:05 +02:00
2021-02-25 16:22:57 +02:00
// ////////Serial.println(averageT);
2021-01-20 21:27:05 +02:00
return averageT ; // возвращаем
2021-01-19 18:26:06 +02:00
}
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 ; // возвращаем
}
2021-01-21 17:54:46 +02:00
//Запрос данных с датчиков.
2021-01-19 18:26:06 +02:00
void reqSensorData ( )
{
float hdc1080Temp = 0 , hdc1080Hum = 0 ;
int eco2 = 0 , tvoc = 0 ;
if ( ccs . available ( ) )
{
if ( ! ccs . readData ( ) )
{
eco2 = ccs . geteCO2 ( ) ;
tvoc = ccs . getTVOC ( ) ;
}
else
{
eco2 = 0 ;
tvoc = 0 ;
2021-02-09 20:29:13 +02:00
errorID = 4 ;
2021-01-19 18:26:06 +02:00
}
}
2021-02-09 20:29:13 +02:00
else
{
errorID = 5 ;
}
2021-01-19 18:26:06 +02:00
hdc1080Temp = hdc1080 . readTemperature ( ) + callibrationT ;
hdc1080Hum = hdc1080 . readHumidity ( ) + callibrationH ;
2021-02-24 15:20:49 +02:00
if ( hdc1080Temp < - 40 | | hdc1080Temp > 60 )
{
errorID = 6 ;
}
2021-02-09 20:29:13 +02:00
2021-02-24 15:20:49 +02:00
if ( hdc1080Hum < 0 | | hdc1080Temp > 100 )
{
errorID = 7 ;
}
2021-02-25 16:22:57 +02:00
// ////////Serial.println("Original data: ");
// ////////Serial.println(hdc1080.readTemperature());
// ////////Serial.println(hdc1080.readHumidity());
2021-01-20 21:27:05 +02:00
2021-02-25 16:22:57 +02:00
// ////////Serial.println("Calibration data: ");
// ////////Serial.print(hdc1080Temp);
// ////////Serial.println(" ");
// ////////Serial.println(hdc1080Hum);
2021-01-20 21:27:05 +02:00
2021-01-19 18:26:06 +02:00
TempAv = middleArifmT ( hdc1080Temp ) ;
HumAv = middleArifmH ( hdc1080Hum ) ;
Eco2Av = middleArifmECO ( eco2 ) ;
TvocAv = middleArifmTVOC ( tvoc ) ;
2021-02-09 20:29:13 +02:00
rssi = WiFi . RSSI ( ) ;
2021-02-24 15:20:49 +02:00
// hall=hallRead();
2021-02-09 20:29:13 +02:00
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 ) ;
}
2021-01-19 18:26:06 +02:00
}
2021-01-21 17:54:46 +02:00
//Отправка данных по MQTT
2021-01-19 18:26:06 +02:00
void SendMqttReq ( )
{
2021-01-20 21:27:05 +02:00
2021-01-21 17:54:46 +02:00
char HumidityInt [ 8 ] , TemperatureInt [ 8 ] ;
dtostrf ( TempAv * 100 , 4 , 0 , TemperatureInt ) ;
dtostrf ( HumAv * 100 , 4 , 0 , HumidityInt ) ;
2021-01-20 21:27:05 +02:00
2021-02-25 16:22:57 +02:00
int tBytes = SPIFFS . totalBytes ( ) / 1024 ;
int uBytes = SPIFFS . usedBytes ( ) / 1024 ;
2021-01-21 17:54:46 +02:00
doc [ " swver " ] = VersionSW ;
doc [ " t " ] = atoi ( TemperatureInt ) ;
doc [ " h " ] = atoi ( HumidityInt ) ;
doc [ " eco " ] = ( int ) Eco2Av ;
doc [ " tvoc " ] = ( int ) TvocAv ;
2021-02-09 20:29:13 +02:00
doc [ " rssi " ] = rssi ;
2021-02-24 15:20:49 +02:00
// doc["hall"]= hall;
2021-02-25 16:22:57 +02:00
doc [ " lasterror " ] = errorID ; //По умолчанию 0
doc [ " memory " ] [ 0 ] = tBytes ;
doc [ " memory " ] [ 1 ] = uBytes ;
2021-01-21 17:54:46 +02:00
doc [ " time " ] = now ( ) ;
2021-01-19 18:26:06 +02:00
char resultString [ 200 ] ;
String JsonData = " " ;
2021-01-20 21:27:05 +02:00
2021-01-19 18:26:06 +02:00
serializeJson ( doc , JsonData ) ;
2021-02-25 16:22:57 +02:00
////Serial.println(JsonData); //Вывод JSON строки в консоль
JsonData . toCharArray ( resultString , JsonData . length ( ) + 1 ) ;
2021-01-19 18:26:06 +02:00
if ( mqttSendFlag = = true )
{
2021-02-25 16:22:57 +02:00
MqttClient . publish ( bufTopic , resultString , true ) ;
////Serial.println("SentToTopic - ok");
errorID = 0 ;
2021-01-19 18:26:06 +02:00
}
}
2021-01-21 17:54:46 +02:00
//Переподключение при петери связи с MQTT
//10 раз проверили и вернулись в общий цикл что бы вдруг что втянуть обновления
2021-01-19 18:26:06 +02:00
void reconnectMqtt ( )
{
2021-01-20 21:27:05 +02:00
byte circle = 0 ;
while ( ! MqttClient . connected ( ) )
2021-01-19 18:26:06 +02:00
{
2021-02-24 15:20:49 +02:00
////Serial.print("MQTT reconnect...");
2021-01-20 21:27:05 +02:00
circle + + ;
2021-02-25 16:22:57 +02:00
if ( circle = = 5 )
2021-01-20 21:27:05 +02:00
{
break ;
2021-02-25 16:22:57 +02:00
}
2021-01-20 21:27:05 +02:00
2021-02-25 16:22:57 +02:00
String maccrandom = macc + String ( random ( 0xffff ) , HEX ) ;
const char * clientId = maccrandom . c_str ( ) ;
2021-01-20 21:27:05 +02:00
2021-02-25 16:22:57 +02:00
//const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage
////Serial.println(clientId);
2021-02-24 15:20:49 +02:00
2021-02-25 16:22:57 +02:00
if ( MqttClient . connect ( clientId , bufWillTopic , 2 , true , " OFFLINE " ) )
{
2021-02-24 15:20:49 +02:00
2021-02-25 16:22:57 +02:00
MqttClient . publish ( bufTopic , " CONNECT " , true ) ;
MqttClient . publish ( bufWillTopic , " ONLINE " , true ) ;
2021-02-09 20:29:13 +02:00
2021-02-25 16:22:57 +02:00
////Serial.println("MqttClient.connect() - OK");
2021-02-24 15:20:49 +02:00
errorID = 8 ;
2021-02-25 16:22:57 +02:00
//client.subscribe("inTopic");
2021-01-20 21:27:05 +02:00
mqttSendFlag = true ;
}
else
{
2021-02-25 16:22:57 +02:00
////Serial.print("MqttClient.state() = ");
////Serial.println(MqttClient.state());
/*
2021-02-24 15:20:49 +02:00
- 4 : MQTT_CONNECTION_TIMEOUT - the server didn ' t respond within the keepalive time
- 3 : MQTT_CONNECTION_LOST - the network connection was broken
- 2 : MQTT_CONNECT_FAILED - the network connection failed
- 1 : MQTT_DISCONNECTED - the client is disconnected cleanly
0 : MQTT_CONNECTED - the client is connected
1 : MQTT_CONNECT_BAD_PROTOCOL - the server doesn ' t support the requested version of MQTT
2 : MQTT_CONNECT_BAD_CLIENT_ID - the server rejected the client identifier
3 : MQTT_CONNECT_UNAVAILABLE - the server was unable to accept the connection
4 : MQTT_CONNECT_BAD_CREDENTIALS - the username / password were rejected
5 : MQTT_CONNECT_UNAUTHORIZED - the client was not authorized to connect
*/
2021-01-20 21:27:05 +02:00
mqttSendFlag = false ;
2021-02-25 16:22:57 +02:00
delay ( 3000 ) ;
2021-01-20 21:27:05 +02:00
}
2021-01-19 18:26:06 +02:00
}
}
2021-01-14 23:27:49 +02:00
void loop ( )
{
//Проверка старта сервера
2021-01-19 18:26:06 +02:00
M5 . update ( ) ;
2021-01-20 21:27:05 +02:00
//Если не определен IP то и не будет отправки.
2021-01-19 18:26:06 +02:00
// 40 секунд и происходит с б р о с настроек WIFI
if ( M5 . Btn . wasReleasefor ( 40000 ) )
{
ledset ( ' r ' , true ) ;
checkButton ( ) ;
2021-02-25 16:22:57 +02:00
}
2021-01-19 18:26:06 +02:00
2021-01-21 17:54:46 +02:00
//По таймеру запруск обновления прошивки
2021-01-14 23:27:49 +02:00
if ( millis ( ) - timingUpdate > nextM5Update )
{
2021-01-20 21:27:05 +02:00
reqNtpTime ( ) ;
2021-01-14 23:27:49 +02:00
OTAUpdate ( ) ;
2021-02-25 16:22:57 +02:00
// ////////Serial.print("OTAUpdate() - ");
// ////////Serial.println(millis());
2021-01-14 23:27:49 +02:00
timingUpdate = millis ( ) ;
}
2021-01-19 18:26:06 +02:00
2021-01-21 17:54:46 +02:00
//Таймер запроса данных с датчиков
2021-01-19 18:26:06 +02:00
if ( millis ( ) - timingReqSensor > nextReqSensor )
{
reqSensorData ( ) ;
2021-02-09 20:29:13 +02:00
ledset ( ' b ' , true ) ;
2021-02-25 16:22:57 +02:00
// ////////Serial.print("reqSensorData() - ");
// ////////Serial.println(millis());
2021-01-19 18:26:06 +02:00
timingReqSensor = millis ( ) ;
}
2021-01-21 17:54:46 +02:00
//Таймер отправки данных в брокер
2021-01-19 18:26:06 +02:00
if ( millis ( ) - timingSendMqtt > nextMqttSend )
{
SendMqttReq ( ) ;
2021-02-09 20:29:13 +02:00
ledset ( ' g ' , true ) ;
2021-01-19 18:26:06 +02:00
timingSendMqtt = millis ( ) ;
}
2021-01-20 21:27:05 +02:00
2021-02-09 20:29:13 +02:00
//Тут же проверка подключения к MQTT
2021-01-20 21:27:05 +02:00
if ( ! MqttClient . connected ( ) )
{
reconnectMqtt ( ) ;
2021-02-09 20:29:13 +02:00
ledset ( ' w ' , true ) ;
2021-01-20 21:27:05 +02:00
}
2021-02-09 20:29:13 +02:00
2021-02-25 16:22:57 +02:00
// ////////Serial.println("=============");
2021-02-09 20:29:13 +02:00
// rssi = WiFi.RSSI();
2021-02-25 16:22:57 +02:00
// ////////Serial.println(rssi);
// ////////Serial.println("=============");
2021-02-09 20:29:13 +02:00
2021-01-20 21:27:05 +02:00
MqttClient . loop ( ) ;
2021-01-19 18:26:06 +02:00
}
2021-02-24 15:20:49 +02:00
int disconnectMQTT ( )
2021-02-25 16:22:57 +02:00
{
MqttClient . publish ( bufTopic , " DISCONNECTED " , true ) ;
2021-02-24 15:20:49 +02:00
MqttClient . disconnect ( ) ;
return 0 ;
2021-02-25 16:22:57 +02:00
}