From a73f1d646af5dc3f4c83f4bfc5268784bb648b41 Mon Sep 17 00:00:00 2001 From: SmartUaWIn Date: Thu, 25 Feb 2021 19:35:58 +0200 Subject: [PATCH] =?UTF-8?q?=D0=98=D0=B4=D0=B5=D1=82=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=86=D0=B5=D1=81=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AAOffice_vent.ino | 466 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 466 insertions(+) create mode 100644 AAOffice_vent.ino diff --git a/AAOffice_vent.ino b/AAOffice_vent.ino new file mode 100644 index 0000000..fcef6a1 --- /dev/null +++ b/AAOffice_vent.ino @@ -0,0 +1,466 @@ +/* +Отправка данных на MQTT про обновление +*/ + +#include // https://github.com/tzapu/WiFiManager +#include //Сохранение настроек хеша прошивки + +#include +#include //Библиотека ОТА обновлений +#include "M5Atom.h" //Библиотека атома для функции Led и Кнопки, можно упразднить и убрать + +#include //Udp клиент +#include //NTP запрос времени +#include //Внутреннее время +#include //Библиотека дял I2C + +#include //Mtqq +#include //Упакова в JSon - удобная библиотека +#include +#include + +//Наша кнопочка при нажатии на которую произойдет вызов wifi менеджера и перезагрузка в станцию +#define TRIGGER_PIN 39 + +#define safetyPin 26 +#define safetyPinOutput 32 + +unsigned int VersionSW = 1; //65536 Версия прошивки + +Servo servoAir; +int posServo = 0; + + +WiFiManager wm; // обьект менеджера +WiFiManagerParameter custom_field; +Preferences OTApreferences; //Обьект хранения настроек хеша прошивки + +String JsonData; +StaticJsonDocument<200> doc, docResult; + +WiFiClient espClient; +PubSubClient MqttClient(espClient); + +WiFiUDP ntpUDP; +NTPClient timeClient(ntpUDP, "0.ua.pool.ntp.org", 7200, 60000); //Собственно сервер времени смещение и частоат запроса, но он вручную + +const PROGMEM char *mqttHostName = "cctv.automation.art"; //Хостнейм брокера 192.168.89.210 cctv.automation.art:8889 +unsigned int mqttPort = 8889; //Порт брокера 1883 +const PROGMEM char *topicName = "/aastudio/sw8"; // +mac адресс девайса Префикс топика +const PROGMEM char *topicNameSub = "/aastudio/sw8/angle"; +const PROGMEM char *mqttLogin = "tt", //Логин пароль - необходимо сменить код при connect() + *mqttPass = "tt"; +const char *mqttIPHost; //тут хранится IP хоста по хостнейму + +unsigned long timingUpdate, timingReqSensor, timingSendMqtt, timingAjaxUpdate; //Таймеры для millis() +int PROGMEM nextM5Update = 450000; //каждые 7.5 минут запрос обновления с сервера +int PROGMEM nextReqSensor = 10000; //опрос датчиков раз в 10 секунд +int PROGMEM nextMqttSend = 3000; //Отправка +int PROGMEM nextAjaxUpdate = 30000; + +String macc = ""; //Глобальное хранение мас адреса + +bool mqttSendFlag = false; +bool safetyStateNow = false, safetyStateOld = false; +int reqCounter = 0; +long rssi = 0; + +//Настройки +void setup() +{ + M5.begin(true, false, true); + delay(50); + + + pinMode(safetyPin, INPUT); //Пин датчика для работы + pinMode(safetyPinOutput, OUTPUT); // Установка пина на выход + digitalWrite(safetyPinOutput, HIGH); //Потому что он 3.3В а не 5 как на выходе рядом + + servoAir.attach(17); + + WiFi.mode(WIFI_STA); + Serial.begin(115200); + Serial.setDebugOutput(true); + delay(100); + + Serial.println("\n Starting station"); + pinMode(TRIGGER_PIN, INPUT); + //int customFieldLength = 40; + const char *custom_radio_str = "
One
Two
Three"; + new (&custom_field) WiFiManagerParameter(custom_radio_str); // custom html input + wm.addParameter(&custom_field); + wm.setSaveParamsCallback(saveParamCallback); + std::vector menu = {"wifi", "info", "param", "sep", "restart", "exit"}; + wm.setMenu(menu); + wm.setClass("invert"); + wm.setConfigPortalTimeout(90); // auto close configportal after n seconds + bool res; + res = wm.autoConnect("AirAnglePortal", "12345678"); // Подключение к анонимной точке доступа + if (!res) + { + Serial.println("Failed to connect or hit timeout"); + ESP.restart(); + } + else + { + Serial.println("connected - OK"); + } + + //Запрос IP сервера MQTT и установка сервера + setMqttServer(); + reqNtpTime(); + macc = getMacAddress(); +} + +//Установка сервера и порта +void setMqttServer() +{ + mdns_init(); + + IPAddress IpMqtt, ipaddr; + + ipaddr = MDNS.queryHost(mqttHostName); // .local omitted + // Serial.println(ipaddr.toString()); + if (ipaddr.toString() == "0.0.0.0") + { + Serial.println("Trying again to resolve mDNS"); + + int err = WiFi.hostByName(mqttHostName, IpMqtt); + if (err == 1) + { + delay(50); + setServCall(IpMqtt); + } + else + { + Serial.print("Error code hostByName(): "); + Serial.println(err); + } + } + else + { + setServCall(ipaddr); + } +} + +void setServCall(IPAddress SetIpaddr) +{ + MqttClient.setServer(SetIpaddr, mqttPort); + MqttClient.setCallback(callback); + Serial.println("Set MQTT Server - OK"); +} + +//Функция получения данных из MQTT если мы подпишемся на топики +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: ")); + //Serial.println(String(error)); + return; + } + + // {"setangle":20,"timer":0,"timerangle": 10} + + //сделать проверку на байті + + byte SetAngle = docResult["setangle"]; + byte isTimer = docResult["timer"]; + byte isTimerAngle = docResult["timerangle"]; + + servoAir.write(SetAngle); + + Serial.println(SetAngle); + Serial.println(isTimer); + Serial.println(isTimerAngle); + + + + Serial.println(); +} + +//Запрос времени NTP и установка локлаьного времени +void reqNtpTime() +{ + timeClient.update(); + setTime(timeClient.getEpochTime()); + // Serial.println(timeClient.getEpochTime()); + // Serial.println("<=ntp====now=>"); + //time_t t = now(); + // Serial.println(t); +} + +//Нажатие кнопки для сброса +void checkButton() +{ + Serial.println("Button Pressed"); + // 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("AirAnglePortal", "12345678")) //Логин и пароль точки доступа + { + Serial.println("failed to connect or hit timeout"); + delay(3000); + // ESP.restart(); + } + else + { + Serial.println("CLIENT connect"); + } +} + +String getParam(String name) +{ + String value; + if (wm.server->hasArg(name)) + { + value = wm.server->arg(name); + } + return value; +} + +void saveParamCallback() +{ + Serial.println("[CALLBACK] saveParamCallback fired"); + Serial.println("PARAM customfieldid = " + getParam("customfieldid")); +} + +//Обновление прошивки, происходит проверка и загрузка +//Делается 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=1234567890&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.println("Hosting return error HASH or error REQUEST"); + } + } + 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/safeatoms.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"); + delay(3000); + ESP.restart(); + break; + + case HTTP_UPDATE_NO_UPDATES: + Serial.println("HTTP_UPDATE_NO_UPDATES"); + delay(3000); + ESP.restart(); + break; + + case HTTP_UPDATE_OK: + Serial.println("HTTP_UPDATE_OK"); + delay(3000); + 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 +void SendMqttReq() +{ + Serial.println("Data in SendMqttReq()"); + rssi = WiFi.RSSI(); + + // doc["mac"] = String(getMacAddress()); + doc["swver"] = VersionSW; + doc["anglestate"] = String(servoAir.read()); + doc["rssi"] = rssi; + 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); + //Serial.println("SentToTopic - ok"); + } +} + +//Переподключение при петери связи с MQTT +//10 раз проверили и вернулись в общий цикл что бы вдруг что втянуть обновления +void reconnectMqtt() +{ + //clientId += String(random(0xffff), HEX); + //clientId.c_str() + //MqttClient.connect(macc.c_str(), mqttLogin, mqttPass + + byte circle = 0; + while (!MqttClient.connected()) + { + + Serial.println("MQTT reconnect..."); + circle++; + if (circle == 2) + { + break; + } + + const char *clientId = macc.c_str(); + //macc += String(random(0xffff), HEX); + if (MqttClient.connect(clientId)) //mqttLogin, mqttPass + { + String finishTopic = ""; + finishTopic = String(topicName) + "/" + macc; + MqttClient.publish(finishTopic.c_str(), "Reconnect NOW and Subscribe"); + + MqttClient.subscribe(topicNameSub); + + Serial.print("Connect MQTT OK"); + mqttSendFlag = true; + } + else + { + Serial.print("failed, rc="); + Serial.println(MqttClient.state()); + mqttSendFlag = false; + } + } +} + +void loop() +{ + //Проверка старта сервера + M5.update(); + if (!MqttClient.connected()) + { + reconnectMqtt(); + } + + //Если не определен IP то и не будет отправки. + // 40 секунд и происходит сброс настроек WIFI + if (M5.Btn.wasReleasefor(40000)) + { + checkButton(); + } + + //По таймеру запруск обновления прошивки + if (millis() - timingUpdate > nextM5Update) + { + reqNtpTime(); + OTAUpdate(); + // Serial.print("OTAUpdate() - "); + // Serial.println(millis()); + timingUpdate = millis(); + } + + //Таймер отправки данных в брокер + + if (millis() - timingSendMqtt > nextMqttSend) + { + SendMqttReq(); + timingSendMqtt = millis(); + } + + MqttClient.loop(); +}