AAOffice_vent/tenzo/tenzosensor/src/main.cpp

578 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
#include <Preferences.h> //Сохранение настроек хеша прошивки
#include <HTTPClient.h>
#include <ESP32httpUpdate.h> //Библиотека ОТА обновлений
#include "M5Atom.h" //Библиотека атома для функции Led и Кнопки, можно упразднить и убрать
#include <WiFiUdp.h> //Udp клиент
#include <NTPClient.h> //NTP запрос времени
#include <TimeLib.h> //Внутреннее время
#include <Wire.h> //Библиотека дял I2C
#include <PubSubClient.h> //Mtqq
#include <ArduinoJson.h> //Упакова в JSon - удобная библиотека
#include <ESPmDNS.h>
#include <Q2HX711.h>
// aastudio/act/24A16053B7C4/data/0
#define BPin 21
#define APin 25
const byte hx711_data_pin = 26;
const byte hx711_clock_pin = 32;
#define TRIGGER_PIN 39
unsigned int VersionSW = 5;
Q2HX711 hx711(hx711_data_pin, hx711_clock_pin);
//3 - Первый код для тензо
WiFiManager wm; // обьект менеджера
Preferences OTApreferences; //Обьект хранения настроек хеша прошивки
String JsonData;
StaticJsonDocument<200> doc, docResult;
WiFiClient espClient;
PubSubClient MqttClient(espClient);
IPAddress IpMqtt;
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "192.168.89.210", 0, 20000); //Собственно сервер времени смещение и частоат запроса, но он вручную
const PROGMEM char *willmess = "{\"conn\":\"err\"}";
const char *mqttHostName = "metrics"; //Хостнейм брокера metrics.local cctv.automation.art //192.168.89.210
unsigned int mqttPort = 1883; //Порт брокера 1883 8889
String getMacAddress();
String macc = getMacAddress();
String topicTemp = "aastudio/act/" + macc + "/data/0";
String setTopic = "aastudio/act/" + macc + "/set/0";
String willTopicTemp = "aastudio/act/" + macc + "/status";
const PROGMEM char *mqttLogin = "AA_Lab", *mqttPass = "automation.art$";
byte setPercent = 0, setSpeedAnemo = 0;
int stateResistor = 0;
const char *mqttIPHost; //тут хранится IP хоста по хостнейму
unsigned long timingUpdate = 0, timingReqSensor = 0, timingSendMqtt = 0; //Таймеры для millis()
int PROGMEM nextM5Update = 450000, nextMqttSend = 5000; //каждые 7.5 минут запрос обновления с сервера
bool mqttSendFlag = false;
int reqCounter = 0;
long rssi = 0, minRes=1480, maxRes=2600;
char bufTopic[140], bufWillTopic[150], bufSetTopic[150];
int moveAnemo(byte percent);
int setMotor(bool Finput, int Binput);
//void callback(char *topic, byte *payload, unsigned int length);
int disconnectMQTT();
int SendMqttReq(bool sendVal, bool sendStatus, byte statusConn);
const int NUM_READ = 16; // количество усреднений для средних арифм. фильтров
float expRunningAverageAdaptive(float newVal) {
static int t = 0;
static int vals[NUM_READ];
static int average = 0;
if (++t >= NUM_READ) t = 0; // перемотка t
average -= vals[t]; // вычитаем старое
average += newVal; // прибавляем новое
vals[t] = newVal; // запоминаем в массив
return ((float)average / NUM_READ);
}
void ledset(byte color = 0)
{
M5.dis.setBrightness(60); //Половина яркости
switch (color)
{
case 2:
M5.dis.drawpix(0, 0xf00000); //Зеленый
break;
case 1:
M5.dis.drawpix(0, 0x00ff00); //Красный
break;
case 3:
M5.dis.drawpix(0, 0x0000ff); //Синий
break;
case 4:
M5.dis.drawpix(0, 0xffffff); //Белый
break;
case 5:
M5.dis.drawpix(0, 0xffec00); //желтый
break;
default:
M5.dis.clear();
break;
}
}
//Настройки
int getIpBlock(int index, String str)
{
char separator = '.';
int found = 0;
int strIndex[] = {0, -1};
int maxIndex = str.length() - 1;
for (int i = 0; i <= maxIndex && found <= index; i++)
{
if (str.charAt(i) == separator || i == maxIndex)
{
found++;
strIndex[0] = strIndex[1] + 1;
strIndex[1] = (i == maxIndex) ? i + 1 : i;
}
}
return found > index ? str.substring(strIndex[0], strIndex[1]).toInt() : 0;
}
IPAddress str2IP(String str)
{
IPAddress ret(getIpBlock(0, str), getIpBlock(1, str), getIpBlock(2, str), getIpBlock(3, str));
return ret;
}
int setMqttServer(const char *mqttHostNameF, unsigned int mqttPortF)
{
mdns_init();
IPAddress ipaddr;
OTApreferences.begin("ota-config");
OTApreferences.putString("mqttip", "0");
delay(1000);
String keyIpMqtt = OTApreferences.getString("mqttip", "0");
Serial.print("keyIpMqtt: ");
Serial.println(keyIpMqtt);
if (keyIpMqtt == "0")
{
//Запрос по хостнейму .local
ipaddr = MDNS.queryHost(mqttHostNameF, 4000);
//Таймаут 4 секунды
//Если не получили по хостнейму МДНС
Serial.print("mdns: ");
Serial.println(ipaddr);
if (ipaddr.toString() == "0.0.0.0")
{
//Запрос к ДНС по адресу сайта
int err = WiFi.hostByName(mqttHostNameF, ipaddr);
////real internal timeout in lwip library is 14[s]
//Если получили по хостнейму
if (err == 1)
{
Serial.print("hostByName: ");
Serial.println(ipaddr);
MqttClient.setServer(ipaddr, mqttPortF);
OTApreferences.putString("mqttip", ipaddr.toString());
}
else
{
Serial.print("All method not FOUND IP");
}
}
else
{ //Если все хорошо
OTApreferences.putString("mqttip", ipaddr.toString());
MqttClient.setServer(ipaddr, mqttPortF);
}
}
else
{
MqttClient.setServer(str2IP(keyIpMqtt), mqttPortF);
}
//MqttClient.setCallback(callback);
OTApreferences.end();
return 0;
}
//Запрос времени NTP и установка локлаьного времени
int reqNtpTime()
{
if (timeClient.update())
{
uint32_t timeEpoch = timeClient.getEpochTime();
if (timeEpoch < 1600000000)
{
Serial.println("Error reqNtpTime() Time");
return 1;
}
setTime(timeEpoch);
// Serial.print(timeEpoch);
// Serial.print(" <=ntp== ==device=> ");
// Serial.println(now());
}
return 0;
}
// //{"percent":50,"speed":20}
// void callback(char *topic, byte *payload, unsigned int length)
// {
// Serial.print("Message arrived [");
// Serial.print(topic);
// Serial.print("] ");
// char jsonResult[250];
// for (int i = 0; i < length; i++)
// {
// Serial.print((char)payload[i]);
// jsonResult[i] = (char)payload[i];
// }
// DeserializationError error = deserializeJson(docResult, jsonResult);
// if (error)
// {
// Serial.print(F("deserializeJson() failed: "));
// return;
// }
// setPercent = (byte)docResult["amount"]; //0-100
// // setSpeedAnemo = (byte)docResult["speed"]; //speed
// }
//Нажатие кнопки для сброса
void checkButton()
{
Serial.println("Button RESET Pressed");
disconnectMQTT();
delay(100);
OTApreferences.begin("ota-config");
OTApreferences.putString("mqttip", "0");
OTApreferences.end();
wm.resetSettings();
ESP.restart();
}
//Обновление прошивки, происходит проверка и загрузка
//Делается Get запрос на хостинг проверяется хеш, если хеш
void OTAUpdate()
{
////Serial.\println("OTAUpdate()");
bool flagOTA = false;
String keyOTA;
String payload;
OTApreferences.begin("ota-config");
if (WiFi.status() == WL_CONNECTED)
{
HTTPClient http;
String serverPath = "http://meteosence.s-host.net/airqa/airquality.php?meteopas=sdsfsd45540dfdfsksfl45&mac = " + macc + " &meteodata = gethash";
http.begin(serverPath.c_str());
int httpResponseCode = http.GET();
if (httpResponseCode > 0)
{
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
payload = http.getString();
Serial.println(payload);
if (payload != "errno" || payload != "errfi")
{
keyOTA = OTApreferences.getString("md5HashOTA");
if (keyOTA.length() <= 0)
{
OTApreferences.putString("md5HashOTA", "undifined");
}
keyOTA = OTApreferences.getString("md5HashOTA");
if (payload != keyOTA)
{
flagOTA = true;
OTApreferences.putString("md5HashOTA", payload);
//Serial.println("flagOTA = true;");
}
}
}
else
{
Serial.print("Error code HTTP: ");
Serial.println(httpResponseCode);
}
// Free resources
http.end();
}
else
{
Serial.println("WiFi Disconnected");
}
if (flagOTA == true)
{
flagOTA = false;
//Serial.println("flagOTA = false;");
t_httpUpdate_return ret = ESPhttpUpdate.update("http://meteosence.s-host.net/airqa/tenzo/tenzo.bin");
//После update ничего не происходит, такая вот особенность.
//Если все прошло хорошо, перезагрузка на новую прошивку
//Serial.print("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");
ESP.restart();
break;
case HTTP_UPDATE_NO_UPDATES:
//Serial.println("HTTP_UPDATE_NO_UPDATES");
ESP.restart();
break;
case HTTP_UPDATE_OK:
//Serial.println("HTTP_UPDATE_OK");
ESP.restart();
break;
}
}
OTApreferences.end();
}
//Получение мак адреса
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);
}
//Отправка данных по MQTT
int SendMqttReq(bool sendVal = true, bool sendStatus = true, byte statusConn = 1)
{
if (mqttSendFlag == true)
{
char resultString[200];
String JsonData = "";
rssi = WiFi.RSSI();
unsigned long timeNow = now();
doc["filter"] = digitalRead(BPin);
doc["preassure"] = expRunningAverageAdaptive((hx711.read()/1000));
doc["ts"] = timeNow;
serializeJson(doc, JsonData);
doc.remove("ts");
doc.remove("preassure");
doc.remove("filter");
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;
case 4:
conn = "upd";
break;
default:
break;
}
doc["conn"] = conn;
doc["rssi"] = rssi;
doc["bsid"] = WiFi.BSSIDstr();
doc["ts"] = timeNow;
doc["exp"] = timeNow + 20000;
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
//7 раз проверили и вернулись в общий цикл что бы вдруг что втянуть обновления
void reconnectMqtt()
{
byte circle = 0;
while (!MqttClient.connected())
{
circle++;
if (circle == 5)
{
break;
}
String maccrandom = macc + String(random(0xffff), HEX);
const char *clientId = maccrandom.c_str();
if (MqttClient.connect(clientId, mqttLogin, mqttPass, bufWillTopic, 2, true, willmess))
{
Serial.println("Mqttconnect - OK");
mqttSendFlag = true;
// MqttClient.subscribe(bufSetTopic);
SendMqttReq(false, true, 1);
}
else
{
Serial.print("Mqtt.state() = ");
Serial.println(MqttClient.state());
/*
-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
*/
mqttSendFlag = false;
delay(500);
}
}
}
void setup()
{
Serial.begin(115200);
Serial.setDebugOutput(true);
M5.begin(true, false, true);
pinMode(APin, OUTPUT);
pinMode(BPin, INPUT);
digitalWrite(APin, HIGH);
delay(50);
pinMode(TRIGGER_PIN, INPUT);
WiFi.mode(WIFI_STA);
delay(100);
Serial.println(setTopic);
Serial.println(topicTemp);
Serial.println(willTopicTemp);
setTopic.toCharArray(bufSetTopic, setTopic.length() + 1);
topicTemp.toCharArray(bufTopic, topicTemp.length() + 1);
willTopicTemp.toCharArray(bufWillTopic, willTopicTemp.length() + 1);
// wm.resetSettings(); // wipe settings
std::vector<const char *> menu = {"wifi", "info", "param", "sep", "restart", "exit"};
wm.setMenu(menu);
// set dark theme
wm.setClass("invert");
wm.setConfigPortalTimeout(30); // auto close configportal after n seconds
wm.setMinimumSignalQuality(10); // set min RSSI (percentage) to show in scans, null = 8%
wm.setScanDispPerc(true); // show RSSI as percentage not graph icons
wm.setWiFiAutoReconnect(true); // if true, enable autoreconnecting
bool res;
res = wm.autoConnect("TensoM5Portal", "12345678"); // Подключение к анонимной точке доступа
if (!res)
{
Serial.println("Failed to connect or hit timeout");
ESP.restart();
}
if (reqNtpTime() == 1)
{
reqNtpTime();
}
setMqttServer(mqttHostName, mqttPort);
}
void loop()
{
M5.update();
if (WiFi.status() != WL_CONNECTED)
{
Serial.println(WiFi.status());
ESP.restart();
}
if (!MqttClient.connected())
{
reconnectMqtt();
}
if (millis() - timingSendMqtt > nextMqttSend)
{
SendMqttReq(true,true,1);
timingSendMqtt = millis();
}
// 40 секунд и происходит сброс настроек WIFI
if (M5.Btn.wasReleasefor(40000))
{
checkButton();
}
//По таймеру запруск обновления прошивки
if (millis() - timingUpdate > nextM5Update)
{
reqNtpTime();
SendMqttReq(false, true, 4);
OTAUpdate();
SendMqttReq(false, true, 1);
timingUpdate = millis();
}
//Таймер отправки данных в брокер
MqttClient.loop();
}
int disconnectMQTT()
{
MqttClient.disconnect();
return 0;
}