From e058ccbf5a4b2d357d705e0f2cda3d364c24e4f4 Mon Sep 17 00:00:00 2001 From: "artem.bukin" Date: Sun, 10 May 2026 23:49:43 +0300 Subject: [PATCH] mqtt support --- AirQUserDemo.ino | 104 ++++++++++++- AppWeb.cpp | 28 +++- DataBase.cpp | 41 ++++- DataBase.hpp | 7 + airQConfig/package-lock.json | 199 +++++++++++++----------- airQConfig/src/views/WifiConfigView.vue | 60 +++++++ data/db.backup | 9 +- data/db.json | 9 +- data/www/index.html | 20 +-- platformio.ini | 33 ++-- 10 files changed, 384 insertions(+), 126 deletions(-) diff --git a/AirQUserDemo.ino b/AirQUserDemo.ino index 3f8d0b2..2f4e6f7 100644 --- a/AirQUserDemo.ino +++ b/AirQUserDemo.ino @@ -22,7 +22,10 @@ #include "MainAppView.hpp" #include "Sensor.hpp" #include "AppWeb.hpp" +#include +WiFiClient wifiClient; +PubSubClient mqttClient(wifiClient); class AirQ_GFX : public lgfx::LGFX_Device { lgfx::Panel_GDEW0154D67 _panel_instance; @@ -524,7 +527,34 @@ void mainApp(ButtonEvent_t *buttonEvent) { if (WiFi.isConnected() && runingEzdataUpload && ezdataUploadCount-- > 0) { ezdataHanlder.setDeviceToken(db.ezdata2.devToken); BUTTON_TONE(); - if (uploadSensorRawData(ezdataHanlder)) { + bool ok = false; + + if(db.ezdata2.enabled) { + ok = uploadSensorRawData(ezdataHanlder); + } + + if(db.mqtt.host != "") { + // Инициализация MQTT клиента + IPAddress serverIP; + if (serverIP.fromString(db.mqtt.host.c_str())) { + mqttClient.setServer(serverIP, 1883); + log_i("using ip addr from host %s", db.mqtt.host.c_str()); + } else { + mqttClient.setServer(db.mqtt.host.c_str(), 1883); + log_i("using host %s as domain", db.mqtt.host.c_str()); + } + mqttClient.setBufferSize(1024); + mqttClient.setCallback(mqttCallback); + if (!mqttClient.connect(db.nickname.c_str(), db.mqtt.login.c_str(), db.mqtt.password.c_str())) { + log_i("cannot connect to mqtt with %s: %s (result=%d)", db.mqtt.host.c_str(), db.mqtt.login.c_str(), mqttClient.state()); + } + + if (uploadSensorMqttData(mqttClient, db.mqtt.topic.c_str())) { + ok = true; + } + } + + if (ok) { successCounter += 1; preferences.putUInt("OK", successCounter); String msg = "OK:" + String(successCounter); @@ -975,6 +1005,14 @@ void listDirectory(fs::FS &fs, const char * dirname, uint8_t levels) { } +// Callback при получении сообщения +void mqttCallback(char* topic, byte* payload, unsigned int length) { + char *message = (char *)malloc(length); + snprintf(message, length, "%s", payload); + log_i("MQTT debug topic=%s: %s", topic, message); + free(message); +} + void wifiAPSTASetup() { log_i("WiFi setup..."); @@ -1004,7 +1042,6 @@ void wifiAPSTASetup() { log_i("softAP MAC: %s", mac.c_str()); } - void wifiStartAP() { WiFi.softAPdisconnect(); WiFi.disconnect(); @@ -1190,6 +1227,69 @@ OUT1: } +bool uploadSensorMqttData(PubSubClient &mqttClient, const char *topic) { + bool ret = false; + cJSON *rootObject = NULL; + cJSON *sen55Object = NULL; + cJSON *scd40Object = NULL; + cJSON *rtcObject = NULL; + cJSON *profileObject = NULL; + char *buf = NULL; + String data; + + rootObject = cJSON_CreateObject(); + if (rootObject == NULL) { + goto OUT1; + } + + sen55Object = cJSON_CreateObject(); + if (sen55Object == NULL) { + goto OUT; + } + cJSON_AddItemToObject(rootObject, "sen55", sen55Object); + + scd40Object = cJSON_CreateObject(); + if (scd40Object == NULL) { + goto OUT; + } + cJSON_AddItemToObject(rootObject, "scd40", scd40Object); + + cJSON_AddNumberToObject(sen55Object, "pm1.0", sensor.sen55.massConcentrationPm1p0); + cJSON_AddNumberToObject(sen55Object, "pm2.5", sensor.sen55.massConcentrationPm2p5); + cJSON_AddNumberToObject(sen55Object, "pm4.0", sensor.sen55.massConcentrationPm4p0); + cJSON_AddNumberToObject(sen55Object, "pm10.0", sensor.sen55.massConcentrationPm10p0); + cJSON_AddNumberToObject(sen55Object, "humidity", sensor.sen55.ambientHumidity); + cJSON_AddNumberToObject(sen55Object, "temperature", sensor.sen55.ambientTemperature); + cJSON_AddNumberToObject(sen55Object, "voc", sensor.sen55.vocIndex); + cJSON_AddNumberToObject(sen55Object, "nox", sensor.sen55.noxIndex); + + cJSON_AddNumberToObject(scd40Object, "co2", sensor.scd40.co2); + cJSON_AddNumberToObject(scd40Object, "humidity", sensor.scd40.humidity); + cJSON_AddNumberToObject(scd40Object, "temperature", sensor.scd40.temperature); + + // cJSON_AddNumberToObject(rtcObject, "sleep_interval", db.rtc.sleepInterval); + // cJSON_AddStringToObject(profileObject, "nickname", db.nickname.c_str()); + + buf = cJSON_PrintUnformatted(rootObject); + data = buf; + // data.replace("\"", "\\\""); + + if (mqttClient.connected() && mqttClient.publish(topic, data.c_str())) { + log_i("mqtt publish ok, topic: %s", topic); + ret = true; + } else { + log_w("mqtt publish failed, connected: %d", mqttClient.connected()); + ret = false; + } + +OUT: + free(buf); + cJSON_Delete(rootObject); +OUT1: + return ret; +} + + /** * This method of obtaining wake status is not 100% accurate. */ diff --git a/AppWeb.cpp b/AppWeb.cpp index cd798c5..cedf013 100644 --- a/AppWeb.cpp +++ b/AppWeb.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "config.h" #include "DataBase.hpp" @@ -17,6 +18,7 @@ bool webServerState = false; extern SensirionI2CScd4x scd4x; extern SensirionI2CSen5x sen5x; +extern PubSubClient mqttClient; static void postWiFiConnect(); static void getWiFiStatus(); @@ -451,10 +453,34 @@ static void postConfig() { } } + cJSON *mqttObject = cJSON_GetObjectItem(configObject, "mqtt"); + if (mqttObject) { + cJSON *mqttHostObject = cJSON_GetObjectItem(mqttObject, "host"); + cJSON *mqttTopicObject = cJSON_GetObjectItem(mqttObject, "topic"); + cJSON *mqttLoginObject = cJSON_GetObjectItem(mqttObject, "login"); + cJSON *mqttPasswordObject = cJSON_GetObjectItem(mqttObject, "password"); + if (String(mqttHostObject->valuestring) != db.mqtt.host + || String(mqttTopicObject->valuestring) != db.mqtt.topic + || String(mqttLoginObject->valuestring) != db.mqtt.login + || String(mqttPasswordObject->valuestring) != db.mqtt.password + ) { + db.mqtt.host = String(mqttHostObject->valuestring); + db.mqtt.topic = String(mqttTopicObject->valuestring); + db.mqtt.login = String(mqttLoginObject->valuestring); + db.mqtt.password = String(mqttPasswordObject->valuestring); + mqttClient.setServer(db.mqtt.host.c_str(), 1883); + flag = true; + } + } + ezdataObject = cJSON_GetObjectItem(configObject, "ezdata2"); if (ezdataObject) { cJSON *tokenObject = cJSON_GetObjectItem(ezdataObject, "dev_token"); - db.ezdata2.devToken = tokenObject->valuestring; + if (tokenObject) { + db.ezdata2.devToken = tokenObject->valuestring; + } + cJSON *enabledObject = cJSON_GetObjectItem(ezdataObject, "enabled"); + db.ezdata2.enabled = cJSON_IsTrue(enabledObject); db.factoryState = false; } diff --git a/DataBase.cpp b/DataBase.cpp index fb4936d..b18d6fa 100644 --- a/DataBase.cpp +++ b/DataBase.cpp @@ -9,6 +9,7 @@ void DataBase::saveToFile() { cJSON *rootObject = NULL; cJSON *configObject = NULL; cJSON *wifiObject = NULL; + cJSON *mqttObject = NULL; cJSON *rtcObject = NULL; cJSON *ntpObject = NULL; cJSON *ezdataObject = NULL; @@ -37,6 +38,16 @@ void DataBase::saveToFile() { cJSON_AddStringToObject(wifiObject, "ssid", wifi.ssid.c_str()); cJSON_AddStringToObject(wifiObject, "password", wifi.password.c_str()); + mqttObject = cJSON_CreateObject(); + if (mqttObject == NULL) { + goto OUT; + } + cJSON_AddItemToObject(configObject, "mqtt", mqttObject); + cJSON_AddStringToObject(mqttObject, "login", mqtt.login.c_str()); + cJSON_AddStringToObject(mqttObject, "password", mqtt.password.c_str()); + cJSON_AddStringToObject(mqttObject, "host", mqtt.host.c_str()); + cJSON_AddStringToObject(mqttObject, "topic", mqtt.topic.c_str()); + rtcObject = cJSON_CreateObject(); if (rtcObject == NULL) { goto OUT; @@ -59,6 +70,7 @@ void DataBase::saveToFile() { } cJSON_AddItemToObject(configObject, "ezdata2", ezdataObject); cJSON_AddStringToObject(ezdataObject, "dev_token", ezdata2.devToken.c_str()); + cJSON_AddBoolToObject(ezdataObject, "enabled", ezdata2.enabled); buzzerObject = cJSON_CreateObject(); if (buzzerObject == NULL) { @@ -91,6 +103,12 @@ void DataBase::dump() { log_d(" ssid: %s", wifi.ssid.c_str()); log_d(" password: %s", wifi.password.c_str()); + log_d(" mqtt:"); + log_d(" login: %s", mqtt.login.c_str()); + log_d(" password: %s", mqtt.password.c_str()); + log_d(" host: %s", mqtt.host.c_str()); + log_d(" topic: %s", mqtt.topic.c_str()); + log_d(" rtc:"); log_d(" sleep_interval: %d", rtc.sleepInterval); @@ -101,6 +119,7 @@ void DataBase::dump() { log_d(" ezdata2:"); log_d(" dev_token: %s", ezdata2.devToken.c_str()); + log_d(" enabled: %d", ezdata2.enabled); log_d(" buzzer:"); log_d(" onoff: %d", buzzer.onoff); @@ -140,6 +159,18 @@ void DataBase::loadFromFile(void) { wifi.ssid = String(ssidObject->valuestring); wifi.password = String(pskObject->valuestring); + cJSON *mqttObject = cJSON_GetObjectItem(configObject, "mqtt"); + if (mqttObject) { + cJSON *loginObject = cJSON_GetObjectItem(mqttObject, "login"); + cJSON *passObject = cJSON_GetObjectItem(mqttObject, "password"); + cJSON *hostObject = cJSON_GetObjectItem(mqttObject, "host"); + cJSON *topicObject = cJSON_GetObjectItem(mqttObject, "topic"); + if (loginObject) mqtt.login = String(loginObject->valuestring); + if (passObject) mqtt.password = String(passObject->valuestring); + if (hostObject) mqtt.host = String(hostObject->valuestring); + if (topicObject) mqtt.topic = String(topicObject->valuestring); + } + cJSON *factoryStateObject = cJSON_GetObjectItem(configObject, "factory_state"); factoryState = cJSON_IsTrue(factoryStateObject); @@ -156,11 +187,15 @@ void DataBase::loadFromFile(void) { ntp.tz = String(tzObject->valuestring); cJSON *ezdataObject = cJSON_GetObjectItem(configObject, "ezdata2"); - cJSON *tokenObject = cJSON_GetObjectItem(ezdataObject, "dev_token"); - ezdata2.devToken = String(tokenObject->valuestring); + if (ezdataObject) { + cJSON *tokenObject = cJSON_GetObjectItem(ezdataObject, "dev_token"); + ezdata2.devToken = String(tokenObject->valuestring); + cJSON *enabledObject = cJSON_GetObjectItem(ezdataObject, "enabled"); + ezdata2.enabled = cJSON_IsTrue(enabledObject); + } cJSON *buzzerObject = cJSON_GetObjectItem(configObject, "buzzer"); - if (cJSON_IsTrue(cJSON_GetObjectItem(buzzerObject, "mute"))) { + if (buzzerObject && cJSON_IsTrue(cJSON_GetObjectItem(buzzerObject, "mute"))) { buzzer.onoff = true; } else { buzzer.onoff = false; diff --git a/DataBase.hpp b/DataBase.hpp index 62d25c8..9a9f058 100644 --- a/DataBase.hpp +++ b/DataBase.hpp @@ -26,10 +26,17 @@ class DataBase { String ntpServer1; String tz; } ntp; + struct { + String host; + String topic; + String login; + String password; + } mqtt; struct { String devToken; String loginName; String password; + bool enabled; } ezdata2; struct { bool onoff; diff --git a/airQConfig/package-lock.json b/airQConfig/package-lock.json index c513468..2b89de7 100644 --- a/airQConfig/package-lock.json +++ b/airQConfig/package-lock.json @@ -701,22 +701,24 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1060,10 +1062,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1248,6 +1251,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -1308,12 +1312,13 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -1321,10 +1326,11 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1344,15 +1350,16 @@ } }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -1468,15 +1475,17 @@ "dev": true }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -1604,9 +1613,9 @@ } }, "node_modules/postcss": { - "version": "8.4.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz", - "integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==", + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", "funding": [ { "type": "opencollective", @@ -1621,10 +1630,11 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -1832,10 +1842,11 @@ } }, "node_modules/rollup": { - "version": "3.28.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.1.tgz", - "integrity": "sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==", + "version": "3.30.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.30.0.tgz", + "integrity": "sha512-kQvGasUgN+AlWGliFn2POSajRQEsULVYFGTvOZmK06d7vCD+YhZztt70kGk3qaeAXeWYL5eO7zx+rAubBc55eA==", "dev": true, + "license": "MIT", "bin": { "rollup": "dist/bin/rollup" }, @@ -1876,9 +1887,10 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -2004,6 +2016,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -2054,10 +2067,11 @@ "dev": true }, "node_modules/vite": { - "version": "4.4.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", - "integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==", + "version": "4.5.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.14.tgz", + "integrity": "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.18.10", "postcss": "^8.4.27", @@ -2180,12 +2194,19 @@ "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" }, "node_modules/yaml": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.2.tgz", - "integrity": "sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.4.tgz", + "integrity": "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==", "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, "engines": { - "node": ">= 14" + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yargs": { @@ -2625,9 +2646,9 @@ "dev": true }, "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "requires": { "balanced-match": "^1.0.0", @@ -2635,12 +2656,12 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "browserslist": { @@ -2893,9 +2914,9 @@ } }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -3073,19 +3094,19 @@ "dev": true }, "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "requires": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -3103,9 +3124,9 @@ } }, "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==" }, "node-releases": { "version": "2.0.13", @@ -3185,14 +3206,14 @@ "dev": true }, "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true }, "pify": { @@ -3246,13 +3267,13 @@ "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==" }, "postcss": { - "version": "8.4.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz", - "integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==", + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", "requires": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" } }, "postcss-import": { @@ -3373,9 +3394,9 @@ "dev": true }, "rollup": { - "version": "3.28.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.1.tgz", - "integrity": "sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==", + "version": "3.30.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.30.0.tgz", + "integrity": "sha512-kQvGasUgN+AlWGliFn2POSajRQEsULVYFGTvOZmK06d7vCD+YhZztt70kGk3qaeAXeWYL5eO7zx+rAubBc55eA==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -3396,9 +3417,9 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" }, "string-width": { "version": "4.2.3", @@ -3519,9 +3540,9 @@ "dev": true }, "vite": { - "version": "4.4.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", - "integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==", + "version": "4.5.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.14.tgz", + "integrity": "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==", "dev": true, "requires": { "esbuild": "^0.18.10", @@ -3586,9 +3607,9 @@ "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" }, "yaml": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.2.tgz", - "integrity": "sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.4.tgz", + "integrity": "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==", "dev": true }, "yargs": { diff --git a/airQConfig/src/views/WifiConfigView.vue b/airQConfig/src/views/WifiConfigView.vue index bad480d..4c09cde 100644 --- a/airQConfig/src/views/WifiConfigView.vue +++ b/airQConfig/src/views/WifiConfigView.vue @@ -59,6 +59,15 @@ const data = ref({ }, "buzzer": { "mute": true + }, + "mqtt": { + "host": "", + "topic": "", + "login": "", + "password": "" + }, + "ezdata2": { + "enabled": false } } }) @@ -92,6 +101,7 @@ const typePwd = computed(() => { onMounted(() => { getWlan() + getConfig() console.log(connectTimeOut) }) @@ -122,6 +132,29 @@ const getWlan = () => { }) } +const getConfig = () => { + fetch('/api/v1/config') + .then(res => { + if (res.status === 200) { + return res.json() + } else { + throw new Error() + } + }) + .then(res => { + if (res.config) { + data.value.config.rtc = res.config.rtc + data.value.config.ntp = res.config.ntp + data.value.config.buzzer = res.config.buzzer + data.value.config.mqtt = res.config.mqtt + data.value.config.ezdata2 = res.config.ezdata2 + } + }) + .catch(err => { + console.log(err) + }) +} + const checkSSIDInput = () => { if (ssid.value.trim() === '') { ssidTip.value = true @@ -416,6 +449,33 @@ const handleToggleDropdown = () => { +
+
+ MQTT Config +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
diff --git a/data/db.backup b/data/db.backup index 4a80320..269dbd0 100644 --- a/data/db.backup +++ b/data/db.backup @@ -5,6 +5,12 @@ "ssid": "", "password": "" }, + "mqtt": { + "host": "", + "password": "", + "login": "", + "topic": "" + }, "rtc": { "sleep_interval": 60 }, @@ -14,7 +20,8 @@ "tz": "GMT0" }, "ezdata2": { - "dev_token": "" + "dev_token": "", + "enabled": false }, "buzzer": { "mute": true diff --git a/data/db.json b/data/db.json index dcf6ae9..313ff02 100644 --- a/data/db.json +++ b/data/db.json @@ -5,6 +5,12 @@ "ssid": "", "password": "" }, + "mqtt": { + "host": "", + "password": "", + "login": "", + "topic": "" + }, "rtc": { "sleep_interval": 60 }, @@ -14,7 +20,8 @@ "tz": "GMT0" }, "ezdata2": { - "dev_token": "" + "dev_token": "", + "enabled": false }, "buzzer": { "mute": true diff --git a/data/www/index.html b/data/www/index.html index e400ec4..20806ba 100644 --- a/data/www/index.html +++ b/data/www/index.html @@ -6,26 +6,26 @@ AirQ diff --git a/platformio.ini b/platformio.ini index 5133690..6661e5e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -7,6 +7,7 @@ ; ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html + [platformio] src_dir = . @@ -15,26 +16,20 @@ platform = espressif32 platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32#2.0.14 board = esp32-s3-devkitc-1 framework = arduino - -lib_deps = - ; m5stack/M5GFX @ ^0.1.9 - ; m5stack/M5Unified @ ^0.1.9 - https://github.com/m5stack/M5Unified.git#develop - https://github.com/m5stack/M5GFX.git#develop - sensirion/Sensirion I2C SEN5X@^0.3.0 - sensirion/Sensirion I2C SCD4x@^0.4.0 - tanakamasayuki/I2C BM8563 RTC@^1.0.4 - mathertel/OneButton@^2.0.3 - bblanchon/ArduinoJson @ ^6.21.3 - +lib_deps = + https://github.com/m5stack/M5Unified.git#develop + https://github.com/m5stack/M5GFX.git#develop + sensirion/Sensirion I2C SEN5X@^0.3.0 + sensirion/Sensirion I2C SCD4x@^0.4.0 + tanakamasayuki/I2C BM8563 RTC@^1.0.4 + mathertel/OneButton@^2.0.3 + bblanchon/ArduinoJson @ ^6.21.3 + knolleary/PubSubClient@^2.8 upload_speed = 1500000 upload_protocol = esptool monitor_speed = 115200 -build_flags = - ; -D ARDUINO_USB_CDC_ON_BOOT=1 - ; -D ARDUINO_USB_MODE=0 - -D ARDUINO_USB_DFU_ON_BOOT=1 - -D CORE_DEBUG_LEVEL=3 - -mfix-esp32-psram-cache-issue - +build_flags = + -D ARDUINO_USB_DFU_ON_BOOT=1 + -D CORE_DEBUG_LEVEL=3 + -mfix-esp32-psram-cache-issue board_build.filesystem = littlefs