Описание и комментарий в коде

master
smartUA 2021-01-21 17:54:46 +02:00
parent 7d9f8d01d2
commit 793656049c
5 changed files with 130 additions and 94 deletions

View File

@ -12,28 +12,28 @@
#include <Preferences.h> //Сохранение настроек хеша прошивки
#include <HTTPClient.h>
#include <ESP32httpUpdate.h>
#include "M5Atom.h"
#include <ESP32httpUpdate.h> //Библиотека ОТА обновлений
#include "M5Atom.h" //Библиотека атома для функции Led и Кнопки, можно упразднить и убрать
#include <Ticker.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <TimeLib.h>
#include <Wire.h>
#include "ClosedCube_HDC1080.h"
#include "Adafruit_CCS811.h" //The device's I2C address is 0x5A
#include <Ticker.h> //Библиотека таймера для Led
#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>
#include <ArduinoJson.h>
#include <PubSubClient.h> //Mtqq
#include <ArduinoJson.h> //Упакова в JSon - удобная библиотека
//Наша кнопочка при нажатии на которую произойдет вызов wifi менеджера и перезагрузка в станцию
#define TRIGGER_PIN 39
unsigned int VersionSW=14; //65536
unsigned int VersionSW = 14; //65536 Версия прошивки
WiFiManager wm; // обьект менеджера
WiFiManagerParameter custom_field;
Preferences OTApreferences;
Preferences OTApreferences; //Обьект хранения настроек хеша прошивки
Ticker RGBWTicker;
Adafruit_CCS811 ccs;
@ -46,38 +46,39 @@ PubSubClient MqttClient(espClient);
IPAddress IpMqtt;
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "0.ua.pool.ntp.org", 7200, 60000);
NTPClient timeClient(ntpUDP, "0.ua.pool.ntp.org", 7200, 60000); //Собственно сервер времени смещение и частоат запроса, но он вручную
const PROGMEM char *mqttHostName = "cctv.automation.art";
unsigned int mqttPort = 8889;
const PROGMEM char *topicName = "/aastudio"; // +mac адресс девайса
const PROGMEM char *mqttLogin = "login",
const PROGMEM char *mqttHostName = "cctv.automation.art"; //Хостнейм брокера
unsigned int mqttPort = 8889; //Порт брокера
const PROGMEM char *topicName = "/aastudio"; // +mac адресс девайса Префикс топика
const PROGMEM char *mqttLogin = "login", //Логин пароль - необходимо сменить код при connect()
*mqttPass = "password";
const char *mqttIPHost;
const char *mqttIPHost; //тут хранится IP хоста по хостнейму
unsigned long timingUpdate, timingReqSensor, timingSendMqtt;
unsigned long timingUpdate, timingReqSensor, timingSendMqtt; //Таймеры для millis()
int PROGMEM nextM5Update = 450000; //каждые 7.5 минут запрос обновления с сервера
int PROGMEM nextReqSensor = 10000; //опрос датчиков раз в 10 секунд
int PROGMEM nextMqttSend = 60000;
int PROGMEM nextMqttSend = 60000; //Отправка
//Поправочные коефициенты
//Поправочные коефициенты для датчиков
//[24A160474D14, 5002919F5450, 5002918A38CC]
//tcoeff[0,1,2]
//hcoeff[0,1,2]
float PROGMEM tcoeff[3] = {-11.18, -9.62, -10.6};
float PROGMEM hcoeff[3] = {13.77, 14.07, 15.56};
float PROGMEM tcoeff[3] = {-11.18, -9.62, -10.6}; //Температура
float PROGMEM hcoeff[3] = {13.77, 14.07, 15.56}; //Влажность
float callibrationT = 0, callibrationH = 0;
String macc = "";
String macc = ""; //Глобальное хранение мас адреса
float TempAv, HumAv, Eco2Av, TvocAv;
//Кусок кода поправить - так делать нельзя
#define NUM_AVER 5
float averageT; // перем. среднего
float valArrayT[NUM_AVER]; // массив
byte idxT = 0;
float averageH; // перем. среднего
float averageH; // перем. среднего
float valArrayH[NUM_AVER]; // массив
byte idxH = 0;
@ -96,21 +97,24 @@ bool mqttSendFlag = false;
int reqCounter = 0;
bool flagblink = true;
//Настройки
void setup()
{
M5.begin(true, false, true);
delay(50);
Wire.begin(25, 21);
Wire.begin(25, 21); //Пины для I2c на ATOM
pinMode(23, OUTPUT);
pinMode(23, OUTPUT); //Пин датчика для работы
digitalWrite(23, LOW);
WiFi.mode(WIFI_STA);
Serial.begin(115200);
Serial.setDebugOutput(true);
delay(3000);
Serial.println("\n Starting station");
pinMode(TRIGGER_PIN, INPUT);
pinMode(TRIGGER_PIN, INPUT);
// wm.resetSettings(); // wipe settings
// add a custom input field
int customFieldLength = 40;
@ -147,7 +151,7 @@ void setup()
bool res;
// res = wm.autoConnect(); // auto generated AP name from chipid
// res = wm.autoConnect("AutoConnectAP"); // anonymous ap
res = wm.autoConnect("AutoConnectAP", "password"); // password protected ap
res = wm.autoConnect("AutoConnectAP", "password"); // Подключение к анонимной точке доступа
if (!res)
{
Serial.println("Failed to connect or hit timeout");
@ -155,7 +159,6 @@ void setup()
}
else
{
//if you get here you have connected to the WiFi
Serial.println("connected...");
}
@ -176,9 +179,10 @@ void setup()
reqNtpTime();
}
//Установка сервера и порта
void setMqttServer()
{
Serial.println("gethostbyname: ");
{
Serial.println("Gethostbyname: ");
int err = WiFi.hostByName(mqttHostName, IpMqtt);
if (err == 1)
{
@ -197,6 +201,7 @@ void setMqttServer()
}
}
//Функция получения данных из MQTT если мы подпишемся на топики
void callback(char *topic, byte *payload, unsigned int length)
{
Serial.print("Message arrived [");
@ -209,33 +214,32 @@ void callback(char *topic, byte *payload, unsigned int length)
Serial.println();
}
//Запрос времени NTP и установка локлаьного времени
void reqNtpTime()
{
timeClient.update();
setTime(timeClient.getEpochTime());
// Serial.println(timeClient.getEpochTime());
// Serial.println("<=ntp====now=>");
time_t t = now();
//time_t t = now();
// Serial.println(t);
}
//Нажатие кнопки для сброса
void checkButton()
{
Serial.println("Button Pressed");
// delay(3000);
// if (digitalRead(TRIGGER_PIN) == LOW) {
Serial.println("Button Held");
Serial.println("Erasing Config, restarting");
wm.resetSettings();
ESP.restart();
// }
// delay(3000);
// if (digitalRead(TRIGGER_PIN) == LOW) {
Serial.println("Erasing Config, restarting");
wm.resetSettings();
ESP.restart();
// }
// start portal w delay
Serial.println("Starting config portal");
wm.setConfigPortalTimeout(120);
if (!wm.startConfigPortal("AirQaPortal", "12345678"))
if (!wm.startConfigPortal("AirQaPortal", "12345678")) //Логин и пароль точки доступа
{
Serial.println("failed to connect or hit timeout");
delay(3000);
@ -257,17 +261,18 @@ String getParam(String name)
return value;
}
void saveParamCallback()
{
Serial.println("[CALLBACK] saveParamCallback fired");
Serial.println("PARAM customfieldid = " + getParam("customfieldid"));
}
//Обновление прошивки, происходит проверка и загрузка
//Делается Get запрос на хостинг проверяется хеш, если хеш
void OTAUpdate()
{
Serial.println("OTAUpdate()");
//http://meteosence.s-host.net/meteosence.php?meteopas=PdF4apD4i95xR5&meteodata=gethash
bool flagOTA = false;
String keyOTA;
String payload;
@ -275,10 +280,10 @@ void OTAUpdate()
OTApreferences.begin("ota-config");
if (WiFi.status() == WL_CONNECTED)
{
{
HTTPClient http;
String getMacNow=getMacAddress();
String serverPath = "http://meteosence.s-host.net/airqa/airquality.php?meteopas=e93gme9hAt9nSWaV&meteodata=gethash&mac="+getMacNow+"";
String getMacNow = getMacAddress();
String serverPath = "http://meteosence.s-host.net/airqa/airquality.php?meteopas=e93gme9hAt9nSWaV&mac=" + getMacNow + "&meteodata=gethash";
http.begin(serverPath.c_str());
int httpResponseCode = http.GET();
@ -293,7 +298,7 @@ void OTAUpdate()
if (keyOTA.length() <= 0)
{
OTApreferences.putString("md5HashOTA", "undifined");
OTApreferences.putString("md5HashOTA", "undifined");
}
keyOTA = OTApreferences.getString("md5HashOTA");
@ -324,6 +329,9 @@ void OTAUpdate()
Serial.println("flagOTA = false;");
t_httpUpdate_return ret = ESPhttpUpdate.update("http://meteosence.s-host.net/airqa/airatoms.bin");
//После update ничего не происходит, такая вот особенность.
//Если все прошло хорошо, перезагрузка на новую прошивку
Serial.print("ret ");
Serial.println(ret);
@ -355,6 +363,7 @@ void OTAUpdate()
OTApreferences.end();
}
//Функция для индикации Led
void ledset(char color, bool blink = false)
{
switch (color)
@ -401,6 +410,7 @@ void ledBlinkTimer()
}
}
//Получение мак адреса
String getMacAddress()
{
uint8_t baseMac[6];
@ -410,6 +420,7 @@ String getMacAddress()
return String(baseMacChr);
}
//Установка коефициентов калибровки
void SetCallibrationCoeff()
{
@ -440,6 +451,8 @@ void SetCallibrationCoeff()
}
}
//Ниже отдельные функции средних арифметических для каждого параместра с историей
float middleArifmT(float newVal)
{
// Serial.print(newVal);
@ -507,6 +520,7 @@ float middleArifmTVOC(float newVal)
return averageTVOC; // возвращаем
}
//Запрос данных с датчиков.
void reqSensorData()
{
float hdc1080Temp = 0, hdc1080Hum = 0;
@ -543,45 +557,40 @@ void reqSensorData()
TvocAv = middleArifmTVOC(tvoc);
}
//Отправка данных по MQTT
void SendMqttReq()
{
Serial.println("Data in SendMqttReq()");
Serial.print(TempAv);
Serial.print(TempAv);
Serial.print(" ");
Serial.print(HumAv);
Serial.print(HumAv);
Serial.print(" ");
Serial.print(Eco2Av);
Serial.print(Eco2Av);
Serial.print(" ");
Serial.println(TvocAv);
Serial.println(TvocAv);
char HumidityInt[8], TemperatureInt[8];
char HumidityInt[8], TemperatureInt[8];
dtostrf(TempAv * 100, 4, 0, TemperatureInt);
dtostrf(HumAv * 100, 4, 0, HumidityInt);
dtostrf(TempAv * 100, 4, 0, TemperatureInt);
dtostrf(HumAv * 100, 4, 0, HumidityInt);
doc["mac"] = String(getMacAddress());
doc["swver"] = VersionSW;
doc["t"] = atoi(TemperatureInt);
doc["h"] = atoi(HumidityInt);
doc["eco"] = (int)Eco2Av;
doc["tvoc"] = (int)TvocAv;
doc["time"] = now();
doc["mac"] = String(getMacAddress());
doc["swver"] = VersionSW;
doc["t"] = atoi(TemperatureInt);
doc["h"] = atoi(HumidityInt);
doc["eco"] = (int)Eco2Av;
doc["tvoc"] = (int)TvocAv;
doc["time"] = now();
char resultString[200];
String JsonData = "";
serializeJson(doc, JsonData);
Serial.println(JsonData); //Вывод JSON строки в консоль
JsonData.toCharArray(resultString, JsonData.length() + 1);
String finishTopic = "";
finishTopic = String(topicName) + "/" + macc;
//Serial.println(finishTopic);
if (mqttSendFlag == true)
{
MqttClient.publish(finishTopic.c_str(), resultString);
@ -589,6 +598,8 @@ void SendMqttReq()
}
}
//Переподключение при петери связи с MQTT
//10 раз проверили и вернулись в общий цикл что бы вдруг что втянуть обновления
void reconnectMqtt()
{
@ -634,15 +645,14 @@ void loop()
M5.update();
//Если не определен IP то и не будет отправки.
// 40 секунд и происходит сброс настроек WIFI
if (M5.Btn.wasReleasefor(40000))
{
ledset('r', true);
checkButton();
}
//По таймеру запруск обновления - проверка хеша прошивки на сервере
//По таймеру запруск обновления прошивки
if (millis() - timingUpdate > nextM5Update)
{
reqNtpTime();
@ -652,6 +662,7 @@ void loop()
timingUpdate = millis();
}
//Таймер запроса данных с датчиков
if (millis() - timingReqSensor > nextReqSensor)
{
reqSensorData();
@ -662,12 +673,14 @@ void loop()
timingReqSensor = millis();
}
//Таймер отправки данных в брокер
if (millis() - timingSendMqtt > nextMqttSend)
{
SendMqttReq();
timingSendMqtt = millis();
}
//Тут же проверка подключения к MQTT
if (!MqttClient.connected())
{
reconnectMqtt();

View File

@ -1,32 +1,55 @@
# M5Atom_airqa
<br/>
1. Настройка Wifi <br/>
2. Проверка Ота обновлений по таймеру с сервера<br/>
3. Получение данных с датчиков формируем в Json<br/>
4. Отправляем в mqtt по хостнейму<br/>
5. Индикация Led<br/>
5.1 Прикрутить реле к одному из девайсов 3А 220В<br/>
6. На будущее забить функцию для IR управления - по времени<br/>
1. Подключить питание в USB<br/>
2. Зажать кнопку сверху на 40 секунд (не боковую. Боковая кнопка - это рестарт)<br/>
3. Начнет мигать зеленый светодиод<br/>
4. Зайти в телефона в точку доступа "AirQaPortal" c паролем "12345678"<br/>
5. Выбрать нужную Wifi точку и ввести пароль. Нажать сохранить<br/>
6. После перезагрузки устройство подключится к точке доступа и начнется отправка информации в топики<br/>
7. Если данные в топики не побежали то это значит что у провайдера нет кольцевого проброса запросов из локальной сети по внешнему ip внутрь этой сети - починим другим способом.<br/>
8. Отправка данных в топики 1 раз в минуту<br/>
9. Запрос обновления прошивки раз в 7 минут<br/>
10. Можно взять данные из COM порта через ttylog -b 115200 -d /dev/ttyACM*<br/>
11. Датчик необходимо установить на не холодной (не внешней) стене, на высоте от 1.5 до 1.8 <br/>метра, от дверей и проходов не менее 30 см. Не устанавливать напротив солнечных окон, не <br/>устанавливать над обогревающими или под охлаждающими приборами.<br/>
<br/><br/>
17:31:54.570 -> HDC1080 Configuration Register
17:31:54.615 -> ------------------------------
17:31:54.615 -> Software reset bit: 0 (0=Normal Operation, 1=Software Reset)
17:31:54.705 -> Heater: 0 (0=Disabled, 1=Enabled)
17:31:54.750 -> Mode of Acquisition: 0 (0=T or RH is acquired, 1=T and RH are acquired in sequence, T first)
17:31:54.841 -> Battery Status: 0 (0=Battery voltage > 2.8V, 1=Battery voltage < 2.8V)
17:31:54.930 -> T Measurement Resolution: 0 (0=14 bit, 1=11 bit)
17:31:54.975 -> RH Measurement Resolution: 0 (00=14 bit, 01=11 bit, 10=8 bit)
17:31:54.570 -> HDC1080 Configuration Register<br/>
17:31:54.615 -> ------------------------------<br/>
17:31:54.615 -> Software reset bit: 0 (0=Normal Operation, 1=Software Reset)<br/>
17:31:54.705 -> Heater: 0 (0=Disabled, 1=Enabled)<br/>
17:31:54.750 -> Mode of Acquisition: 0 (0=T or RH is acquired, 1=T and RH are acquired in sequence, T first)<br/>
17:31:54.841 -> Battery Status: 0 (0=Battery voltage > 2.8V, 1=Battery voltage < 2.8V)<br/>
17:31:54.930 -> T Measurement Resolution: 0 (0=14 bit, 1=11 bit)<br/>
17:31:54.975 -> RH Measurement Resolution: 0 (00=14 bit, 01=11 bit, 10=8 bit)<br/>
<br/><br/>
Если устройство находится в рекомендуемом рабочем диапазоне (относительная влажность от 10% до 70% и температура от -20 до 70 ° C), то не нужно часто калибровать (длительный дрейф составляет ± 0,25% относительной влажности / год). Датчик CCS811 не может измерять концентрацию СО2 непосредственно и выдает рассчитанные "эквивалентные" значения СО2, которые при высокой концентрации ЛОВ оказываются сильно завышенными.
Датчики настроены на точность 14 бит.
<br/><br/>
Характеристики HDC1080:<br/>
• Робоча температура: -20 ° C ~ 70 ° C<br/>
• Діапазон вимірювання датчика вологості: 0 ~ 100% RH<br/>
• Точність датчика вологості: похибка 14 біт ± 2% відносної вологості<br/>
• Точність повторюваності вологості: ± 0.1% RH<br/>
• Час відгуку датчика вологості: 15с<br/>
• Час вимірювання вологості: 8 біт 2,5 мс, 11 біт 3,85 мс, 14 біт 6,5 ms<br/>
• Точність датчика температури: ± 0,4 ° C (температура навколишнього середовища Температура 5 ° C ~ 60 ° C)<br/>
• Повторюваність вимірювання температури: ± 0,1 ° C<br/>
• Час вимірювання температури: 11 біт 3,85 мс, 14 біт 6,5 мс<br/>
• Напруга живлення: рекомендується 3,3 В<br/>
Характеристики CCS811:<br/>
• Напруга живлення: рекомендується 3,3 V<br/>
• Робоча частота інтерфейсу I2C: 400 кГц<br/>
• Діапазон виявлення eTVOC: 0 ~ 32768ppb<br/>
• Діапазон виявлення eCO2: 400 ~ 32768ppm<br/>
• Автоматичний час корекції вихідних умов для чутливого шару оксиду металу: 24 години<br/>
• Можливість налаштування і зчитування часу датчика після включення: не менше 20 хвилин<br/>
Если устройство находится в рекомендуемом рабочем диапазоне (относительная влажность от 10% до 70% и температура от -20 до 70 ° C), вашему заказчику не нужно часто калибровать его (длительный дрейф составляет ± 0,25% относительной влажности / год).
датчик CCS811 не может измерять концентрацию СО2 непосредственно и выдает рассчитанные "эквивалентные" значения СО2, которые при высокой концентрации ЛОВ оказываются сильно завышенными.
<br/><br/>
Информация для датчика 1080 https://www.terraelectronica.ru/news/5287

BIN
pdf/Описание.docx Normal file

Binary file not shown.