From 837d65342de56af2298830c0eea187904861aafc Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 14 Oct 2021 11:51:52 +0300 Subject: [PATCH] First commit --- FC.ino | 369 +++++++++++ P_auth.h | 64 ++ P_css.h | 305 +++++++++ P_help.h | 112 ++++ P_index.h | 86 +++ P_js.h | 135 ++++ P_setup.h | 1028 +++++++++++++++++++++++++++++ P_sgp.h | 198 ++++++ P_time.h | 968 ++++++++++++++++++++++++++++ P_weath.h | 304 +++++++++ P_wifi.h | 144 +++++ README.md | 8 + SRV.ino | 1081 +++++++++++++++++++++++++++++++ WiFi_Clock.ino | 1570 +++++++++++++++++++++++++++++++++++++++++++++ fileSystem.ino | 121 ++++ fonts.h | 418 ++++++++++++ globals.h | 14 + langModule.ino | 257 ++++++++ max7219.h | 107 +++ ntpModule.ino | 0 rtc.h | 59 ++ sgpModule.h | 136 ++++ soundModule.h | 26 + weatherModule.ino | 501 +++++++++++++++ 24 files changed, 8011 insertions(+) create mode 100644 FC.ino create mode 100644 P_auth.h create mode 100644 P_css.h create mode 100644 P_help.h create mode 100644 P_index.h create mode 100644 P_js.h create mode 100644 P_setup.h create mode 100644 P_sgp.h create mode 100644 P_time.h create mode 100644 P_weath.h create mode 100644 P_wifi.h create mode 100644 SRV.ino create mode 100644 WiFi_Clock.ino create mode 100644 fileSystem.ino create mode 100644 fonts.h create mode 100644 globals.h create mode 100644 langModule.ino create mode 100644 max7219.h create mode 100644 ntpModule.ino create mode 100644 rtc.h create mode 100644 sgpModule.h create mode 100644 soundModule.h create mode 100644 weatherModule.ino diff --git a/FC.ino b/FC.ino new file mode 100644 index 0000000..88ed966 --- /dev/null +++ b/FC.ino @@ -0,0 +1,369 @@ +bool loadConfig(){ // Завантаження даних збереженних в файлі config.json + File configFile = SPIFFS.open("/config.json", "r"); // Відкриваемо файл на читання + if(!configFile) { // якщо файл не знайдено ствоюємого його та записуємо в ньго данні з наших змінних + if(printCom) Serial.println("Failed to open config file"); + saveConfig(); // Створюємо файл + configFile.close(); + return false; // Повернення з помилкою + } + size_t size = configFile.size(); // Перевіряємо ромір файлу, будемо використовувати файл довжиною в 1024 байта + if(printCom) { + Serial.println("size config.file = " + (String) size); + } + if(size > 4096) { + if(printCom) { + Serial.println("Config file size is too large"); + } + configFile.close(); + return false; // Повернення з помилкою + } + jsonConfig = configFile.readString(); // завантажуємо файл конфігурації в глобальну змінну + DynamicJsonDocument doc(8192); // Резервуємо память для json обекту буфер може розти по мірі необхідності переважно для ESP8266 + deserializeJson(doc, jsonConfig); + configFile.close(); + + ssidAP = doc["ssidAP"].as(); + passwordAP = doc["passwordAP"].as(); + ssid[0] = doc["ssid0"].as(); + password[0] = doc["password0"].as(); + ssid[1] = doc["ssid1"].as(); + password[1] = doc["password1"].as(); + auth = doc["auth"].as(); + authOn = doc["authOn"]; + kuOn = doc["kuOn"]; + kuOff = doc["kuOff"]; + weatherHost = doc["weatherHost"]; + weatherKey0 = doc["weatherKey0"].as(); + weatherKey1 = doc["weatherKey1"].as(); + cityID0 = doc["cityID0"].as(); + cityID1 = doc["cityID1"].as(); + snprintf(personalCityName, 51, "%s", (doc["PSN"].as()).c_str()); + weatherLang = doc["weatherLang"].as(); + displayForecast = doc["displayForecast"]; + displayCityName = doc["displayCityName"]; + displayForecastNow = doc["displayForecastNow"]; + displayForecastToday = doc["displayForecastToday"]; + displayForecastTomorrow = doc["displayForecastTomorrow"]; + animNotWeather = doc["animNotWeather"]; + timeStartViewWeather = doc["timeStartViewWeather"]; + timeEndViewWeather = doc["timeEndViewWeather"]; + timeScrollSpeed = doc["timeScrollSpeed"]; + MAX7219_ROTATE = doc["MAX7219_ROTATE"]; + updateOTAEnable = doc["updateOTAEnable"]; + volBrightnessD = doc["volBrightnessD"]; + volBrightnessN = doc["volBrightnessN"]; + timeDay = doc["timeDay"]; + timeNight = doc["timeNight"]; + volBrightnessAuto = doc["volBrightnessAuto"]; + lowLivelBrightness = doc["lowLivelBrightness"]; + upLivelBrightness = doc["upLivelBrightness"]; + clockNight = doc["clockNight"]; + isActiveBuzzer = doc["isActiveBuzzer"]; + function[0] = doc["function00"]; + function[1] = doc["function01"]; + function[2] = doc["function02"]; + function[3] = doc["function03"]; + function[4] = doc["function04"]; + function[5] = doc["function05"]; + function[6] = doc["function06"]; + function[7] = doc["function07"]; + function[8] = doc["function08"]; + function[9] = doc["function09"]; + function[10] = doc["function10"]; + function[11] = doc["function11"]; + period[0] = doc["period00"]; + period[1] = doc["period01"]; + period[2] = doc["period02"]; + period[3] = doc["period03"]; + period[4] = doc["period04"]; + period[5] = doc["period05"]; + period[6] = doc["period06"]; + period[7] = doc["period07"]; + period[8] = doc["period08"]; + period[9] = doc["period09"]; + period[10] = doc["period10"]; + period[11] = doc["period11"]; + printCom = doc["printCom"]; + sensore[0] = doc["sensor00"]; + sensore[1] = doc["sensor01"]; + sensore[2] = doc["sensor02"]; + sensore[3] = doc["sensor03"]; + sensore[4] = doc["sensor04"]; + param0 = doc["param0"]; + param1 = doc["param1"]; + param2 = doc["param2"]; + param3 = doc["param3"]; + param4 = doc["param4"]; + pressSys = doc["pressSys"]; + fontCLOCK = doc["fontCLOCK"]; + aliData = doc["aliData"]; + animPoint = doc["animPoint"]; + corr00 = doc["corr00"]; + corr01 = doc["corr01"]; + corr02 = doc["corr02"]; + corr03 = doc["corr03"]; + corr04 = doc["corr04"]; + MAX7219_NUM = doc["MAX7219_NUM"]; + rtcStat = doc["rtcStat"]; + uuid = doc["uuid"].as(); + api_key = doc["api_key"].as(); + sensors_ID0 = doc["sensors_ID0"]; + sensors_ID1 = doc["sensors_ID1"]; + sensors_ID2 = doc["sensors_ID2"]; + displayData = doc["displayData"]; + butStat = doc["butStat"]; + sgpCo2LivelAlarm = doc["sgpCo2LivelAlarm"]; + eCo2AlarmEsp = doc["eCo2AlarmEsp"]; + eCo2Led = doc["eCo2Led"]; + sgpTvocLivelAlarm = doc["sgpTvocLivelAlarm"]; + tvocAlarmEsp = doc["tvocAlarmEsp"]; + tvocLed = doc["tvocLed"]; + setSgpCorr = doc["setSgpCorr"]; + +printCom = true; +updateOTAEnable = true; + + if(MAX7219_NUM == 0) { + MAX7219_NUM = 4; + } + + if(printCom) { + printTime(); + Serial.print("Load Config : "); + Serial.println(jsonConfig); + } + return true; +} + +//================================================================================================================================================ +bool loadAlarm(){ // Завантаження даних збереженних в файлі config.json + File configFile = SPIFFS.open("/alarm.json", "r"); // Відкриваемо файл на читання + if(!configFile) { // якщо файл не знайдено ствоюємого його та записуємо в ньго данні з наших змінних + if(printCom) Serial.println("Failed to open alarm file"); + saveAlarm(); // Створюємо файл + configFile.close(); + return false; // Повернення з помилкою + } + size_t size = configFile.size(); // Перевіряємо ромір файлу, будемо використовувати файл довжиною в 1024 байта + if(printCom) Serial.println("size alarme.file = " + (String) size); + if(size > 2048) { + if(printCom) Serial.println("Config file size is too large"); + configFile.close(); + return false; // Повернення з помилкою + } + jsonAlarm = configFile.readString(); // завантажуємо файл конфігурації в глобальну змінну + DynamicJsonDocument doc(4096); // Резервуємо память для json обекту буфер може розти по мірі необхідності переважно для ESP8266 + deserializeJson(doc, jsonAlarm); + configFile.close(); + ntpServerName = doc["ntpServerName"].as(); + timeZone = doc["timeZone"]; // Так отримуємо число + isDayLightSaving = doc["isDayLightSaving"]; + alarme[0][0] = doc["al_0_0"]; + alarme[0][1] = doc["al_0_1"]; + alarme[0][2] = doc["al_0_2"]; + alarme[1][0] = doc["al_1_0"]; + alarme[1][1] = doc["al_1_1"]; + alarme[1][2] = doc["al_1_2"]; + alarme[2][0] = doc["al_2_0"]; + alarme[2][1] = doc["al_2_1"]; + alarme[2][2] = doc["al_2_2"]; + alarme[3][0] = doc["al_3_0"]; + alarme[3][1] = doc["al_3_1"]; + alarme[3][2] = doc["al_3_2"]; + alarme[4][0] = doc["al_4_0"]; + alarme[4][1] = doc["al_4_1"]; + alarme[4][2] = doc["al_4_2"]; + rtcStat = doc["rtcStat"]; + + if(printCom) { + printTime(); + Serial.print("Load Alarm(config): "); + Serial.println(jsonAlarm); + } + return true; +} + +//================================================================= +bool saveConfig(){ + DynamicJsonDocument doc(8192); + deserializeJson(doc, jsonConfig); + doc["ssidAP"] = ssidAP; + doc["passwordAP"] = passwordAP; + doc["ssid0"] = ssid[0]; + doc["password0"] = password[0]; + doc["ssid1"] = ssid[1]; + doc["password1"] = password[1]; + doc["auth"] = auth; + doc["authOn"] = authOn; + doc["kuOn"] = kuOn; + doc["kuOff"] = kuOff; + doc["weatherHost"] = weatherHost; + doc["weatherKey0"] = weatherKey0; + doc["weatherKey1"] = weatherKey1; + doc["cityID0"] = cityID0; + doc["cityID1"] = cityID1; + doc["PSN"] = chr_to_str(personalCityName); + doc["weatherLang"] = weatherLang; + doc["displayForecast"] = displayForecast; + doc["displayCityName"] = displayCityName; + doc["displayForecastNow"] = displayForecastNow; + doc["displayForecastToday"] = displayForecastToday; + doc["displayForecastTomorrow"] = displayForecastTomorrow; + doc["timeStartViewWeather"] = timeStartViewWeather; + doc["timeEndViewWeather"] = timeEndViewWeather; + doc["timeScrollSpeed"] = timeScrollSpeed; + doc["MAX7219_ROTATE"] = MAX7219_ROTATE; + doc["updateOTAEnable"] = updateOTAEnable; + doc["volBrightnessD"] = volBrightnessD; + doc["volBrightnessN"] = volBrightnessN; + doc["timeDay"] = timeDay; + doc["timeNight"] = timeNight; + doc["volBrightnessAuto"] = volBrightnessAuto; + doc["lowLivelBrightness"] = lowLivelBrightness; + doc["upLivelBrightness"] = upLivelBrightness; + doc["clockNight"] = clockNight; + doc["isActiveBuzzer"] = isActiveBuzzer; + doc["function00"] = function[0]; + doc["function01"] = function[1]; + doc["function02"] = function[2]; + doc["function03"] = function[3]; + doc["function04"] = function[4]; + doc["function05"] = function[5]; + doc["function06"] = function[6]; + doc["function07"] = function[7]; + doc["function08"] = function[8]; + doc["function09"] = function[9]; + doc["function10"] = function[10]; + doc["function11"] = function[11]; + doc["period00"] = period[0]; + doc["period01"] = period[1]; + doc["period02"] = period[2]; + doc["period03"] = period[3]; + doc["period04"] = period[4]; + doc["period05"] = period[5]; + doc["period06"] = period[6]; + doc["period07"] = period[7]; + doc["period08"] = period[8]; + doc["period09"] = period[9]; + doc["period10"] = period[10]; + doc["period11"] = period[11]; + doc["printCom"] = printCom; + doc["sensor00"] = sensore[0]; + doc["sensor01"] = sensore[1]; + doc["sensor02"] = sensore[2]; + doc["sensor03"] = sensore[3]; + doc["sensor04"] = sensore[4]; + doc["param0"] = param0; + doc["param1"] = param1; + doc["param2"] = param2; + doc["param3"] = param3; + doc["param4"] = param4; + doc["pressSys"] = pressSys; + doc["fontCLOCK"] = fontCLOCK; + doc["aliData"] = aliData; + doc["animPoint"] = animPoint; + doc["corr00"] = corr00; + doc["corr01"] = corr01; + doc["corr02"] = corr02; + doc["corr03"] = corr03; + doc["corr04"] = corr04; + doc["MAX7219_NUM"] = MAX7219_NUM; + doc["rtcStat"] = rtcStat; + doc["uuid"] = uuid; + doc["api_key"] = api_key; + doc["sensors_ID0"] = sensors_ID0; + doc["sensors_ID1"] = sensors_ID1; + doc["sensors_ID2"] = sensors_ID2; + doc["displayData"] = displayData; + doc["butStat"] = butStat; + doc["sgpCo2LivelAlarm"] = sgpCo2LivelAlarm; + doc["eCo2AlarmEsp"] = eCo2AlarmEsp; + doc["eCo2Led"] = eCo2Led; + doc["sgpTvocLivelAlarm"] = sgpTvocLivelAlarm; + doc["tvocAlarmEsp"] = tvocAlarmEsp; + doc["tvocLed"] = tvocLed; + doc["setSgpCorr"] = setSgpCorr; + + jsonConfig = ""; + if(serializeJson(doc, jsonConfig) == 0) { + if(printCom) { + Serial.println(F("Failed to write to jsonConfig")); + } + } + + // Відкриваємо файл для запису + File configFile = SPIFFS.open("/config.json", "w"); + if(!configFile) { + configFile.close(); + return false; + } + + if(serializeJson(doc, configFile) == 0) { + if(printCom) { + Serial.println(F("Failed to write to file")); + } + } + + if(printCom) { + printTime(); + Serial.print("Save Config : "); + Serial.println(jsonConfig); + } + configFile.close(); + bip(); + return true; +} + +//================================================================= +bool saveAlarm() { + DynamicJsonDocument doc(4096); + deserializeJson(doc, jsonAlarm); + doc["ntpServerName"] = ntpServerName; + doc["timeZone"] = timeZone; + doc["isDayLightSaving"] = isDayLightSaving; + doc["al_0_0"] = alarme[0][0]; + doc["al_0_1"] = alarme[0][1]; + doc["al_0_2"] = alarme[0][2]; + doc["al_1_0"] = alarme[1][0]; + doc["al_1_1"] = alarme[1][1]; + doc["al_1_2"] = alarme[1][2]; + doc["al_2_0"] = alarme[2][0]; + doc["al_2_1"] = alarme[2][1]; + doc["al_2_2"] = alarme[2][2]; + doc["al_3_0"] = alarme[3][0]; + doc["al_3_1"] = alarme[3][1]; + doc["al_3_2"] = alarme[3][2]; + doc["al_4_0"] = alarme[4][0]; + doc["al_4_1"] = alarme[4][1]; + doc["al_4_2"] = alarme[4][2]; + doc["rtcStat"] = rtcStat; + + jsonAlarm = ""; + if(serializeJson(doc, jsonAlarm) == 0) { + if(printCom) { + Serial.println(F("Failed to write to jsonConfig")); + } + } + + // Відкриваємо файл для запису + File configFile = SPIFFS.open("/alarm.json", "w"); + if(!configFile) { + configFile.close(); + return false; + } + + if(serializeJson(doc, configFile) == 0) { + if(printCom) { + Serial.println(F("Failed to write to file")); + } + } + + if(printCom) { + printTime(); + Serial.print("Save Alarm : "); + Serial.println(jsonAlarm); + } + configFile.close(); + bip(); + return true; +} diff --git a/P_auth.h b/P_auth.h new file mode 100644 index 0000000..cf8e044 --- /dev/null +++ b/P_auth.h @@ -0,0 +1,64 @@ +const char P_auth[] PROGMEM = R"=====( + + + + Часы информер WiFi_Clock + + + + + + +
+
+ Часы информер WiFi_Clock_{{ver}}
+ Время на ESP: +
+
+
+
+
+ +
+
+
Для доступа к данному устройству необходимо пройти авторизацию.
+
+ + + + + +
Введите токен авторизации
+
+
+ Войти +
+
+
+
+ + + +)====="; diff --git a/P_css.h b/P_css.h new file mode 100644 index 0000000..5e3c943 --- /dev/null +++ b/P_css.h @@ -0,0 +1,305 @@ +const char P_css[] PROGMEM = R"=====( +@charset "utf-8"; +html { + height: 100%; + width: 100%; +} +body { + color: #4e4e4e; + background: #e8e8e8; + height: 100%; + width: 100%; + font-size: 10pt; + font-family: 'Roboto', sans-serif; + margin: 0 auto; +} +table { + font-size: 10pt; + font-weight: 450; +} +header { + height: 54px; + margin-bottom: 22px; +} +.header-block { + padding-top: 6px; + position: fixed; + font-size: 11pt; + font-weight: bold; + text-align: center; + line-height: 150%; + height: 54px; + border-bottom: 1px solid #b3b3b3; + width: 100%; + background-color: #f4f4f4; + -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.16); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.16); +} +.central-unit { + margin-left: auto; + margin-right: auto; + width: 500px; + max-width: 100%; + display: block; + box-shadow: 3px 8px 15px rgba(0, 0, 0, 0.4); + border: 1px solid #d9d9d9; +} +.main-menu { + background: #eeeeee; + font-weight: 500; + font-size: 0; + display: block; + width: 100%; +} +.unit-body { + background-color: white; + padding: 10px; + margin-left: auto; + margin-right: auto; + max-width: 100%; + display: block; +} +.unit-footer { + display: block; + background: #f8f8f8; +} +footer { + height: 41px; +} +.informer { + background-color: #f5f5f5; + margin: 5px; + padding: 1%; + border: 1px solid #d9d9d9; + border-radius: 2px; + font-style: italic; + text-align: justify; + font-size: 0.8em; + display: block; +} +fieldset { + border: 1px solid #d9d9d9; + border-radius: 4px; + margin-top: 5px; + margin-bottom: 5px; + padding: 5px 5px 10px 5px; + background-color: #f5f5f5; +} +fieldset legend { + font-weight: 600; + text-align: left; + padding-left: 4px; + padding-right: 5px; + margin-left: 6px; +} +#main_unit { + text-align: center; +} +.ico-text { + font-size: 10pt; + color: #434343; + cursor: pointer; + background-color: #eeeeee; + transition: 0.5s linear; + padding: 6px 5px 6px 8px; + border-bottom: 1px solid #d9d9d9; + display: table-cell; +} +.ico-text:hover { + background-color: white; +} +.ico-text-active { + background-color: white; + border-bottom: 1px solid white; +} +.ico-text-right { + display: table-cell; + width: inherit; + font-size: 10pt; + color: #434343; + background-color: #eeeeee; + border-bottom: 1px solid #d9d9d9; +} + +.switch { + font-weight: 450; + display: block; + margin: 6px 0 6px 0; + } +.opt_cn { + font-weight: 450; +} +.table { + border-collapse: collapse; + margin-left: auto; + margin-right: auto; +} +.table-centered { + font-weight: 450; + margin-left: auto; + margin-right: auto; +} +.table-centered > * > tr > td { + text-align: left; +} +.left { + text-align: left !important; +} +.right { + text-align: right !important; +} +.center { + text-align: center !important; +} +.table > * > tr > td { + border: 1px solid #a2a9b1; + padding: 0.5em 0.65em; + text-align: left; +} +.table > * > tr > th { + border: 1px solid #a2a9b1; + padding: 0.5em 0.65em; + text-align: center; +} +input[type=text].field, input[type=password].field { + padding: 3px; + margin: 1px; + border: 1px solid #575757; + border-radius: 2px; +} +input:focus[type=text].field{ + border: 1px solid #03d703 +} +input:invalid[type=text] { + border:1px solid red !important; +} +.save_button { + background-color: rgb(221 239 255); + padding: 6px; + border-radius: 3px; + border: 1px solid #c6c6c6; + font-weight: bold; + line-height: 100%; + cursor: pointer; + display: inline-block; + z-index: 1005; +} +.save_button:hover { + box-shadow: 0 0 10px 2px rgba(0,0,0,0.3); +} +.form-buttons { + text-align: right; + padding: 12px; +} +.center { + text-align:center; +} +.link__img{ + text-decoration: none; +} +.footer-band { + margin: auto; + position: fixed; + left: 0; + bottom: 0; + background: #b6b6b6; + width: 100%; + text-align: center; + padding: 5px 0 5px 0; +} +.footer-band-labels { + width: 500px; + margin-left: auto; + margin-right: auto; +} +.footer-left { + float: left; + padding-right: 15px; +} +.footer-right { + float: right; + padding-left: 15px; +} +.login-main { + height: 75%; + display: flex; + align-items: center; + justify-content: center; +} +.login-form-title { + text-align: center; + font-size: 16pt; + font-weight: 450; + padding: 10px 0 10px 0; +} +::selection { + background: green; color: #fff +} +::-moz-selection { + background: green; color: #fff +} +select { + height: 22px; + padding: 0 5px 0; + border-radius: 2px; + border: 1px solid #909090; +} +a { + color: blue; +} +a:visited { + color: blue; +} +a:hover { + color: #1b63ff; +} +.board-container { + display: flex; + justify-content: space-between; + flex-wrap: wrap; +} +.board-block-full { + width: 100%; +} +.board-block-half { + width: 50%; +} +.board-block { + box-sizing: border-box; + display: flex; + justify-content: flex-start; + padding: 5px; +} +.board-block-form { + border: 1px solid #eaeaea; + border-radius: 5px; + background-color: #fbfbfb; + font-size: 26pt; + color: #2c7087; + font-weight: 500; + width: 100%; +} +.main-time-font { + font-size: 65pt; + text-align: center; + font-weight: 600; +} +.board-block-title { + padding: 6px 0 3px 10px; + font-weight: 450; + font-size: 11pt; + color: #4f4f4f; +} +.board-block-text { + font-weight: 400; + font-size: 10pt; + color: #3f3f3f; +} +.board-block-data { + color: #2c7087; + font-weight: 600; + font-size: 37pt; + text-align: right; + padding: 6px 17px 6px 0; +} +)====="; diff --git a/P_help.h b/P_help.h new file mode 100644 index 0000000..1fc8e47 --- /dev/null +++ b/P_help.h @@ -0,0 +1,112 @@ +const char P_help[] PROGMEM = R"=====( + + + + + Часы информер WiFi_Clock + + + + + + +
+
+ Часы информер WiFi_Clock_{{ver}}
+ Время на ESP: + {{time}} +
+
+
+
+ +
+
+ Если что-то пошло не так... +
ВНИМАНИЕ!!! Некоторые изменения могут быть необратимыми! +
+
+ +
+
+
+
+ Update: select and download the firmware (bin) +
+
+ + +
+
+
+
+
+ Если вы ввели что-то не так и не можете изменить его, верните устройство к настройкам по умолчанию. Файл конфигурации будет удален. Устройство перезагрузится! +
+
+
+ +
+
+ + + +)====="; diff --git a/P_index.h b/P_index.h new file mode 100644 index 0000000..8fa6cd1 --- /dev/null +++ b/P_index.h @@ -0,0 +1,86 @@ +const char P_index[] PROGMEM = R"=====( + + + + + Часы информер WiFi_Clock + + + + + +
+
+ Часы информер WiFi_Clock_{{ver}}
+
+
+
+
+ +
+
+
+
+
Время ESP
+
{{time}}
+
+
+
+
+
Погода
+
Сервер:
+
Прогноз недоступен
+
+
+
+
+
Датчик 1
+
-28.9 C
+
+
+
+
+
Датчик 2
+
148 %
+
+
+
+
+
Датчик sgp30
+
148 %
+
+
+
+
+
+
+ + + +)====="; diff --git a/P_js.h b/P_js.h new file mode 100644 index 0000000..04689a3 --- /dev/null +++ b/P_js.h @@ -0,0 +1,135 @@ +const char P_js[] PROGMEM = R"=====( +let xhr=createXmlHttpObject(); + +function createXmlHttpObject() { + let xhr; + if(window.XMLHttpRequest) { + xhr=new XMLHttpRequest(); + } else { + xhr=new ActiveXObject('Microsoft.XMLHTTP'); + } + return xhr; +} +function load(submit) { + if(xhr.readyState===0 || xhr.readyState===4){ + submit+=".json"; + let auth = document.location.search; + if(auth.match(/auth=/)) { + submit+=auth; + } + xhr.open('GET',submit,true); + xhr.send(null); + xhr.onload=function() { + jsonResponse=JSON.parse(xhr.responseText); + loadBlock(xhr.onload); + } + } +} +function loadBlock(){ + let data2 = JSON.parse(xhr.responseText); + let data = document.getElementsByTagName('body')[0].innerHTML; + let new_string; + for (let key in data2){ + new_string=data.replace(new RegExp('{{'+key+'}}', 'g'), data2[key]); + data=new_string; + } + document.getElementsByTagName('body')[0].innerHTML=new_string; + let inputs=document.getElementsByTagName("input"); + let selects=document.getElementsByTagName("select"); + for (let key in data2) { + if(data2[key]=='checked'){ + for (let i=0; i=60) { + min=Number(min)+1;sec=0; + } + if (min>=60) { + hours=Number(hours)+1; + min=0; + } + if (hours>=24) { + hours=0 + }; + document.getElementById("time").innerHTML = hours+":"+(min<10?"0":"")+min+":"+(sec<10?"0":"")+sec; + set_real_time = setTimeout("real_time("+hours+","+min+","+sec+");", 1000); +} +function load_time(submit) { + server = "/Time"; + send_request(submit,server); + load('/configs.json'); +} +function get_html(submit) { + let auth = document.location.search; + if(auth.match(/auth=/)) submit += auth; + window.location.href = submit; +} +function convert(submit) { + let auth = document.location.search; + if(auth.match(/auth=/)) { + submit+=auth.replace("\?", "&"); + } + return (submit); +} +)====="; diff --git a/P_setup.h b/P_setup.h new file mode 100644 index 0000000..e731ccc --- /dev/null +++ b/P_setup.h @@ -0,0 +1,1028 @@ +const char P_setup[] PROGMEM = R"=====( + + + + + Часы информер WiFi_Clock + + + + + + +
+
+ Часы информер WiFi_Clock_{{ver}}
+ Время на ESP: + {{time}} +
+
+
+
+ +
+
+
+ Настройки Часов +
+ Здесь можно настроить параметры экрана, отображение данных на экране, параметры и отображение датчиков. +
+
+

Настройки экрана

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Кол-во модулей (8x8)
Вращение внутри модуля + +
Скорость бегущей строки
Выравнивание данных
Отображать дату + +
Анимация точек + +
Шрифт часов + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Функция на экране Длительность
+
+
+
+ Управление яркостью +
+ + + + + + + + + + + + + + +
Дневной режим экрана с:до:
Уровень яркости днем:ночью:
+ +
+ + + + + + + + +
Уровень c фоторезистора низ:верх:
+
+
+
+ Настройки датчиков +
+
+ Уровень яркости фоторезистора (0-15): {{lba}} +
+ +
+ + + + + + + + + + + +
Сигнал в начале каждого часа с:до:
Кнопка подключена к GPIO16 и к:
+
+ Подтягивающий резистор подключен соответственно к GPIO16 и к противоположному полюсу питания +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Датчик Корр. Данные
+ + + + {{Td}}
{{Tu}}
{{Th}}
{{Hd}}
{{Pu}}
+
+ {{sgp}} +
+
+ Сохранить настройки +
+
+
+
+ + + +)====="; diff --git a/P_sgp.h b/P_sgp.h new file mode 100644 index 0000000..0bc0c0c --- /dev/null +++ b/P_sgp.h @@ -0,0 +1,198 @@ +const char P_sgp[] PROGMEM = R"=====( + + + + + Часы информер WiFi_Clock + + + + + + +
+
+ Часы информер WiFi_Clock_{{ver}}
+ Время на ESP: + {{time}} +
+
+
+
+ +
+
+ Настройки SGP-30 +

Настройка параметров eCO₂:

+
+ SGP30 измеряет два параметра: TVOC и eCO₂. + eCO₂ - эквивалент диоксида углерода СО₂-экв: единица, используемая для сравнения излучающей способности парниковых газов с диоксидом углерода. + Картинка из интернета +
+
+ Текущий уровень eCO₂ (400-5000++): {{sgpCo2}}ppm +
+ ({{textCo2}}) +
+
+
+ + + + + +
Отображать уровень eCO₂ на экране
+
+ Уровни оповещения eCO₂: 0=(400-699), 1=(700-999), 2=(1000-2499), 3=(2500-4999), 4=(5000++) +
+ + + + + + + + + + + + + +
Установить уровень оповещения:
Выводить оповещение на экран
Отправлять Alarm в информ топик MQTT
+
+
+ +

Настройка параметров TVOC:

+
+ TVOC - совокупные летучие органические соединения. В некоторых случаях измерение одного только CO₂ не показывает превышения VOC. + Картинка из интернета +
+
+ Текущий уровень TVOC (0-2200++): {{sgpTvoc}}ppb +
+ ({{textTvoc}}) +
+
+
+ + + + + +
Отображать уровень TVOC на экране
+
+ Уровни оповещения TVCO: 0=(0-64), 1=(65-219), 2=(220-659), 3=(660-2199), 4=(2200++) +
+ + + + + + + + + + + + + +
Установить уровень оповещения:
Выводить оповещение на экран
Отправлять Alarm в информ топик MQTT
+
+
+
+

Настройка коррекци данных SGP-30:

+
+
+ Во избежание ошибок измерения необходимо указать датчику текущую абсолютную влажность воздуха, которая будет учтена при расчёте концентрации. Для этого, в паре с SGP30, рекомендуется использовать датчик влажности/температуры. +
+ +
+ Данные ручного ввода: +
+ + + + + + + + + +
Коррекция температуры (°С):
Коррекция влажности (%):
+
+
+
+ + +
+
+ + + +)====="; diff --git a/P_time.h b/P_time.h new file mode 100644 index 0000000..24c11dd --- /dev/null +++ b/P_time.h @@ -0,0 +1,968 @@ +const char P_time[] PROGMEM = R"=====( + + + + + Часы информер WiFi_Clock + + + + + + +
+
+ Часы информер WiFi_Clock_{{ver}}
+ Время на ESP: + {{time}} +
+
+
+
+ +
+
+ Настройки Времени + + + + + + + + + + + + + + + + + + + + + + + + +
Сервер точного времени (пример) "time.nist.gov"
Адрес сервера
Ваша часовая зона + +
Переход на летнее время + + +
Использовать модуль RTC + + +
+ +
+
+
+ Настройка будильника + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Номер Часы Минуты Режим
1 + + + + + +
2 + + + + + +
3 + + + + + +
4 + + + + + +
5 + + + + + +
+
+
+ Настройки Времени + + + + + + + + + + + + + +
+ Время + + + + : + + + + Дата + + + + - + + + + - + + +
+
+ Установить +
+
+
+ +
+
+ + + +)====="; diff --git a/P_weath.h b/P_weath.h new file mode 100644 index 0000000..8f5c118 --- /dev/null +++ b/P_weath.h @@ -0,0 +1,304 @@ +const char P_weath[] PROGMEM = R"=====( + + + + + Часы информер WiFi_Clock + + + + + + +
+
+ Часы информер WiFi_Clock_{{ver}}
+ Время на ESP: + {{time}} +
+
+
+
+ +
+
+ Настройки погоды +
+ Чтобы получить прогноз погоды, + weatherbit.io + openweathermap.org + здесь мы берем ключи API. +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Погодный сервер
API weatherbit ключ
Название города
API openweathermap ключ
Название или код города
Отображаемое название города
Язык прогноза
+ + + + + + + + + + + + + + + + + + + + + +
Получать и выводить погоду на экран + + +
Отображать название города + + +
Отображать прогноз на сейчас + + +
Отображать прогноз на сегодня + + +
Получать и выводить прогноз на завтра + + +
+ + + + + + + +
Показывать погоду с:до:
+
+
+
+ Данные сервера + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Название города :{{location_name}}
Регион :{{location_region}}
Страна :{{location_country}}
Время обновления :{{location_localtime}}
Рассвет :{{location_sunrise}}
Закат :{{location_sunset}}
Температура :{{location_temp}}
Ощущается как :{{location_app_temp}}
Влажность (%) :{{location_rh}}
Давление (mb) :{{location_pres}}
Скорость ветра (m/s) :{{location_wind_spd}}
Направление ветра :{{location_wind_cdir_full}}
Облачность (%) :{{location_clouds}}
Видимость (km) :{{location_vis}}
Индекс UV (0-11+) :{{location_uv}}
Описание погоды :{{location_weather_description}}
+
+
+ +
+
+ + + +)====="; diff --git a/P_wifi.h b/P_wifi.h new file mode 100644 index 0000000..2da295b --- /dev/null +++ b/P_wifi.h @@ -0,0 +1,144 @@ +const char P_wifi[] PROGMEM = R"=====( + + + + + Часы информер WiFi_Clock + + + + + + +
+
+ Часы информер WiFi_Clock_{{ver}}
+ Время на ESP: + {{time}} +
+
+
+
+ +
+
+
+ Настройки WIFI +
+ Введите настройки интернет соединения для обновления времени, получения данных о погоде. +
+

+ Подключение к локальной WiFi сети +

+
+ + + + + + + + + + + + + + + + +
SSID WiFi сетиПароль
1
2
+
+
+ +
+ Точка доступа часов (IP_192.168.4.1) +
+ + + + + + + + + +
Введите имя точки доступа часов
Пароль к точке доступа
+
+
+
+ Авторизация WEB сервера +
+ + + + + + + + + +
Использовать авторизацию
Токен авторизации
+
+
+
+ Тестовое сообщение + + Отправить +
+
+
+ +
+
+ + + +)====="; diff --git a/README.md b/README.md index 4b0a9c8..77807f3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,10 @@ # WiFi_Clock_esp8266 WiFi Clock on esp8266 based on VZ_Clock (by IvanZah) + () : +- , ; +- DHT22 SPG30; +- WiFi ; +- WiFi ; +- ; +- , ; +- . diff --git a/SRV.ino b/SRV.ino new file mode 100644 index 0000000..a46c0ea --- /dev/null +++ b/SRV.ino @@ -0,0 +1,1081 @@ +void server_init(void) { + server.on("/", auth_auth); + server.on("/index.vz", authIndex); + server.on("/wifi.vz", auth_wifi); + server.on("/time.vz", auth_time); + server.on("/weather.vz", auth_weather); + server.on("/setup.vz", auth_setup); + server.on("/sgp.vz", auth_sgp); + server.on("/help.vz", auth_help); + server.on("/style.css", [](){server.send_P ( 200, "text/css", P_css);}); + server.on("/function.js", [](){server.send_P ( 200, "text/plain", P_js);}); + server.on("/favicon.ico", [](){server.send(200, "text/html", "");}); + server.on("/configs.json", handle_ConfigJSON); // формування configs.json сторінки для передачі данних в web інтерфейс + server.on("/index-data.json", get_IndexDataJson); + server.on("/configs_wifi.json", get_ConfigWifiJson); + server.on("/configs_time.json", handle_ConfigTimeJson); + server.on("/configs_weath.json", handle_ConfigWeathJson); + server.on("/configs_setup.json", handle_ConfigSetupJson); + server.on("/configs_sgp.json", handle_ConfigSgpJson); + server.on("/ssid", handle_Set_Ssid); + server.on("/ntp", handle_ntp); // Установка часової зони по запиту типа http://192.168.2.100/timeZone?timeZone=3 + server.on("/set_time", handle_set_time); + server.on("/timepc", handle_timepc); + server.on("/weatherUpdate", handle_weather_update); + server.on("/weather", handle_weather); // Установка сервера погоди по запиту типа http://192.168.2.100/weatherHost?weatherHost=api.openweathermap.org + server.on("/weathOn", handle_weath_on); + server.on("/setup", handle_setup); + server.on("/sgp", handle_sgp); + server.on("/mess", handleMessage); + server.on("/restart", handle_Restart); // перезавантаження модуля по запиту типу http://192.168.1.11/restart?device=ok + server.on("/stopalarm", handle_stopAlarm); + server.on("/resetConfig", handle_resetConfig); + server.on("/printCom", handle_set_printCom); + server.onNotFound([]() {(404, "text/plain", "FileNotFound");}); + httpUpdater.setup(&server); + server.begin(); +} + +void sendAuthPage() { + server.send_P(200, "text/html", P_auth); +} + +//====================================================================================================== +void auth_auth() { + if(!authOn) { + server.send_P(200, "text/html", P_index); + } else { + sendAuthPage(); + } +} + +//====================================================================================================== +void authIndex() { + server.send_P(200, "text/html", P_index); +} + +//====================================================================================================== +void auth_wifi() { + if(server.arg("auth")==auth || !authOn) { + server.send_P(200, "text/html", P_wifi); + } else { + sendAuthPage(); + } +} + +//====================================================================================================== +void auth_time() { + if(server.arg("auth")==auth || !authOn) { + server.send_P(200, "text/html", P_time); + } else { + sendAuthPage(); + } +} +//====================================================================================================== +void auth_weather() { + if(server.arg("auth")==auth || !authOn) { + server.send_P(200, "text/html", P_weath); + } else { + sendAuthPage(); + } +} +//====================================================================================================== +void auth_setup() { + if(server.arg("auth")==auth || !authOn) { + server.send_P(200, "text/html", P_setup); + } else { + sendAuthPage(); + } +} +//====================================================================================================== +void auth_sgp() { + if(server.arg("auth")==auth || !authOn) { + server.send_P(200, "text/html", P_sgp); + } else { + sendAuthPage(); + } +} + +//====================================================================================================== +void auth_help() { + if(server.arg("auth")==auth || !authOn) { + server.send_P(200, "text/html", P_help); + } else { + sendAuthPage(); + } +} + +//========================================== +bool isNotVerified() { + if(authOn && server.arg("auth") != auth) { + server.send_P(404, "text/html", "404, you are not authorized!"); + return true; + } + return false; +} + +String getJsonHeaderPart() { + String json = "\"ver\":\"" + + String(ver) + + "\",\"time\":\"" + + (String(hour) + ":" + (minute < 10 ? "0" : "") + String(minute) + ":" + (second < 10 ? "0" : "") + String(second)); + return json; +} + +void get_IndexDataJson() { + String json = "{" + + getJsonHeaderPart() + + "\",\"ip\":\"" + + WiFi.localIP().toString() + + "\",\"printCom\":\"" + + (printCom == 1 ? "checked" : "") + + "\"}"; + server.send(200, "text/json", json); +} + +//====================================================================================================== +void handle_ConfigJSON() { + if(isNotVerified()) { + return; + } + String json = "{" + + getJsonHeaderPart() + + "\",\"ip\":\"" + + WiFi.localIP().toString() + + "\",\"printCom\":\"" + + (printCom==1?"checked":"") + + "\"}"; + server.send(200, "text/json", json); +} + +//====================================================================================================== +void get_ConfigWifiJson() { + if(isNotVerified()) { + return; + } + String json = "{" + + getJsonHeaderPart() + + "\",\"auth\":\"" + + auth + + "\",\"ssid0\":\"" + + ssid[0] + + "\",\"password0\":\"" + + password[0] + + "\",\"ssid1\":\"" + + ssid[1] + + "\",\"password1\":\"" + + password[1] + + "\",\"ssidAP\":\"" + + ssidAP + + "\",\"passwordAP\":\"" + + passwordAP + + "\",\"authOn\":\"" + + (authOn==1 ? "checked" : "") + + "\"}"; + server.send(200, "text/json", json); +} +//====================================================================================================== +void handle_ConfigTimeJson(){ + if(isNotVerified()) { + return; + } + String json = "{"; + json += getJsonHeaderPart(); + json += "\",\"ntpServerName\":\""; + json += ntpServerName; + json += "\",\"timeZone\":\""; + json += timeZone; + json += "\",\"isDayLightSaving\":\""; + json += (isDayLightSaving==1?"checked":""); + json += "\",\"rtcStat\":\""; + json += (rtcStat==1?"checked":""); + json += "\",\"setTMes\":\""; + json += "\",\"al_0_0\":\""; + json += alarme[0][0]; + json += "\",\"al_0_1\":\""; + json += alarme[0][1]; + json += "\",\"al_0_2\":\""; + json += alarme[0][2]; + json += "\",\"al_1_0\":\""; + json += alarme[1][0]; + json += "\",\"al_1_1\":\""; + json += alarme[1][1]; + json += "\",\"al_1_2\":\""; + json += alarme[1][2]; + json += "\",\"al_2_0\":\""; + json += alarme[2][0]; + json += "\",\"al_2_1\":\""; + json += alarme[2][1]; + json += "\",\"al_2_2\":\""; + json += alarme[2][2]; + json += "\",\"al_3_0\":\""; + json += alarme[3][0]; + json += "\",\"al_3_1\":\""; + json += alarme[3][1]; + json += "\",\"al_3_2\":\""; + json += alarme[3][2]; + json += "\",\"al_4_0\":\""; + json += alarme[4][0]; + json += "\",\"al_4_1\":\""; + json += alarme[4][1]; + json += "\",\"al_4_2\":\""; + json += alarme[4][2]; + json += "\",\"t0\":\""; + json += hour; + json += "\",\"t1\":\""; + json += minute; + json += "\",\"d0\":\""; + json += day; + json += "\",\"d1\":\""; + json += month; + json += "\",\"d2\":\""; + json += year; + json += "\"}"; + server.send(200, "text/json", json); +} + +//====================================================================================================== +void handle_ConfigWeathJson(){ + if(isNotVerified()) { + return; + } + int sr = location_sunrise.substring(0, 2).toInt() + (int)hourCorr; + if(sr>23) sr -= 24; + if(sr<0) sr += 24; + String sunrise = String(sr) + location_sunrise.substring(2, 5); + int ss = location_sunset.substring(0, 2).toInt() + (int)hourCorr; + if(ss>23) ss -= 24; + if(ss<0) ss += 24; + String sunset = String(ss) + location_sunset.substring(2, 5); + int st = location_localtime.substring(11, 13).toInt() + (int)hourCorr; + int ly = location_localtime.substring(0, 4).toInt(); + byte lm = location_localtime.substring(5, 7).toInt(); + byte ld = location_localtime.substring(8, 10).toInt(); + if(st>23) { + st -= 24; + ld++; + if(ld==32 || (ld==31 && (lm==4 || lm==6 || lm==9 || lm==11)) || (lm==2 && ((ld==29 && ly%4!=0) || (ld==30 && ly%4==0)))) { + ld=1; + lm++; + if(lm>12){ + lm=1; + ly++; + } + } + } + if(st<0) { + st += 24; + ld--; + if(ld<1) { + ld = 0 + ((lm==5 || lm==7 || lm==10 || lm==12 || (lm==3 && ly%4==0))?30:(lm==3 && ly%4!=0)?29:31); + lm--; + if(lm<1){ + lm=12; + ly--; + } + } + } + String lt = String(ly) + "-" + (lm<10?"0":"") + String(lm) + "-" + (ld<10?"0":"") + String(ld) + " " + (st<10?"0":"") + String(st) + location_localtime.substring(13, 16); + String json = "{"; + json += getJsonHeaderPart(); + json += "\",\"weatherKey0\":\""; + json += weatherKey0; + json += "\",\"weatherKey1\":\""; + json += weatherKey1; + json += "\",\"weatherHost\":\""; + json += weatherHost; + json += "\",\"cityID0\":\""; + json += cityID0; + json += "\",\"cityID1\":\""; + json += cityID1; + json += "\",\"personalCityName\":\""; + json += personalCityName; + json += "\",\"weatherLang\":\""; + json += weatherLang; + json += "\",\"displayForecast\":\""; + json += (displayForecast==1?"checked":""); + json += "\",\"displayCityName\":\""; + json += (displayCityName==1?"checked":""); + json += "\",\"displayForecastNow\":\""; + json += (displayForecastNow==1?"checked":""); + json += "\",\"displayForecastToday\":\""; + json += (displayForecastToday==1?"checked":""); + json += "\",\"displayForecastTomorrow\":\""; + json += (displayForecastTomorrow==1?"checked":""); + json += "\",\"animNotWeather\":\""; + json += (animNotWeather==1?"checked":""); + json += "\",\"timeStartViewWeather\":\""; + json += timeStartViewWeather; + json += "\",\"timeEndViewWeather\":\""; + json += timeEndViewWeather; + json += "\",\"location_name\":\""; + json += location_name; + json += "\",\"location_region\":\""; + json += location_region; + json += "\",\"location_country\":\""; + json += location_country; + json += "\",\"location_localtime\":\""; + json += lt; + json += "\",\"location_temp\":\""; + json += location_temp; + json += "\",\"location_app_temp\":\""; + json += location_app_temp; + json += "\",\"location_rh\":\""; + json += location_rh; + json += "\",\"location_pres\":\""; + json += location_pres; + json += "\",\"location_wind_spd\":\""; + json += location_wind_spd; + json += "\",\"location_wind_cdir_full\":\""; + json += location_wind_cdir_full; + json += "\",\"location_sunrise\":\""; + json += sunrise; + json += "\",\"location_sunset\":\""; + json += sunset; + json += "\",\"location_clouds\":\""; + json += location_clouds; + json += "\",\"location_vis\":\""; + json += location_vis; + json += "\",\"location_uv\":\""; + json += location_uv; + json += "\",\"location_weather_description\":\""; + json += location_weather_description; + json += "\",\"uuid\":\""; + json += uuid; + json += "\",\"api_key\":\""; + json += api_key; + json += "\",\"sensors_ID0\":\""; + json += sensors_ID0; + json += "\",\"sensors_ID1\":\""; + json += sensors_ID1; + json += "\",\"sensors_ID2\":\""; + json += sensors_ID2; + json += "\"}"; + server.send(200, "text/json", json); +} + +//====================================================================================================== +void handle_ConfigSetupJson(){ + if(isNotVerified()) { + return; + } + String json = "{"; + json += getJsonHeaderPart(); + json += "\",\"kuOn\":\""; + json += kuOn; + json += "\",\"kuOff\":\""; + json += kuOff; + json += "\",\"timeDay\":\""; + json += timeDay; + json += "\",\"volBrightnessD\":\""; + json += volBrightnessD; + json += "\",\"volBrightnessN\":\""; + json += volBrightnessN; + json += "\",\"timeNight\":\""; + json += timeNight; + json += "\",\"timeScrollSpeed\":\""; + json += 100 - timeScrollSpeed; + json += "\",\"clockNight\":\""; + json += (clockNight==1?"checked":""); + json += "\",\"volBrightnessAuto\":\""; + json += (volBrightnessAuto==1?"checked":""); + json += "\",\"lowLivelBrightness\":\""; + json += lowLivelBrightness; + json += "\",\"upLivelBrightness\":\""; + json += upLivelBrightness; + json += "\",\"lba\":\""; + json += levelBridhtness; + json += "\",\"isActiveBuzzer\":\""; + json += (isActiveBuzzer == 1 ? "checked" : ""); + json += "\",\"sensor00\":\""; + json += sensore[0]; + json += "\",\"corr00\":\""; + json += corr00; + float Td=data00; + if(param0==20){ + if(pressSys==1 && Td>815) Td /= 1.3332239; + if(pressSys!=1 && Td<815) Td /= 0.7500615613026439; + } + json += "\",\"Td\":\""; + json += Td; + json += "\",\"sensor01\":\""; + json += sensore[1]; + json += "\",\"corr01\":\""; + json += corr01; + float Tu=data01; + if(param1==20){ + if(pressSys==1 && Tu>815) Tu /= 1.3332239; + if(pressSys!=1 && Tu<815) Tu /= 0.7500615613026439; + } + json += "\",\"Tu\":\""; + json += Tu; + json += "\",\"sensor02\":\""; + json += sensore[2]; + json += "\",\"corr02\":\""; + json += corr02; + float Th=data02; + if(param2==20){ + if(pressSys==1 && Th>815) Th /= 1.3332239; + if(pressSys!=1 && Th<815) Th /= 0.7500615613026439; + } + json += "\",\"Th\":\""; + json += Th; + json += "\",\"sensor03\":\""; + json += sensore[3]; + json += "\",\"corr03\":\""; + json += corr03; + float Hd=data03; + if(param3==20){ + if(pressSys==1 && Hd>815) Hd /= 1.3332239; + if(pressSys!=1 && Hd<815) Hd /= 0.7500615613026439; + } + json += "\",\"Hd\":\""; + json += Hd; + json += "\",\"sensor04\":\""; + json += sensore[4]; + json += "\",\"corr04\":\""; + json += corr04; + float Pu=data04; + if(param4==20){ + if(pressSys==1 && Pu>815) Pu /= 1.3332239; + if(pressSys!=1 && Pu<815) Pu /= 0.7500615613026439; + } + json += "\",\"Pu\":\""; + json += Pu; + json += "\",\"pressSys\":\""; + json += pressSys; + json += "\",\"param0\":\""; + json += param0; + json += "\",\"param1\":\""; + json += param1; + json += "\",\"param2\":\""; + json += param2; + json += "\",\"param3\":\""; + json += param3; + json += "\",\"param4\":\""; + json += param4; + json += "\",\"MAX7219_ROTATE\":\""; + json += MAX7219_ROTATE; + json += "\",\"MAX7219_NUM\":\""; + json += MAX7219_NUM; + json += "\",\"fontCLOCK\":\""; + json += fontCLOCK; + json += "\",\"animPoint\":\""; + json += animPoint; + json += "\",\"aliData\":\""; + json += aliData; + json += "\",\"butStat\":\""; + json += butStat; + json += "\",\"displayData\":\""; + json += displayData; + json += "\",\"function00\":\""; + json += function[0]; + json += "\",\"function01\":\""; + json += function[1]; + json += "\",\"function02\":\""; + json += function[2]; + json += "\",\"function03\":\""; + json += function[3]; + json += "\",\"function04\":\""; + json += function[4]; + json += "\",\"function05\":\""; + json += function[5]; + json += "\",\"function06\":\""; + json += function[6]; + json += "\",\"function07\":\""; + json += function[7]; + json += "\",\"function08\":\""; + json += function[8]; + json += "\",\"function09\":\""; + json += function[9]; + json += "\",\"function10\":\""; + json += function[10]; + json += "\",\"function11\":\""; + json += function[11]; + json += "\",\"period00\":\""; + json += period[0]; + json += "\",\"period01\":\""; + json += period[1]; + json += "\",\"period02\":\""; + json += period[2]; + json += "\",\"period03\":\""; + json += period[3]; + json += "\",\"period04\":\""; + json += period[4]; + json += "\",\"period05\":\""; + json += period[5]; + json += "\",\"period06\":\""; + json += period[6]; + json += "\",\"period07\":\""; + json += period[7]; + json += "\",\"period08\":\""; + json += period[8]; + json += "\",\"period09\":\""; + json += period[9]; + json += "\",\"period10\":\""; + json += period[10]; + json += "\",\"period11\":\""; + json += period[11]; + json += "\",\"sgp\":\""; + if(sgpFound){ + json += "SGP30"; + } else json += ""; + json += "\"}"; + server.send(200, "text/json", json); +} + +//====================================================================================================== +void handle_ConfigSgpJson() { + if(isNotVerified()) { + return; + } + String json = "{" + + getJsonHeaderPart() + + "\",\"sgpCo2\":\"" + + sgpCo2 + + "\",\"textCo2\":\"" + + sgpCo2Message[sgpValues.co2Livel] + + "\",\"sgpCo2LivelAlarm\":\"" + + sgpCo2LivelAlarm + + "\",\"eCo2AlarmEsp\":\"" + + (eCo2AlarmEsp==1?"checked":"") + + "\",\"eCo2Led\":\"" + + (eCo2Led==1?"checked":"") + + "\",\"sgpTvoc\":\"" + + sgpTvoc + + "\",\"textTvoc\":\"" + + sgpTvocMessage[sgpValues.tvocLivel] + + "\",\"sgpTvocLivelAlarm\":\"" + + sgpTvocLivelAlarm + + "\",\"tvocAlarmEsp\":\"" + + (tvocAlarmEsp==1?"checked":"") + + "\",\"tvocLed\":\"" + + (tvocLed==1?"checked":"") + + "\",\"setSgpCorr\":\"" + + setSgpCorr + + "\",\"sgpCorrTemp\":\"" + + sgpCorrTemp + + "\",\"sgpCorrHumi\":\"" + + sgpCorrHumi + + "\"}"; + server.send(200, "text/json", json); +} + +//====================================================================================================== +void handle_Set_Ssid(){ + if(isNotVerified()) { + return; + } + if(server.arg("ssid0")!="") ssid[0] = server.arg("ssid0").c_str(); + password[0] = server.arg("password0").c_str(); + ssid[1] = server.arg("ssid1").c_str(); + password[1] = server.arg("password1").c_str(); + if(server.arg("ssidAP")!="") ssidAP = server.arg("ssidAP").c_str(); + passwordAP = server.arg("passwordAP").c_str(); + if(server.arg("auth")!="") auth = server.arg("auth").c_str(); + if(server.arg("authOn")!="") authOn = server.arg("authOn").toInt(); + saveConfig(); + if(printCom) { + printTime(); + Serial.println("Set ssid0: " + ssid[0] + ", Set password0: " + password[0] + ", ssid1: " + ssid[1] + ", password1: " + password[1] + ", ssidAP: " + ssidAP + ", AP password: " + passwordAP + ", Set auth: " + auth + ", Set authOn: " + authOn); + } + server.send(200, "text/plain", "OK"); + ESP.reset(); +} + +void handle_ntp() { + if(isNotVerified()) { + return; + } + if(server.arg("ntpServerName")!="") { + ntpServerName = server.arg("ntpServerName").c_str(); + } + if(server.arg("timeZone")!="") { + timeZone = server.arg("timeZone").toFloat(); + } + if(server.arg("isDayLightSaving")!="") { + isDayLightSaving = server.arg("isDayLightSaving").toInt(); + } + if(server.arg("rtcStat")!="") { + rtcStat = server.arg("rtcStat").toInt(); + } +// if(server.arg("setTMes")!="") setTMes = server.arg("setTMes").toInt(); + if(server.arg("al_0_0")!="") { + alarme[0][0]=server.arg("al_0_0").toInt(); + } + if(server.arg("al_0_1")!="") { + alarme[0][1]=server.arg("al_0_1").toInt(); + } + if(server.arg("al_0_2")!="") { + alarme[0][2]=server.arg("al_0_2").toInt(); + } + if(server.arg("al_1_0")!="") { + alarme[1][0]=server.arg("al_1_0").toInt(); + } + if(server.arg("al_1_1")!="") { + alarme[1][1]=server.arg("al_1_1").toInt(); + } + if(server.arg("al_1_2")!="") { + alarme[1][2]=server.arg("al_1_2").toInt(); + } + if(server.arg("al_2_0")!="") { + alarme[2][0]=server.arg("al_2_0").toInt(); + } + if(server.arg("al_2_1")!="") { + alarme[2][1]=server.arg("al_2_1").toInt(); + } + if(server.arg("al_2_2")!="") { + alarme[2][2]=server.arg("al_2_2").toInt(); + } + if(server.arg("al_3_0")!="") { + alarme[3][0]=server.arg("al_3_0").toInt(); + } + if(server.arg("al_3_1")!="") { + alarme[3][1]=server.arg("al_3_1").toInt(); + } + if(server.arg("al_3_2")!="") { + alarme[3][2]=server.arg("al_3_2").toInt(); + } + if(server.arg("al_4_0")!="") { + alarme[4][0]=server.arg("al_4_0").toInt(); + } + if(server.arg("al_4_1")!="") { + alarme[4][1]=server.arg("al_4_1").toInt(); + } + if(server.arg("al_4_2")!="") { + alarme[4][2]=server.arg("al_4_2").toInt(); + } + if(printCom) { + printTime(); + Serial.println("Set NTP Server Name: " + ntpServerName + ", NTP Time Zone: " + String(timeZone) + ", isDayLightSaving: " + String(isDayLightSaving)); + } + alarm_hold = 0; + saveAlarm(); + timeUpdateNTP(); + server.send(200, "text/plain", "OK"); +} + +//====================================================================================================== +void handle_set_time(){ + if(isNotVerified()) { + return; + } + if(server.arg("t0")!="") hour = server.arg("t0").toInt(); + if(server.arg("t1")!="") minute = server.arg("t1").toInt(); + if(server.arg("d0")!="") day = server.arg("d0").toInt(); + if(server.arg("d1")!="") month = server.arg("d1").toInt(); + if(server.arg("d2")!="") year = server.arg("d2").toInt(); + if(printCom) { + printTime(); + Serial.println("Set manual time: " + String(hour) + ":" + String(minute) + " " + String(day) + "-" + String(month) + "-" + String(year)); + } + server.send(200, "text/plain", "OK"); + + localEpoc = (hour * 60 * 60 + minute * 60); + showSimpleDate(); + + rtcStruct.hour = hour; + rtcStruct.minute = minute; + rtcStruct.second = 0; + rtcStruct.month = month; + rtcStruct.day = day; + rtcStruct.year = year; + printTime(); + setRTCDateTime(); +} + +//====================================================================================================== +void handle_timepc(){ + if(isNotVerified()) { + return; + } + if(server.arg("hours")!="") { + hour = server.arg("hours").toInt(); + } + if(server.arg("minute")!="") { + minute = server.arg("minute").toInt(); + } + if(server.arg("sec")!="") { + second = server.arg("sec").toInt(); + } + if(server.arg("tz")!="") { + timeZone = server.arg("tz").toFloat(); + } + if(server.arg("day")!="") { + day = server.arg("day").toInt(); + } + if(server.arg("month")!="") { + month = server.arg("month").toInt(); + } + if(server.arg("year")!="") { + year = server.arg("year").toInt(); + } + if(printCom) { + printTime(); + Serial.println("Set Date/Time from PC - "+String(day)+"."+String(month)+"."+String(year)+" "+String(hour)+":"+String(minute)+":"+String(second)+" timeZone="+String(timeZone)); + } + localMillisAtUpdate = millis(); + localEpoc = (hour * 60 * 60 + minute * 60 + second); + saveConfig(); + server.send(200, "text/plain", "OK"); +} + +//====================================================================================================== +void weather_update() { + if(displayForecast) { + if(!weatherHost) { + getWeatherData0(); + getWeatherDataz0(); + } else { + getWeatherData1(); + getWeatherDataz1(); + } + } +} + +//====================================================================================================== +void handle_weath_on() { + if(isNotVerified()) { + return; + } + if(server.arg("displayForecast")!="") { + displayForecast = server.arg("displayForecast").toInt(); + } + if(printCom) { + printTime(); + Serial.println("displayForecast = " + String(displayForecast)); + } + if(displayForecast) { + weather_update(); + } + saveConfig(); + server.send(200, "text/plain", "OK"); +} + +//====================================================================================================== +void handle_weather_update() { + if(isNotVerified()) { + return; + } + if(server.arg("update") == "ok") { + weather_update(); + bip(); + server.send(200, "text/plain", "OK"); + } +} + +//====================================================================================================== +void handle_weather() { + if(server.arg("weatherHost")!="") { + weatherHost = server.arg("weatherHost").toInt(); + } + if(server.arg("weatherKey0")!="") { + weatherKey0 = server.arg("weatherKey0").c_str(); + } + if(server.arg("weatherKey1")!="") { + weatherKey1 = server.arg("weatherKey1").c_str(); + } + if(server.arg("cityID0")!="") { + cityID0 = server.arg("cityID0").c_str(); + } + if(server.arg("cityID1")!="") { + cityID1 = server.arg("cityID1").c_str(); + } + if(server.arg("weatherLang")!="") { + weatherLang = server.arg("weatherLang").c_str(); + } + if(server.arg("displayForecast")!="") { + displayForecast = server.arg("displayForecast").toInt(); + } + if(server.arg("displayCityName")!="") { + displayCityName = server.arg("displayCityName").toInt(); + } + if(server.arg("displayForecastNow")!="") { + displayForecastNow = server.arg("displayForecastNow").toInt(); + } + if(server.arg("displayForecastToday")!="") { + displayForecastToday = server.arg("displayForecastToday").toInt(); + } + if(server.arg("displayForecastTomorrow")!="") { + displayForecastTomorrow = server.arg("displayForecastTomorrow").toInt(); + } + if(server.arg("timeStartViewWeather")!="") { + timeStartViewWeather = server.arg("timeStartViewWeather").toInt(); + } + if(server.arg("timeEndViewWeather")!="") { + timeEndViewWeather = server.arg("timeEndViewWeather").toInt(); + } + if(server.arg("timeScrollSpeed")!="") { + timeScrollSpeed = 100 - server.arg("timeScrollSpeed").toInt(); + } + uuid = server.arg("uuid").c_str(); + api_key = server.arg("api_key").c_str(); + sensors_ID0 = server.arg("sensors_ID0").toInt(); + sensors_ID1 = server.arg("sensors_ID1").toInt(); + sensors_ID2 = server.arg("sensors_ID2").toInt(); + if(server.arg("personalCityName")!="") { + snprintf(personalCityName, 51, "%s", server.arg("personalCityName").c_str()); + } + if(printCom) { + printTime(); + Serial.print("Set Weather Server: "); + if(!weatherHost) { + Serial.print(weatherHost0); + } else { + Serial.print(weatherHost1); + } + Serial.println(", Key0: " + weatherKey0 + ", Key1: " + weatherKey1 + ", City ID0: " + cityID0 + ", City ID1: " + cityID1 + ", weatherLang: " + weatherLang); + Serial.println(" displayCityName: " + String(displayCityName) + ", displayForecastNow: " + String(displayForecastNow) + ", displayForecastTomorrow: " + String(displayForecastTomorrow) + ", personalCityName: " + String(personalCityName)); + Serial.println(" timeStartViewWeather: " + String(timeStartViewWeather) + ", timeEndViewWeather: " + String(timeEndViewWeather) + ", timeScrollSpeed: " + String(timeScrollSpeed) + ", uuid: " + String(uuid) + ", api_key: " + String(api_key) + ", sensors_ID0: " + String(sensors_ID0) + ", sensors_ID1: " + String(sensors_ID1) + ", sensors_ID2: " + String(sensors_ID2)); + } + + saveConfig(); + initLang(); + weather_update(); + + server.send(200, "text/plain", "OK"); +} + +//====================================================================================================== +void handle_setup(){ + if(isNotVerified()) { + return; + } + if(server.arg("timeDay")!="") timeDay = server.arg("timeDay").toInt(); + if(server.arg("volBrightnessD")!="") volBrightnessD = server.arg("volBrightnessD").toInt(); + if(server.arg("timeNight")!="") timeNight = server.arg("timeNight").toInt(); + if(server.arg("volBrightnessN")!="") volBrightnessN = server.arg("volBrightnessN").toInt(); + if(server.arg("volBrightnessAuto")!="") volBrightnessAuto = server.arg("volBrightnessAuto").toInt(); + if(server.arg("lowLivelBrightness")!="") lowLivelBrightness = server.arg("lowLivelBrightness").toInt(); + if(server.arg("upLivelBrightness")!="") upLivelBrightness = server.arg("upLivelBrightness").toInt(); + if(server.arg("isActiveBuzzer")!="") isActiveBuzzer = server.arg("isActiveBuzzer").toInt(); + if(server.arg("clockNight")!="") clockNight = server.arg("clockNight").toInt(); + if(server.arg("MAX7219_ROTATE")!="") MAX7219_ROTATE = server.arg("MAX7219_ROTATE").toInt(); + if(server.arg("MAX7219_NUM")!="") MAX7219_NUM = server.arg("MAX7219_NUM").toInt(); + if(server.arg("kuOn")!="") kuOn = server.arg("kuOn").toInt(); + if(server.arg("kuOff")!="") kuOff = server.arg("kuOff").toInt(); + if(server.arg("sensor00")!="" && server.arg("param0")!=""){ + int sens = server.arg("sensor00").toInt(); + int param = server.arg("param0").toInt(); + if(sens==0||(sens==1&¶m>=0&¶m<5)||((sens==2||sens==5||sens==10)&¶m>=0&¶m<15)||(sens==3&&(param>=0&¶m<5)||param==20)||(sens==4&&((param>=0&¶m<15)||param==20))||(((sens>5&&sens<10)||(sens>10&&sens<19))&¶m<24)){ + sensore[0] = server.arg("sensor00").toInt(); + param0 = server.arg("param0").toInt(); + } + } + if(server.arg("sensor01")!="" && server.arg("param1")!=""){ + int sens = server.arg("sensor01").toInt(); + int param = server.arg("param1").toInt(); + if(sens==0||(sens==1&¶m>=0&¶m<5)||((sens==2||sens==5||sens==10)&¶m>=0&¶m<15)||(sens==3&&(param>=0&¶m<5)||param==20)||(sens==4&&((param>=0&¶m<15)||param==20))||(((sens>5&&sens<10)||(sens>10&&sens<19))&¶m<24)){ + sensore[1] = sens; + param1 = param; + } + } + if(server.arg("sensor02")!="" && server.arg("param2")!=""){ + int sens = server.arg("sensor02").toInt(); + int param = server.arg("param2").toInt(); + if(sens==0||(sens==1&¶m>=0&¶m<5)||((sens==2||sens==5||sens==10)&¶m>=0&¶m<15)||(sens==3&&(param>=0&¶m<5)||param==20)||(sens==4&&((param>=0&¶m<15)||param==20))||(((sens>5&&sens<10)||(sens>10&&sens<19))&¶m<24)){ + sensore[2] = server.arg("sensor02").toInt(); + param2 = server.arg("param2").toInt(); + } + } + if(server.arg("sensor03")!="" && server.arg("param3")!=""){ + int sens = server.arg("sensor03").toInt(); + int param = server.arg("param3").toInt(); + if(sens==0||(sens==1&¶m>=0&¶m<5)||((sens==2||sens==5||sens==10)&¶m>=0&¶m<15)||(sens==3&&(param>=0&¶m<5)||param==20)||(sens==4&&((param>=0&¶m<15)||param==20))||(((sens>5&&sens<10)||(sens>10&&sens<19))&¶m<24)||(sens==99&¶m==3)){ + sensore[3] = server.arg("sensor03").toInt(); + param3 = server.arg("param3").toInt(); + } + } + if(server.arg("sensor04")!="" && server.arg("param4")!=""){ + int sens = server.arg("sensor04").toInt(); + int param = server.arg("param4").toInt(); + if(sens==0||(sens==1&¶m>=0&¶m<5)||((sens==2||sens==5||sens==10)&¶m>=0&¶m<15)||(sens==3&&(param>=0&¶m<5)||param==20)||(sens==4&&((param>=0&¶m<15)||param==20))||(((sens>5&&sens<10)||(sens>10&&sens<19))&¶m<24)||(sens==99&¶m==21)){ + sensore[4] = server.arg("sensor04").toInt(); + param4 = server.arg("param4").toInt(); + } + } + if(server.arg("pressSys")!="") pressSys = server.arg("pressSys").toInt(); + if(server.arg("fontCLOCK")!="") fontCLOCK = server.arg("fontCLOCK").toInt(); + if(server.arg("animPoint")!="") animPoint = server.arg("animPoint").toInt(); + if(server.arg("aliData")!="") aliData = server.arg("aliData").toInt(); + if(server.arg("timeScrollSpeed")!="") timeScrollSpeed = 100 - server.arg("timeScrollSpeed").toInt(); + if(server.arg("corr00")!="") corr00 = server.arg("corr00").toFloat(); + if(server.arg("corr01")!="") corr01 = server.arg("corr01").toFloat(); + if(server.arg("corr02")!="") corr02 = server.arg("corr02").toFloat(); + if(server.arg("corr03")!="") corr03 = server.arg("corr03").toFloat(); + if(server.arg("corr04")!="") corr04 = server.arg("corr04").toInt(); + if(server.arg("displayData")!="") displayData = server.arg("displayData").toInt(); + if(server.arg("butStat")!="") butStat = server.arg("butStat").toInt(); + + if(server.arg("function00")!="") function[0] = server.arg("function00").toInt(); + if(server.arg("function01")!="") function[1] = server.arg("function01").toInt(); + if(server.arg("function02")!="") function[2] = server.arg("function02").toInt(); + if(server.arg("function03")!="") function[3] = server.arg("function03").toInt(); + if(server.arg("function04")!="") function[4] = server.arg("function04").toInt(); + if(server.arg("function05")!="") function[5] = server.arg("function05").toInt(); + if(server.arg("function06")!="") function[6] = server.arg("function06").toInt(); + if(server.arg("function07")!="") function[7] = server.arg("function07").toInt(); + if(server.arg("function08")!="") function[8] = server.arg("function08").toInt(); + if(server.arg("function09")!="") function[9] = server.arg("function09").toInt(); + if(server.arg("function10")!="") function[10] = server.arg("function10").toInt(); + if(server.arg("function11")!="") function[11] = server.arg("function11").toInt(); + + if(server.arg("period00")!="") period[0] = server.arg("period00").toInt(); + if(server.arg("period01")!="") period[1] = server.arg("period01").toInt(); + if(server.arg("period02")!="") period[2] = server.arg("period02").toInt(); + if(server.arg("period03")!="") period[3] = server.arg("period03").toInt(); + if(server.arg("period04")!="") period[4] = server.arg("period04").toInt(); + if(server.arg("period05")!="") period[5] = server.arg("period05").toInt(); + if(server.arg("period06")!="") period[6] = server.arg("period06").toInt(); + if(server.arg("period07")!="") period[7] = server.arg("period07").toInt(); + if(server.arg("period08")!="") period[8] = server.arg("period08").toInt(); + if(server.arg("period09")!="") period[9] = server.arg("period09").toInt(); + if(server.arg("period10")!="") period[10] = server.arg("period10").toInt(); + if(server.arg("period11")!="") period[11] = server.arg("period11").toInt(); + + if(printCom){ + printTime(); + Serial.println("timeDay: " + String(timeDay) + ", volBrightnessD: " + String(volBrightnessD) + ", timeNight: " + String(timeNight) + ", volBrightnessN: " + String(volBrightnessN) + ", kuOn: " + String(kuOn) + ", kuOff: " + String(kuOff) + ", MAX7219_ROTATE: " + String(MAX7219_ROTATE) + ", clockNight: " + String(clockNight) + ", isActiveBuzzer: "+String(isActiveBuzzer)); + Serial.println(" sensore[0]: "+String(sensore[0])+", sensore[1]: "+String(sensore[1])+", sensore[2]: "+String(sensore[2])+", sensore[3]: "+String(sensore[3])+", sensore[4]: "+String(sensore[4])); + Serial.println(" param0: "+String(param0)+", param1: "+String(param1)+", param2: "+String(param2)+", param3: "+String(param3)+", param4: "+String(param4)); + Serial.println(" func00: "+String(function[0])+", func01: "+String(function[1])+", func02: "+String(function[2])+", func03: "+String(function[3])+", func04: "+String(function[4])+", func05: "+String(function[5])+", func06: "+String(function[6])+", func07: "+String(function[7])+", func08: "+String(function[8])+", func09: "+String(function[9])+", func10: "+String(function[10])+", func11: "+String(function[11])); + Serial.println(" peri00: "+String(period[0])+", peri01: "+String(period[1])+", peri02: "+String(period[2])+", peri03: "+String(period[3])+", peri04: "+String(period[4])+", peri05: "+String(period[5])+", peri06: "+String(period[6])+", peri07: "+String(period[7])+", peri08: "+String(period[8])+", peri09: "+String(period[9])+", peri10: "+String(period[10])+", peri11: "+String(period[11])); + } + saveConfig(); + sensorsAll(); + server.send(200, "text/plain", "OK"); +} + +//====================================================================================================== +void handle_sgp() { + if(isNotVerified()) { + return; + } + if(server.arg("eCo2Led")!="") { + sgpCo2 = server.arg("eCo2Led").toInt(); + } + if(server.arg("sgpCo2LivelAlarm")!="") { + sgpCo2LivelAlarm = server.arg("sgpCo2LivelAlarm").toInt(); + } + if(server.arg("eCo2AlarmEsp")!="") { + eCo2AlarmEsp = server.arg("eCo2AlarmEsp").toInt(); + } + if(server.arg("tvocLed")!="") { + tvocLed = server.arg("tvocLed").toInt(); + } + if(server.arg("sgpTvocLivelAlarm")!="") { + sgpTvocLivelAlarm = server.arg("sgpTvocLivelAlarm").toInt(); + } + if(server.arg("tvocAlarmEsp")!="") { + tvocAlarmEsp = server.arg("tvocAlarmEsp").toInt(); + } + if(server.arg("setSgpCorr")!="") { + setSgpCorr = server.arg("setSgpCorr").toInt(); + } + if(setSgpCorr == 99) { + if(server.arg("sgpCorrTemp")!="") { + sgpCorrTemp = server.arg("sgpCorrTemp").toFloat(); + } + if(server.arg("sgpCorrHumi")!="") { + sgpCorrHumi = server.arg("sgpCorrHumi").toFloat(); + } + } + if(printCom) { + printTime(); + Serial.println("Set eCo2Led: " + String(eCo2Led) + ", sgpCo2LivelAlarm: " + String(sgpCo2LivelAlarm) + ", eCo2AlarmEsp: " + String(eCo2AlarmEsp)); + Serial.print(" tvocLed: " + String(tvocLed) + ", sgpTvocLivelAlarm: " + String(sgpTvocLivelAlarm) + ", tvocAlarmEsp: " + String(tvocAlarmEsp)+ ", setSgpCorr: " + String(setSgpCorr)); + if(setSgpCorr == 99) { + if(printCom) { + Serial.println(", sgpCorrTemp: " + String(sgpCorrTemp) + ", sgpCorrMan: " + String(sgpCorrHumi)); + } + } else { + if(printCom) { + Serial.println(""); + } + } + } + + saveConfig(); + server.send(200, "text/plain", "OK"); +} + +//====================================================================================================== +void handleMessage() { + if(isNotVerified()) { + return; + } + if(server.arg("text") != "") { + server.send(200, "text/plain", "OK"); + String text = server.arg("text").c_str(); + bip(3); + printStringWithShift((space + String(text) + space).c_str(), timeScrollSpeed); + if(printCom) { + printTime(); + Serial.println(text); + } + } +} + +//====================================================================================================== +void handle_stopAlarm(){ + if(isNotVerified()) { + return; + } + if(server.arg("stopAlarm")=="ok") { + if(alarm_stat) { + stopAlarm = true; + if(printCom) { + printTime(); + Serial.println("STOP ALARM"); + } + bip(); + } + } + server.send(200, "text/plain", "OK"); +} + +//====================================================================================================== +void handle_resetConfig() { + if(isNotVerified()) { + return; + } + if(server.arg("device") == "ok") { + SPIFFS.remove("/config.json"); + if(printCom) { + printTime(); + Serial.println("ESP erase Config file"); + } + delay(3000); + server.send(200, "text/plain", "OK"); + delay(3000); + bip(); + ESP.reset(); + } +} + +//====================================================================================================== +void handle_set_printCom() { + if(isNotVerified()) { + return; + } + if(server.arg("printCom")!=""){ + printCom = server.arg("printCom").toInt(); + if(printCom){ + printTime(); + Serial.println("Set printCom: " + String(printCom)); + } + saveConfig(); + } + server.send(200, "text/plain", "OK"); +} + +//====================================================================================================== +void handle_Restart(){ + if(isNotVerified()) { + return; + } + if(server.arg("device") == "ok"){ + server.send(200, "text/plain", "OK"); + ESP.reset(); + } +} diff --git a/WiFi_Clock.ino b/WiFi_Clock.ino new file mode 100644 index 0000000..30f4be7 --- /dev/null +++ b/WiFi_Clock.ino @@ -0,0 +1,1570 @@ + +#define ver "0.1" + +#define DIN_PIN 13 //GPIO 13 / D7 +#define CS_PIN 15 //GPIO 15 / D8 +#define CLK_PIN 14 //GPIO 14 / D5 +#define buzzerPin 12 //GPIO 12 / D6 + +#define MAX_DIGITS 16 + +#define BUT_PIN 16 + +#define brightPin A0 + +// заглушки +void printTime(); +void printStringWithShift(const char* s, int shiftDelay); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Adafruit_SGP30.h" + +#include "globals.h" +#include "soundModule.h" +#include "max7219.h" +#include "fonts.h" +#include "rtc.h" + + +// WEB страницы +#include "P_js.h" +#include "P_css.h" +#include "P_index.h" +#include "P_time.h" +#include "P_weath.h" +#include "P_setup.h" +#include "P_sgp.h" +#include "P_help.h" +#include "P_auth.h" +#include "P_wifi.h" + +Ticker blinker; +ESP8266HTTPUpdateServer httpUpdater; +WiFiClient ESPclient; +ESP8266WebServer server(80); // Веб сервер +File fsUploadFile; +IPAddress apIP(192, 168, 4, 1); + +// ===================================================================================== +String ssid[2] = {"LocalWire"}; // Назва локального WiFi +String password[2] = {"12345678"}; // Пароль локального WiFi +String ssidAP = "WiFi-Clock"; // Назва точки доступу +String passwordAP = "11223344"; +String auth = "1234asdf5678"; + +// переменные сервера погоды +String weatherHost0 = "api.weatherbit.io"; +String weatherHost1 = "api.openweathermap.org"; +String weatherKey0 = ""; +String weatherKey1 = ""; +String cityID0 = "Kyiv"; +String cityID1 = "703448"; +boolean authOn = true; +boolean weatherHost = 0; +char personalCityName[51] = ""; +String weatherLang = "uk"; // Мова отримання прогнозу погоди +String location_name = ""; +String location_region = ""; +String location_country = ""; +String location_localtime = ""; +float location_temp; +float location_app_temp; +int location_rh; +float location_pres; +float location_wind_spd; +String location_wind_cdir_full = ""; +String location_sunrise = ""; +String location_sunset = ""; +int location_clouds; +int location_vis; +int location_uv; +String location_weather_description = ""; +String cityName; + +String weatherString; +String weatherStringZ; +bool animNotWeather = true; + +// -------------------------------------------- +String uuid = ""; +String api_key = ""; +int sensors_ID0 = 3300; //88733 Frankfurt +int sensors_ID1 = 0; //88459 Frankfurt +int sensors_ID2 = 0; +float nMon00 = 0.0; +float nMon01 = 0.0; +float nMon02 = 0.0; + +// ===================================================================================== +byte function[12] = {1, 2, 1, 3, 1, 4, 5, 6, 7, 8, 0, 0}; +byte period[12] = {10, 5, 10, 1, 10, 5, 5, 5, 5, 5, 0, 0}; +byte fnCount = 0; +byte oldCount = 0; +unsigned long fnTimer; +bool endString = true; + + +// индикаторы + +byte fontCLOCK = 8; // 0-крупный, 1-крупный цифровой, 2-полу жирный, 3-полу жирный цифровой, 4-обычный, 5-обычный цифровой, 6-узкий, 7-узкий цифровой. +byte animPoint = 4; +byte aliData = 8; +byte volBrightnessD = 8; +byte volBrightnessN = 2; +bool volBrightnessAuto = 0; +byte levelBridhtness = 0; +int lowLivelBrightness = 0; +int upLivelBrightness = 1023; +byte timeDay = 7; +byte timeNight = 21; + +byte timeStartViewWeather = 6; +byte timeEndViewWeather = 23; +byte timeScrollSpeed = 20; + +// ---------- Настройка оновлення часу +IPAddress timeServerIP; +String ntpServerName = "ntp3.time.in.ua"; +const int NTP_PACKET_SIZE = 48; +byte packetBuffer[NTP_PACKET_SIZE]; + + +bool stopAlarm = false; + +int pinDHT = 2; + +SimpleDHT22 dht22; + +boolean WIFI_connected = false; + + +WiFiUDP udp; +unsigned int localPort = 2390; +unsigned long epochNM; + +#define LEAP_YEAR(Y) (((1970+Y)>0) && !((1970+Y)%4) && (((1970+Y)%100)||!((1970+Y)%400))) // Високосні літа + +String jsonConfig = "{}"; +String jsonAlarm = "{}"; +String jsonTime = "{}"; + +// ---------- Змінні для роботи локального годинника +float timeZone = 2.0; // часовий пояс +float hourCorr; +bool isDayLightSaving = true; +int displayData = 1; // 0 - Не отображать, 1 - отображать статику, 2 - отображать в бегущей строке +long localEpoc = 0; +long localMillisAtUpdate = 0; + +int g_hour, g_minute, g_second, g_month = 1, g_day, g_dayOfWeek, g_year; + +bool statusUpdateNtpTime = 0; // якщо не "0" - то останнє оновленя часу було вдалим +String y, mon, wd, d, h, m, s, mes; +uint8_t hourTest[3], minuteTest[3]; + +String date; + +bool clockNight = 0; + +// ---------- +byte dig[MAX_DIGITS] = {0}; +byte digold[MAX_DIGITS] = {0}; +byte digtrans[MAX_DIGITS] = {0}; +int dx = 0; +int dy = 0; +byte del = 0; + +bool updateOTAEnable = 1; +// пароль обновления +String passwordOTA = "11223344"; + + +#include "sgpModule.h" + + +unsigned long minCount; +unsigned long minCount2; +unsigned long weatherCount; +unsigned long weatherZCount; +bool displayForecast = true; +bool displayCityName = true; // отображать название города +bool displayForecastNow = true; // отображать прогноз на сейчас +bool displayForecastToday = true; // отображать прогноз на сегодня +bool displayForecastTomorrow = true; // отображать прогноз на завтра +bool updateForecastNot = true; +int updateForecast = 0; +int updateForecasttomorrow = 0; + +float data00; // данные первого датчика +float data01; // данные второго датчика +float data02; // данные третьего датчика +float data03; // данные 4 датчика +float data04; // данные пятого датчика + +bool pressSys = 1; +byte humidity; // влажность для прогноза +float pressure; // давление для прогноза +float temp; // температура для прогноза + +bool ds18b20Found = false; +bool dhtFound = false; + +float tempDht = 0; +float humiDht = 0; + +float corr00 = 0; +float corr01 = 0; +float corr02 = 0; +float corr03 = 0; +float corr04 = 0; + +byte sensore[5] = {10,6,7,10,0}; //NONE=0, DS18B20=1, Si7021=2, BMP280=3, BME280=4, DHT=5, MQTT1=6, MQTT2=7, MQTT3=8; =9, AHTx0=10, THING1=11, THING2=12, THING3=13, THING4=14, THING5=15, nMon00=16, nMon00=17, nMon00=18,; +byte param0 = 0; // 0-темп.дом(tD), 1-темп.улица(tU), 2-темп.Н(tН), 3-(tT), 4-(tL) +byte param1 = 1; // 10-влажность1(hD), 11-(h1), 12-(h2), 13-(h3), 14-(h4) +byte param2 = 2; // 20-давление(P), 21-целое число(С) 22-батарейка(V), 23-батарейка(A) +byte param3 = 10; +byte param4 = 20; + + +//bool setTMes = true; +bool alarm_stat = 0; +bool alarm_hold = 0; +byte alarm_numer = 255; +byte alarme[5][3] {{12, 30, 0}, {7, 15, 0}, {22, 55, 0}, {0, 30, 0}, {0, 0, 0}}; //1-часы, 2-минуты, 3-откл(0)/1раз(11)/пон-пят(8)/пон-сб(9)/сб-вс(10)/вс(1)/пон(2)/вто(3)/сре(4)/чет(5)/пят(6)/сб(7)/всегда(12) + +bool firstStart = 0; +bool apStart=0; +byte amountNotStarts = 0; +String jsonLine = ""; + +bool rtcStat = false; + + + +byte errorRTC; +bool butStat = 0; +byte butMode = 0; // 0 - не нажата, 1 - нажата один раз, 2 - нажата два раза, 3 - 5 секунд нажата, 4 - 30 секунд нажата. +byte butFlag = 0; // 1 - кнопка нажата, 0 - не нажата +int butCount = 0; // счетчик времени нажатия кнопки +int butMillis = 0; +bool runningLine = 0; + +String tJanuary, tFebruary, tMarch, tApril, tMay, tJune, tJuly, tAugust, tSeptember, tOctober, tNovember, tDecember; +String tMonday, tTuesday, tWednesday, tThursday, tFriday, tSaturday, tSunday; + +String space = ""; +bool startLine = false; +String textLine; + +//====================================================================================== +void setup() { + Wire.begin(); + Serial.begin(115200); + if (printCom) { + Serial.println(""); + } + pinMode(BUT_PIN, INPUT); + digitalWrite(BUT_PIN, !butStat); + delay(500); + SPIFFS.begin(); + loadConfig(); + loadAlarm(); + + initLang(); + initMAX7219(); + sendCmdAll(CMD_SHUTDOWN, 1); + sendCmdAll(CMD_INTENSITY, 1); + + // задаем количество пробелов в зависимости от кол-ва знаков + for(int i = 0; i < MAX7219_NUM; i++) { + space += " "; + } + + Wire.beginTransmission(0x67); + errorRTC = Wire.endTransmission(); + if (errorRTC == 0) { + rtcAddr = 0x67; + if(printCom) { + Serial.println("YES!!! find RTC module addr: 0x67!"); + } + } else { + Wire.beginTransmission(0x68); + errorRTC = Wire.endTransmission(); + if(errorRTC == 0) { + rtcAddr = 0x68; + if(printCom) { + Serial.println("YES!!! find RTC module addr: 0x68!"); + } + } else { + rtcStat = false; + } + } + if(rtcStat) { + if(printCom) { + Serial.println("RTC START"); + } + getRTCDateTime(); + hour = rtcStruct.hour; + minute = rtcStruct.minute; + second = rtcStruct.second; + day = rtcStruct.day; + month = rtcStruct.month; + year = rtcStruct.year; + dayOfWeek = rtcStruct.dayOfWeek; + if (printCom) { + Serial.println("RTC update: " + String(hour) + ":" + String(minute) + ":" + String(second) + " " + String(day) + "." + String(month) + "." + String(year) + " D=" + String(dayOfWeek)); + } + } else if (printCom) { + Serial.println("RTC module off!"); + } + + // ------------------ + sensorsDht(); + + sensors(); + server_init(); + // ---------- + localMillisAtUpdate = millis(); + localEpoc = (hour * 60 * 60 + minute * 60 + second); + udp.begin(localPort); + pinMode(buzzerPin, OUTPUT); + // ---------- Підключення до WiFi + wifiConnect(); + blinker.attach(0.05, ledPrint); + // *********** OTA SETUP + + if(updateOTAEnable) { + ArduinoOTA.setPort(8266); + ArduinoOTA.setHostname("ESP-ZAL"); + //ArduinoOTA.setPassword((const char *)"123"); + ArduinoOTA.onEnd([](){ESP.restart();}); + ArduinoOTA.onError([](ota_error_t error) { + Serial.printf("Error[%u]: ", error); + if (error == OTA_AUTH_ERROR && printCom) { + Serial.println("Auth Failed"); + } else if (error == OTA_BEGIN_ERROR && printCom) { + Serial.println("Begin Failed"); + } else if (error == OTA_CONNECT_ERROR && printCom) { + Serial.println("Connect Failed"); + } else if (error == OTA_RECEIVE_ERROR && printCom) { + Serial.println("Receive Failed"); + } else if (error == OTA_END_ERROR && printCom) { + Serial.println("End Failed"); + } + ESP.restart(); + }); + ArduinoOTA.begin(); + } + if (WiFi.status() == WL_CONNECTED) { + if (displayForecast) { + if (!weatherHost) { + getWeatherData0(); + getWeatherDataz0(); + } else { + getWeatherData1(); + getWeatherDataz1(); + } + } + } + + if(!sgp.begin()){ + if(printCom){ + Serial.println("Sensor SGP-30 not found :("); + } + sgpFound = false; + } else { + if(printCom){ + printTime(); + Serial.print("Found SGP30 serial #"); + Serial.print(sgp.serialnumber[0], HEX); + Serial.print(sgp.serialnumber[1], HEX); + Serial.println(sgp.serialnumber[2], HEX); + } + sgpFound = true; + } +} + +//====================================================================================== +void reconnect(){ + if(printCom) { + printTime(); + Serial.println("Start Reconnect void..."); + } + if(WiFi.status() == WL_CONNECTED) { // && !ESPclient.connected() + if(printCom) { + printTime(); + Serial.print("MQTT reconnection..."); + } + } +} +void ledPrint(){ + updateTime(); + if(endString){ + if(function[fnCount]==1) showAnimClock(); + if(!startLine){ + if(function[fnCount]==2){ + if(displayData==1){ + showSimpleDate(); + } else if(displayData==2 && hour>=timeStartViewWeather && hour=timeStartViewWeather && hour=timeDay && hour<=timeNight):(hour>=timeDay || hour 30 && updateForecast < 360) weatherString = space + tWeatrTN + " - " + String(updateForecast) + "мин." + space; + else if(updateForecast >= 360) weatherString = space + tWeatrNot + space; + textLine=weatherString; + if(updateForecasttomorrow<30) textLine+=weatherStringZ; + startLine=true; + } + //} else fnTimer=millis(); + } else fnTimer=millis(); + } else if(function[fnCount]>3 && function[fnCount]<9){ + if(sensore[function[fnCount]-4]){ + showSimple(function[fnCount]-4); + } else fnTimer=millis(); + } + } + } +} +//====================================================================================== +//====================================================================================== +void loop() { + // дозволяємо HTTP серверу відповідать на запити + server.handleClient(); + + if(updateOTAEnable) { + ArduinoOTA.handle(); + } + + if(fnTimer < millis() && endString) { + fnCount++; + if(fnCount >= 12) { + fnCount=0; + } + fnTimer = millis() + (period[fnCount] * 1000); + } + if(startLine) { + printStringWithShift(textLine.c_str(), timeScrollSpeed); + startLine = false; + } + + buttonInter(); + + // сигнал кожду годину + checkNeedHourSound(); + if(secFr==0 && second==10 && !alarm_stat) { + sensorsAll(); + } + //----------- РОБОТА З БУДИЛЬНИКОМ------------------------------------------------------ + if(secFr==0) { + if(second>0 && alarms()){ + if(!alarm_stat && alarm_numer!=255 && !alarm_hold) alarm_stat=1; + } else if(alarm_stat){ + alarm_stat=0; + if(alarme[alarm_numer][2]==11) alarme[alarm_numer][2]=0; + } else if(alarm_hold!=0); + } + if(alarm_stat){ + if(secFr==0 && second>1 && second<=59){ + invert(); + refreshAll(); + bip(); + bip(); + } + } + //------------- РОБОТА З ЯСКРАВІСТЮ ЕКРАНУ -------------------------------- + if(secFr==0){ + if(volBrightnessAuto){ + //levelBridhtness = map(analogRead(brightPin), 1023, 0, 0, 15); + int br=analogRead(brightPin); + if(lowLivelBrightness<=upLivelBrightness){ + if(brupLivelBrightness) upLivelBrightness=br; + } else{ + if(brlowLivelBrightness) lowLivelBrightness=br; + } + levelBridhtness=map(br,lowLivelBrightness, upLivelBrightness, volBrightnessN, volBrightnessD); + sendCmdAll(CMD_INTENSITY, levelBridhtness); + } else{ + if(hour>=timeDay && hour 0 ? 1 : -1)) % 10; + int znak = znakT % 10; + byte digPos[10] {3, 4, 5, 6, 17, 18, 19, 20, 21, 22}; + byte indent = aliData * (MAX7219_NUM - 4); + dx = dy = 0; + clr(); + showDigit((temp0 < 0.0 ? digPos[znak*2+1]:digPos[znak*2]), indent, znaki5x8); // друкуємо D+ альбо D- + if(temp1 <= -10.0 || temp1 >= 10) showDigit((temp1 < 0 ? (temp1 * -1) / 10 : temp1 / 10), 4 + indent, dig5x8); + showDigit((temp1 < 0 ? (temp1 * -1) % 10 : temp1 % 10), 10 + indent, dig5x8); + showDigit(2, 16 + indent, znaki5x8); + showDigit(temp2, 18 + indent, dig5x8); + showDigit(0, 24 + indent, znaki5x8); + showDigit(1, 27 + indent, znaki5x8); + refreshAll(); +} + +//==========ВИВІД НА ЕКРАН ВОЛОГОСТІ======================================== +void showSimpleHumidity(byte znakT, float humi0){ + if(humi0>0){ + int humi1 = int(humi0); + int humi2 = int(humi0*10*(humi0>0?1:-1))%10; + int znak = znakT%10; + byte digPos[5] {7, 23, 24, 25, 26}; + byte indent = aliData * (MAX7219_NUM - 4); + dx = dy = 0; + clr(); + showDigit(digPos[znak], indent, znaki5x8); // друкуємо знак вологості + if (humi1 >= 10) showDigit(humi1/10, 6 + indent, dig5x8); + showDigit((humi1-(humi1/10)*10), 12 + indent, dig5x8); + showDigit(2, 18 + indent, znaki5x8); + showDigit(humi2, 20 + indent, dig5x8); + showDigit(8, 26 + indent, znaki5x8); + refreshAll(); + } +} + +//==========ВИВІД НА ЕКРАН ТИСКУ======================================== +void showSimplePressure(byte znakT, float press0){ + if(pressSys==1 && press0>815) press0 /= 1.3332239; + if(pressSys!=1 && press0<815) press0 /= 0.7500615613026439; + if(press0 > 0){ + int press1 = (int) press0 / 1000; + int press2 = ((int) press0 - press1 * 1000) / 100; + int press3 = ((int) press0 - press1 * 1000 - press2 * 100) / 10; + int press4 = (int)press0 % 10; + byte indent = aliData * (MAX7219_NUM - 4); + dx = dy = 0; + clr(); + showDigit(9, 0 + indent, znaki5x8); // друкуємо знак тиску + if(press1 > 0) showDigit(press1, 5 + indent, dig5x8); + showDigit(press2, (press1 > 0 ? 10 : 6) + indent, dig5x8); + showDigit(press3, (press1 > 0 ? 16 : 12) + indent, dig5x8); + showDigit(press4, (press1 > 0 ? 22 : 18) + indent, dig5x8); + showDigit((pressSys == 1 ? 10 : 15), (press1 > 0 ? 28 : 24) + indent, znaki5x8); + showDigit((pressSys == 1 ? 11 : 16), (press1 > 0 ? (pressSys == 1 ? 33 : 32) : (pressSys == 1 ? 29 : 28)) + indent, znaki5x8); + refreshAll(); + } +} + +//==========ВИВІД НА ЕКРАН ДОДАТКОВИХ ДАННИХ======================================== +void showSimpleNumeric(byte znakT, float numer0) { + byte indent = aliData * (MAX7219_NUM - 4); + dx = dy = 0; + clr(); + showDigit((numer0 < 0.0 ? 32 : 31), 0 + indent, znaki5x8); + float numer1 = numer0 * (numer0 >= 0 ? 1 : -1); + if (numer1 >= 10000) { + showDigit((int)numer1 % 10, 28 + indent, dig4x8); + showDigit((int)(numer1 / 10) % 10, 23 + indent, dig4x8); + showDigit((int)(numer1 / 100) % 10, 18 + indent, dig4x8); + showDigit((int)(numer1 / 1000) % 10, 13 + indent, dig4x8); + showDigit((int)(numer1 / 10000) % 10, 8 + indent, dig4x8); + } else if (numer1 >= 1000) { + showDigit((int)(numer1 * 10) % 10, 28 + indent, dig4x8); + showDigit(2, 26 + indent, znaki5x8); + showDigit((int)numer1 % 10, 21 + indent, dig4x8); + showDigit((int)(numer1 / 10) % 10, 16 + indent, dig4x8); + showDigit((int)(numer1 / 100) % 10, 11 + indent, dig4x8); + showDigit((int)(numer1 / 1000) % 10, 6 + indent, dig4x8); + } else { + showDigit((int)(numer1 * 100) % 10, 28 + indent, dig4x8); + showDigit((int)(numer1 * 10) % 10, 23 + indent, dig4x8); + showDigit(2, 21 + indent, znaki5x8); + showDigit((int)numer1 % 10, 16 + indent, dig4x8); + if (numer1 >= 10) showDigit((int)(numer1 / 10) % 10, 11 + indent, dig4x8); + if (numer1 >= 100) showDigit((int)(numer1 / 100) % 10, 6 + indent, dig4x8); + } + refreshAll(); +} + +//==========ВИВІД НА ЕКРАН ДАТИ========================================================= +void showSimpleDate() { + bool nonsens = false; + byte digPos[8] {0, 5, 10, 12, 17, 22, 23, 28}; + if(year % 10 == 1) { + digPos[6]++; + if(month%10 == 1) { + digPos[3]++; + digPos[2]++; + digPos[1]++; + digPos[0]++; + } + if(month / 10 == 1) { + digPos[2]++; + digPos[1]++; + digPos[0]++; + } + if(day % 10 == 1) { + digPos[0]++; + } + } else { + if(month % 10 == 1) { + digPos[5]--; + digPos[4]--; + } else if(month / 10 == 1) { + digPos[5]--; + digPos[4]--; + digPos[3]--; + } + if(month % 10 == 1 && month / 10 == 1) { + digPos[2]++; + digPos[1]++; + digPos[0]++; + } + if(month % 10 != 1 && month / 10 != 1 && (day % 10 == 1 || day / 10 == 1)) { + digPos[5]--; + digPos[4]--; + digPos[3]--; + digPos[2]--; + digPos[1]--; + } else if(day % 10 == 1) { + digPos[0]++; + } + if(month % 10 != 1 && month / 10 != 1 && day % 10 != 1 && day / 10 == 1) { + nonsens = true; + } + } + byte indent = aliData * (MAX7219_NUM - 4); + dx = dy = 0; + clr(); + showDigit(nonsens?10:day / 10, digPos[0] + indent, dig4x8); + showDigit(day % 10, digPos[1] + indent, dig4x8); + showDigit(2, digPos[2] + indent, znaki5x8); + showDigit(month / 10, digPos[3] + indent, dig4x8); + showDigit(month % 10, digPos[4] + indent, dig4x8); + showDigit(2, digPos[5] + indent, znaki5x8); + showDigit((year - 2000) / 10, digPos[6] + indent, dig4x8); + showDigit((year - 2000) % 10, digPos[7] + indent, dig4x8); + refreshAll(); +} + +//==========ВИВІД НА ЕКРАН АНІМАЦІЙНОГО ГОДИННИКА======================================= +void showAnimClock() { + if(fontCLOCK > 7) { + showAnimClock2(); + return; + } + byte indent = (hour < 10 ? 12 : 15) + 4 * (MAX7219_NUM - 4); + byte digPos[5] = {(indent-(fontCLOCK<2?14:fontCLOCK<6?12:10)), (indent-(fontCLOCK<2?7:fontCLOCK<6?6:5)), (indent+3), (indent+(fontCLOCK<2?10:fontCLOCK<6?9:8)), indent}; + int digHt = 16; + int num=hour<10?1:0; + int i; + if(del==0){ + del=digHt; + for(i=num; i<4; i++) digold[i]=dig[i]; + dig[0]=hour/10; + dig[1]=hour%10; + dig[2]=minute/10; + dig[3]=minute%10; + for(i=num; i<4; i++) digtrans[i]=(dig[i]==digold[i])?0:digHt; + } else del--; + clr(); + for(i=num; i<4; i++){ + if(digtrans[i]==0){ + dy=0; + if(fontCLOCK==0) showDigit(dig[i], digPos[i], dig6x8); + else if(fontCLOCK==1) showDigit(dig[i], digPos[i], dig6x8dig); + else if(fontCLOCK==2) showDigit(dig[i], digPos[i], dig5x8rn); + else if(fontCLOCK==3) showDigit(dig[i], digPos[i], dig5x8rndig); + else if(fontCLOCK==4) showDigit(dig[i], digPos[i], dig5x8); + else if(fontCLOCK==5) showDigit(dig[i], digPos[i], dig5x8dig); + else if(fontCLOCK==6) showDigit(dig[i], digPos[i], dig4x8); + else if(fontCLOCK==7) showDigit(dig[i], digPos[i], dig4x8dig); + } else{ + dy=digHt-digtrans[i]; + if(fontCLOCK==0) showDigit(digold[i], digPos[i], dig6x8); + else if(fontCLOCK==1) showDigit(digold[i], digPos[i], dig6x8dig); + else if(fontCLOCK==2) showDigit(digold[i], digPos[i], dig5x8rn); + else if(fontCLOCK==3) showDigit(digold[i], digPos[i], dig5x8rndig); + else if(fontCLOCK==4) showDigit(digold[i], digPos[i], dig5x8); + else if(fontCLOCK==5) showDigit(digold[i], digPos[i], dig5x8dig); + else if(fontCLOCK==6) showDigit(digold[i], digPos[i], dig4x8); + else if(fontCLOCK==7) showDigit(digold[i], digPos[i], dig4x8dig); + dy=-digtrans[i]; + if(fontCLOCK==0) showDigit(dig[i], digPos[i], dig6x8); + else if(fontCLOCK==1) showDigit(dig[i], digPos[i], dig6x8dig); + else if(fontCLOCK==2) showDigit(dig[i], digPos[i], dig5x8rn); + else if(fontCLOCK==3) showDigit(dig[i], digPos[i], dig5x8rndig); + else if(fontCLOCK==4) showDigit(dig[i], digPos[i], dig5x8); + else if(fontCLOCK==5) showDigit(dig[i], digPos[i], dig5x8dig); + else if(fontCLOCK==6) showDigit(dig[i], digPos[i], dig4x8); + else if(fontCLOCK==7) showDigit(dig[i], digPos[i], dig4x8dig); + digtrans[i]--; + } + } + dy=0; + int flash=millis()%2000; + if(animPoint%2) flash=flash%1000; + else flash=flash/2; + if (!alarm_stat){ + if(!WIFI_connected){ + if(flash<500){ + setCol(digPos[4], 0xC0); setCol(digPos[4]+1, 0xC0); // полная точка + } + } else if(!statusUpdateNtpTime){ + if(flash<149){ + setCol(digPos[4], 0x66); setCol(digPos[4]+1, 0x66); + } + } else if(animPoint<3){ // Простая + if(flash<499 || animPoint==0){ + setCol(digPos[4], 0x66); setCol(digPos[4]+1, 0x66); + } + } else if(animPoint==3 || animPoint==4){ // MAX1 + if(flash<500){ + setCol(digPos[4], 0x62); setCol(digPos[4]+1, 0x62); + } else{ + setCol(digPos[4], 0x46); setCol(digPos[4]+1, 0x46); + } + } else if(animPoint==5 || animPoint==6){ // MAX2 + if((flash>=200 && flash<400) || flash>=600){ + setCol(digPos[4], 0x66); setCol(digPos[4]+1, 0x66); + } + if(flash>=0 && flash<200){ + setCol(digPos[4], 0x24); setCol(digPos[4]+1, 0x24); + } + if(flash>=400 && flash<600){ + setCol(digPos[4], 0x42); setCol(digPos[4]+1, 0x42); + } + } else if(animPoint==7 || animPoint==8){ // Мерцание + if((flash>=(animPoint==5?180:200) && flash<(animPoint==5?360:400)) || flash>=(animPoint==5?540:600)){ + setCol(digPos[4], 0x66); setCol(digPos[4]+1, 0x66); + } + if(flash>=0 && flash<(animPoint==5?180:200)){ + setCol(digPos[4], 0x24); setCol(digPos[4]+1, 0x42); + } + if(flash>=(animPoint==5?360:400) && flash<(animPoint==5?540:600)){ + setCol(digPos[4], 0x42); setCol(digPos[4]+1, 0x24); + } + } else if(animPoint==9 || animPoint==10){ // Вращение + if(flash<250){ + setCol(digPos[4], 0x06); setCol(digPos[4]+1, 0x60); + } else if(flash>=250 && flash<500){ + setCol(digPos[4], 0x42); setCol(digPos[4]+1, 0x42); + } else if(flash>=500 && flash<750){ + setCol(digPos[4], 0x60); setCol(digPos[4]+1, 0x06); + } else if(flash>=750){ + setCol(digPos[4], 0x24); setCol(digPos[4]+1, 0x24); + } + } + if(displayForecast && updateForecast && WIFI_connected) { + setCol(00, flash<500?0x80:0x00); + } + if(displayForecastTomorrow && displayForecast && updateForecasttomorrow && WIFI_connected) { + setCol((MAX7219_NUM*8-1), flash < 500 ? 0x80 : 0x00); + } + } else { + setCol(digPos[4], 0x66); + setCol(digPos[4]+1, 0x66); + } + refreshAll(); +} + +//========================================================================================= +void showAnimClock2() { + int num = hour < 10 ? 1 : 0; + int indent = 4 * (MAX7219_NUM - 4) / 2 - (1 * num); + byte digPos[6] = {0, 6, 13, 19, 25, 29}; + int digHt=16; + int i; + if(del==0){ + del=digHt; + for(i=num; i<4; i++) digold[i]=dig[i]; + dig[0]=hour/10; + dig[1]=hour%10; + dig[2]=minute/10; + dig[3]=minute%10; + for(i=num; i<4; i++) digtrans[i]=(dig[i]==digold[i])?0:digHt; + } else del--; + clr(); + for(i=num; i<4; i++){ + if(digtrans[i]==0){ + dy=0; + showDigit(dig[i], digPos[i]+indent-(i==1&&num?2:0), fontCLOCK==8?dig5x8sec:dig5x7sec); + } else{ + dy=digHt-digtrans[i]; + showDigit(digold[i], digPos[i]+indent-(i==1&&num?2:0), fontCLOCK==8?dig5x8sec:dig5x7sec); + dy=-digtrans[i]; + showDigit(dig[i], digPos[i]+indent-(i==1&&num?2:0), fontCLOCK==8?dig5x8sec:dig5x7sec); + digtrans[i]--; + } + } + dy=0; + int flash=millis()%2000; + flash=flash/2; + if (!alarm_stat) { + if(flash<500) { + setCol(11+indent-(num?1:0), 0x80); + } else { + setCol(12+indent-(num?1:0), 0x80); + } + if(displayForecast && updateForecast && WIFI_connected) { + setCol(00, flash<500?0x80:0x00); + } + if(displayForecastTomorrow && displayForecast && updateForecasttomorrow && WIFI_connected) { + setCol((MAX7219_NUM*8-1), flash<500?0x80:0x00); + } + } else { + setCol(11+indent-(num?1:0), 0x80); + setCol(12+indent-(num?1:0), 0x80); + } + showDigit((second/10)%10, digPos[4]+indent+(num?1:0), fontCLOCK==8?dig3x7:dig3x6); + showDigit(second%10, digPos[5]+indent+(num?1:0), fontCLOCK==8?dig3x7:dig3x6); + refreshAll(); +} + +//================================================= +void showAnimWifi(byte probaWifi) { + byte digPos[2] = {18, 25}; + int digHt = 16; + int num = 2; + int ii; + if (del == 0) { + del = digHt; + for (ii = 0; ii < num; ii++) digold[ii] = dig[ii]; + dig[0] = probaWifi / 10; + dig[1] = probaWifi % 10; + for (ii = 0; ii < num; ii++) digtrans[ii] = (dig[ii] == digold[ii]) ? 0 : digHt; + } else del--; + clr(); + for (ii = 0; ii < num; ii++) { + if (digtrans[ii] == 0) { + dy = 0; + showDigit(dig[ii], digPos[ii], dig6x8); + } else { + dy = digHt - digtrans[ii]; + showDigit(digold[ii], digPos[ii], dig6x8); + dy = - digtrans[ii]; + showDigit(dig[ii], digPos[ii], dig6x8); + digtrans[ii]--; + } + } + dy = 0; + refreshAll(); +} + +//==========ДРУКУВАННЯ БІГУЧОЇ СТРОКИ *s - текст, shiftDelay - швидкість========================================== +void printStringWithShift(const char* s, int shiftDelay) { + endString=false; + while(*s){ // коли працює ця функція, основний цикл зупиняється + printCharWithShift(*s, shiftDelay); + s++; + if (updateOTAEnable) { + ArduinoOTA.handle(); + } + server.handleClient(); // зберігаемо можливість відповіді на HTML запити під час бігучої стоки + buttonInter(); + if (butMode != 0) { + clr(); + refreshAll(); + runningLine = 0; + return; + } + } + endString=true; +} + +//==========ДРУКУВАННЯ БІГУЧОГО СИМВОЛУ с - символ, shiftDelay - швидкість===================================== +void printCharWithShift(unsigned char c, int shiftDelay) { + c = convert_UA_RU_PL_DE(c); + if (c < ' ') return; + c -= 32; + int w = showChar(c, fontUA_RU_PL_DE); + for (int i = 0; i < w + 1; i++) { + delay(shiftDelay); + scrollLeft(); + refreshAll(); + } +} + +//====================================================================================== +int showChar(char ch, const uint8_t *data) { + int len = pgm_read_byte(data); + int i, w = pgm_read_byte(data + 1 + ch * len); + for (i = 0; i < w; i++) + scr[MAX7219_NUM * 8 + i] = pgm_read_byte(data + 1 + ch * len + 1 + i); + scr[MAX7219_NUM * 8 + i] = 0; + return w; +} + +//====================================================================================== +void showDigit(char ch, int col, const uint8_t *data) { + if (dy < -8 | dy > 8) return; + int len = pgm_read_byte(data); + int w = pgm_read_byte(data + 1 + ch * len); + col += dx; + for (int i = 0; i < w; i++) { + if (col + i >= 0 && col + i < 8 * MAX7219_NUM) { + byte v = pgm_read_byte(data + 1 + ch * len + 1 + i); + if (!dy) scr[col + i] = v; else scr[col + i] |= dy > 0 ? v >> dy : v << -dy; + } + } +} + +//====================================================================================== +void setCol(int col, byte v) { + if (dy < -8 | dy > 8) return; + col += dx; + if (col >= 0 && col < 8 * MAX7219_NUM) { + if (!dy) scr[col] = v; else scr[col] |= dy > 0 ? v >> dy : v << -dy; + } +} + +//========== +void saveChrMas(String string_t, byte lenght_off, byte number_s) { + byte lenght = string_t.length(); + if (lenght > lenght_off) return; + const char *s = string_t.c_str(); + + for (int i = 0; i < lenght; i++) { + //snprintf(*memory_date_mes[number_s], 1, "%s", *s); + s++; + } +} + +//==========ОНОВЛЕННЯ ЛОКАЛЬНОГО ЧАСУ (ЛОКАЛЬНІ ЧАСИ)=============================================================== +void updateTime(){ + long curEpoch=localEpoc+((millis()-localMillisAtUpdate)/1000); + long epoch=round(curEpoch+86400L); + epoch=(epoch%86400L); + hour=((epoch%86400L)/3600)%24; + minute=(epoch%3600)/60; + second=epoch%60; + if(second!=lastSecond) { + // на початку нової секунди скидаємо secFr в "0" + lastSecond=second; + secFr=0; + if(lastMinute!=minute){ + if(hour==0 && minute==0 && second==0){ + day++; + if(day==32 || (day==31 && (month==4 || month==6 || month==9 || month==11)) || (month==2 && ((day==29 && year%4!=0) || (day==30 && year%4==0)))){ + day=1; + month++; + if(month>12){ + month=1; + year++; + } + } + dayOfWeek++; + if(dayOfWeek>7) dayOfWeek=1; + } + lastMinute=minute; + } + } else secFr++; +} + +//==========ОНОВЛЕННЯ МЕРЕЖЕВОГО ЧАСУ (перевірка в три проходи)==================================================== +void timeUpdateNTP() { + if (!WIFI_connected) { + return; + } + if (printCom) { + printTime(); + } + statusUpdateNtpTime = 1; + for (int timeTest = 0; timeTest < 3; timeTest++) { + getNTPtime(); + if (printCom) { + if (timeTest) Serial.print(" "); + Serial.println("Proba #" + String(timeTest + 1) + " " + String(g_hour) + ":" + ((g_minute < 10) ? "0" : "") + String(g_minute) + ":" + ((g_second < 10) ? "0" : "") + String(g_second)); + } + // updateTime(); + + hourTest[timeTest] = g_hour; + minuteTest[timeTest] = (g_minute || (g_minute == 59 ? 0 : g_minute++)); + if (statusUpdateNtpTime == 0) { + if (printCom) { + printTime(); + Serial.print("ERROR TIME!!!\r\n"); + } + return; + } + if (timeTest > 0) { + if ((hourTest[timeTest] != hourTest[timeTest - 1] || minuteTest[timeTest] != minuteTest[timeTest - 1])) { + statusUpdateNtpTime = 0; + if (printCom) { + printTime(); + Serial.print("ERROR TIME!!!\r\n"); + } + return; + } + } + } + hour = g_hour; + minute = g_minute; + second = g_second; + day = g_day; + dayOfWeek = g_dayOfWeek; + month = g_month; + year = g_year; + if (rtcStat) { + rtcStruct.hour = hour; + rtcStruct.minute = minute; + rtcStruct.second = 0; + rtcStruct.year = year; + rtcStruct.month = month; + rtcStruct.day = day; + rtcStruct.dayOfWeek = dayOfWeek; + setRTCDateTime(); + } + localMillisAtUpdate = millis(); + localEpoc = (hour * 60 * 60 + minute * 60 + second); +// saveTime(); + if (printCom) { + printTime(); + Serial.println((day < 10 ? "0" : "") + String(day) + "." + (month < 10 ? "0" : "") + String(month) + "." + String(year) + " DW = " + String(dayOfWeek)); + Serial.println(" Time update OK."); + } +} + +//==========ОТРИМАННЯ ДАТИ ТА ЧАСУ ВІД СЕРВЕРА ТОЧНОГО ЧАСУ ============================================================= +void getNTPtime() { + WiFi.hostByName(ntpServerName.c_str(), timeServerIP); + int cb; + for (int i = 0; i < 3; i++) { + memset(packetBuffer, 0, NTP_PACKET_SIZE); + packetBuffer[0] = 0b11100011; + packetBuffer[1] = 0; + packetBuffer[2] = 6; + packetBuffer[3] = 0xEC; + packetBuffer[12] = 49; + packetBuffer[13] = 0x4E; + packetBuffer[14] = 49; + packetBuffer[15] = 52; + udp.beginPacket(timeServerIP, 123); //NTP порт 123 + udp.write(packetBuffer, NTP_PACKET_SIZE); + udp.endPacket(); + delay(800); // чекаємо пів секуни + cb = udp.parsePacket(); + if (!cb && printCom) Serial.println(" no packet yet..." + String (i + 1)); + if (!cb && i == 2) { // якщо час не отримано + statusUpdateNtpTime = 0; + return; // вихіз з getNTPtime() + } + if (cb) i = 3; + } + if (cb) { // якщо отримали пакет з серверу + udp.read(packetBuffer, NTP_PACKET_SIZE); + unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); + unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); + unsigned long secsSince1900 = highWord << 16 | lowWord; + const unsigned long seventyYears = 2208988800UL; // Unix час станом на 1 січня 1970. в секундах, то 2208988800: + unsigned long epoch = secsSince1900 - seventyYears; + epochNM = epoch - (millis() / 1000); + boolean summerTime; + if (month < 3 || month > 10) summerTime = false; // не переходимо на літній час в січні, лютому, листопаді і грудню + if (month > 3 && month < 10) summerTime = true; // Sommerzeit лічимо в квіні, травні, червені, липні, серпені, вересені + if (month == 3 && (hour + 24 * day) >= (3 + 24 * (31 - (5 * year / 4 + 4) % 7)) || month == 10 && (hour + 24 * day) < (3 + 24 * (31 - (5 * year / 4 + 1) % 7))) summerTime = true; + epoch += (int)(timeZone * 3600 + (3600 * (isDayLightSaving && summerTime))); + hourCorr = timeZone + (isDayLightSaving && summerTime); + g_year = 0; + int days = 0; + uint32_t time; + time = epoch / 86400; + g_hour = (epoch % 86400L) / 3600; + g_minute = (epoch % 3600) / 60; + g_second = epoch % 60; + g_dayOfWeek = (((time) + 4) % 7) + 1; + while ((unsigned)(days += (LEAP_YEAR(g_year) ? 366 : 365)) <= time) { + g_year++; + } + days -= LEAP_YEAR(g_year) ? 366 : 365; + time -= days; + days = 0; + g_month = 0; + uint8_t monthLength = 0; + for (g_month = 0; g_month < 12; g_month++) { + if (g_month == 1) { + if (LEAP_YEAR(g_year)) monthLength = 29; + else monthLength = 28; + } + else monthLength = monthDays[g_month]; + if (time >= monthLength) time -= monthLength; + else break; + } + g_month++; + g_day = time + 1; + g_year += 1970; + return; + } + if (printCom) Serial.println("Nie ma czasu((("); +} + +//========================================================================================================= +void wifiConnect() { + if (printCom) { + printTime(); + Serial.print("Connecting WiFi (ssid0=" + String(ssid[0].c_str()) + " pass0=" + String(password[0].c_str()) + ") "); + } + if(WiFi.status() == WL_CONNECTED){ + WIFI_connected = true; + if(printCom) Serial.print(" IP adress : "); + if(printCom) Serial.println(WiFi.localIP()); + firstStart=1; + timeUpdateNTP(); + amountNotStarts=0; + return; + } + if (!firstStart) printStringWithShift("WiFi", 15); + WiFi.disconnect(); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid[0].c_str(), password[0].c_str()); + for (int i = 1; i < 21; i++) { + if (WiFi.status() == WL_CONNECTED){ + WiFi.setAutoConnect(true); + WiFi.setAutoReconnect(true); + WIFI_connected = true; + if(printCom) Serial.print(" IP adress : "); + if(printCom) Serial.println(WiFi.localIP()); + if(!firstStart){ + String aaa=WiFi.localIP().toString() + space; + clr(); + printStringWithShift(" IP: ", 15); + printStringWithShift(aaa.c_str(), 25); + } + firstStart=1; + timeUpdateNTP(); + amountNotStarts=0; + return; + } + if(printCom) Serial.print("."); + if(!firstStart){ + int j=0; + while (j<500){ + if(j%10==0) showAnimWifi(i); + j++; + delay(1); + } + } + delay (800); + } + if (printCom) { + printTime(); + Serial.print("/nConnecting WiFi (ssid1=" + String(ssid[1].c_str()) + " pass1=" + String(password[1].c_str()) + ") "); + } + if (!firstStart) printStringWithShift("WiFi", 15); + WiFi.disconnect(); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid[1].c_str(), password[1].c_str()); + for (int i = 1; i < 21; i++) { + if (WiFi.status() == WL_CONNECTED) { + WIFI_connected = true; + if(printCom) Serial.print(" IP adress : "); + if(printCom) Serial.println(WiFi.localIP()); + if(!firstStart){ + String aaa=WiFi.localIP().toString() + space; + clr(); + printStringWithShift(" IP: ", 15); + printStringWithShift(aaa.c_str(), 25); + } + firstStart=1; + timeUpdateNTP(); + amountNotStarts=0; + return; + } + if(printCom) Serial.print("."); + if(!firstStart){ + int j=0; + while (j<500){ + if(j%10==0) showAnimWifi(i); + j++; + delay(1); + } + } + delay (800); + } + WiFi.disconnect(); + if (printCom) Serial.println(" Not connected!!!"); + amountNotStarts++; + if (printCom) { + Serial.print("Amount of the unsuccessful connecting = "); + Serial.println(amountNotStarts); + } + if (amountNotStarts > 21) { + amountNotStarts = 0; + firstStart = 0; + ESP.reset(); + } + if (!firstStart) { + WiFi.mode(WIFI_AP); + WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); + WiFi.softAP(ssidAP.c_str(), passwordAP.c_str()); + if (printCom) { + printTime(); + Serial.println("Start AP mode!!!"); + Serial.print(" Wifi AP IP : "); + Serial.println(WiFi.softAPIP()); + } + updateTime(); + String aaa = tPoint + " " + ssidAP; + if(passwordAP != "") aaa += ", " + tPass + ": " + passwordAP; + aaa += ", " + tIp + ": 192.168.4.1"; + clr(); + printStringWithShift(aaa.c_str(), 35); + //firstStart=1; + } +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void sensorsAll() { + if(printCom) Serial.println("======== START GET SENSORS DATA ======================="); + sensorsDht(); + sensors(); + if(printCom) Serial.println("======== END =========================================="); +} + +//------------------------------------------------------------------------- +void sensors() { + data00 = (sensore[0]==0?0:sensore[0]==5?(param0>4?humiDht:tempDht):0); + if(sensore[0]) { + data00 += corr00; + } + data01 = (sensore[1]==0?0:sensore[1]==5?(param1>4?humiDht:tempDht):0); + if(sensore[1]) { + data01 += corr01; + } + if(printCom){ + if(sensore[0]){ + printTime(); + Serial.println("sensore[0](+corr) = " + String(data00)); + } + if(sensore[1]){ + printTime(); + Serial.println("sensore[1](+corr) = " + String(data01)); + } + } + if(setSgpCorr){ + if(setSgpCorr==4 && dhtFound){ + sgpCorrTemp = tempDht; + sgpCorrHumi = humiDht; + } + } + + if((sensore[0]==5 && sensore[2]==5 && dhtFound)){ + if(param4==21&&sensore[4]==99){ + float absH=(6.112*(pow(2.718281828,(17.67*data00)/(data00+243.5)))*data02*2.1674)/(273.15+data00); + if(printCom){ + printTime(); + Serial.println("Absolute Humi = " + String(absH) + "g/m3"); + } + data04=absH; + } + if(param3==3&&sensore[3]==99){ + float ans=(data00-(14.55+0.114*data00)*(1-(0.01*data02))-pow(((2.5+0.007*data00)*(1-(0.01*data02))),3)-(15.9+0.117*data00)*pow((1-(0.01*data02)),14)); + if(printCom){ + printTime(); + Serial.println("Dew point = " + String(ans) + "*C"); + } + data03=ans; + } + } +} + +//-------------------------------------------------------------------------- +void sensorsDht() { //5 + dhtFound=false; + int err = SimpleDHTErrSuccess; + int err2 = SimpleDHTErrSuccess; + byte temp11 = 0; + byte humi11 = 0; + if((err2 = dht22.read2(pinDHT, &tempDht, &humiDht, NULL)) == SimpleDHTErrSuccess) { + humiDht = int(humiDht); + if(printCom) { + printTime(); + Serial.println("Temperature DHT22: " + String(tempDht) + " *C, Humidity: " + String(humiDht) + " %"); + } + dhtFound=true; + } +} + +void printTime() { + if (printCom) { + Serial.print((hour < 10 ? "0" : "") + String(hour) + ":" + (minute < 10 ? "0" : "") + String(minute) + ":" + (second < 10 ? "0" : "") + String(second) + " "); + } +} + +//-------------------------------------------------------------------------- +byte alarms() { + for (byte i = 0; i < 5; i++) { + if (alarme[i][0] == hour && alarme[i][1] == minute && (alarme[i][2] == dayOfWeek || (alarme[i][2] == 8 && (dayOfWeek > 1 && dayOfWeek < 7)) || (alarme[i][2] == 9 && dayOfWeek > 1) || (alarme[i][2] == 10 && (dayOfWeek == 1 || dayOfWeek == 7)) || alarme[i][2] > 10)) { + alarm_numer = i; + return 1; + } + } + alarm_numer = 255; + return 0; +} + +//------------ function urlencode for weather parameters -------------------- +String urlencode(String str) { // функция взята от http://forum.amperka.ru/members/benben.19545/ + String encodedString = ""; + char c; + char code0; + char code1; + for (int i = 0; i < str.length(); i++) { + c = str.charAt(i); + if (c == ' ') { + encodedString += '+'; + } else if (isalnum(c)) { + encodedString += c; + } else { + code1 = (c & 0xf) + '0'; + if ((c & 0xf) > 9) { + code1 = (c & 0xf) - 10 + 'A'; + } + c = (c >> 4) & 0xf; + code0 = c + '0'; + if (c > 9) { + code0 = c - 10 + 'A'; + } + encodedString += '%'; + encodedString += code0; + encodedString += code1; + } + yield(); + } + return encodedString; +} + +//------------ function chr_to_str -------------------- +String chr_to_str(String str) { + String chr_to_str = ""; + for (int i = 0; i < str.length(); i++) { + chr_to_str += str.charAt(i); + } + return chr_to_str; +} + +//--------------------------------------------------------------------------- +void buttonInter() { + if (digitalRead(BUT_PIN) == butStat && butCount == 0 && butFlag == 0 && butMode == 0) { + butCount = millis(); + butFlag = 1; + } + if ((millis() - butCount) >= 30000 && butFlag == 1 && butMode == 0) { + butMode = 4; + butFlag = 0; + butCount = 0; + } + if (digitalRead(BUT_PIN) == !butStat && (millis() - butCount) >= 10000 && butFlag == 1 && butMode == 0) { + butMode = 3; + butFlag = 0; + butCount = 0; + } + if (digitalRead(BUT_PIN) == !butStat && (millis() - butCount) < 10000 && (millis() - butCount) > 800 && (butFlag == 1 || butFlag == 2) && butMode == 0) { + butMode = 1; + butFlag = 0; + butCount = 0; + } + if (digitalRead(BUT_PIN) == !butStat && (millis() - butCount) <= 800 && butFlag == 1 && butMode == 0) { + butFlag = 2; + } + if (digitalRead(BUT_PIN) == butStat && (millis() - butCount) <= 800 && butFlag == 2) { + butMode = 2; + butFlag = 0; + butCount = 0; + } +} + +//---------------------------------------------------------------- +void buttonHandling() { + if (alarm_stat && (butMode || stopAlarm)) { // если будильник работает, то любое нажатие выключает его + alarm_stat = 0; + alarm_hold = 1; + stopAlarm = false; + butMode = 0; + if (alarme[alarm_numer][2] == 11) { + alarme[alarm_numer][2] = 0; + } + } + if (butMode == 4) { // если кнопка нажата была более 30 секунд то возврат к заводским установкам + butMode = 0; + Serial.println("Ta to jest KAPUT!!!!!!"); + bip(); + bip(); + bip(); + bip(); + SPIFFS.remove("/config.json"); + if (printCom) { + printTime(); + Serial.println("ESP erase Config file"); + } + delay(3000); + ESP.reset(); + } + if (butMode == 3) { // если кнопка была нажата более 10 секунд но менее 30, то будет рестарт часов + butMode = 0; + Serial.println("Reset ESP!!!"); + bip(); + bip(); + bip(); + ESP.reset(); + } + if (butMode == 1) { + bip(); + clr(); + refreshAll(); + if(sensore[0]) { + showSimple(0); + delay(1500); + } + if(sensore[1]) { + showSimple(1); + delay(1500); + } + if(sensore[2]) { + showSimple(2); + delay(1500); + } + if(sensore[3]) { + showSimple(3); + delay(1500); + } + if(sensore[4]) { + showSimple(4); + delay(1500); + } + butMode = 0; + clr(); + refreshAll(); + } + if (butMode == 2) { // При двойном нажатии на кнопку выводится прогноз погоды + bip(); + bip(); + butMode = 0; + clr(); + refreshAll(); + printStringWithShift(weatherString.c_str(), timeScrollSpeed); + printStringWithShift(weatherStringZ.c_str(), timeScrollSpeed); + clr(); + refreshAll(); + } +} diff --git a/fileSystem.ino b/fileSystem.ino new file mode 100644 index 0000000..43dca32 --- /dev/null +++ b/fileSystem.ino @@ -0,0 +1,121 @@ +//====================================== Тут функції для роботи з файловою системою +String getContentType(String filename) { + if (server.hasArg("download")) { + return "application/octet-stream"; + } else if (filename.endsWith(".htm") || filename.endsWith(".html") || filename.endsWith(".vz")) { + return "text/html"; + } else if (filename.endsWith(".json")) { + return "application/json"; + } else if (filename.endsWith(".css")) { + return "text/css"; + } else if (filename.endsWith(".js")) { + return "application/javascript"; + } else if (filename.endsWith(".png")) { + return "image/png"; + } else if (filename.endsWith(".gif")) { + return "image/gif"; + } else if (filename.endsWith(".jpg")) { + return "image/jpeg"; + } else if (filename.endsWith(".ico")) { + return "image/x-icon"; + } else if (filename.endsWith(".xml")) { + return "text/xml"; + } else if (filename.endsWith(".pdf")) { + return "application/x-pdf"; + } else if (filename.endsWith(".zip")) { + return "application/x-zip"; + } else if (filename.endsWith(".gz")) { + return "application/x-gzip"; + } + return "text/plain"; +} + +//======================================= Читання файлу +bool handleFileRead(String path) { + if (path.endsWith("/")) path += "index.htm"; + String contentType = getContentType(path); + String pathWithGz = path + ".gz"; + if (SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) { + if (SPIFFS.exists(pathWithGz)) + path += ".gz"; + File file = SPIFFS.open(path, "r"); + size_t sent = server.streamFile(file, contentType); + file.close(); + return true; + } + return false; +} + +//======================================== Завантаження файлу +void handleFileUpload() { + if (server.uri() != "/edit") return; + HTTPUpload& upload = server.upload(); + if (upload.status == UPLOAD_FILE_START) { + String filename = upload.filename; + if (!filename.startsWith("/")) filename = "/" + filename; + fsUploadFile = SPIFFS.open(filename, "w"); + filename = String(); + } else if (upload.status == UPLOAD_FILE_WRITE) { + if (fsUploadFile) + fsUploadFile.write(upload.buf, upload.currentSize); + } else if (upload.status == UPLOAD_FILE_END) { + if (fsUploadFile) + fsUploadFile.close(); + } +} + +//======================================== Видалення файлу +void handleFileDelete() { + if (server.args() == 0) return server.send(500, "text/plain", "BAD ARGS"); + String path = server.arg(0); + if (path == "/") + return server.send(500, "text/plain", "BAD PATH"); + if (!SPIFFS.exists(path)) + return server.send(404, "text/plain", "FileNotFound"); + SPIFFS.remove(path); + server.send(200, "text/plain", ""); + path = String(); +} + +//========================================= Створення файлу +void handleFileCreate() { + if (server.args() == 0) + return server.send(500, "text/plain", "BAD ARGS"); + String path = server.arg(0); + if (path == "/") + return server.send(500, "text/plain", "BAD PATH"); + if (SPIFFS.exists(path)) + return server.send(500, "text/plain", "FILE EXISTS"); + File file = SPIFFS.open(path, "w"); + if (file) + file.close(); + else + return server.send(500, "text/plain", "CREATE FAILED"); + server.send(200, "text/plain", ""); + path = String(); +} + +//========================================== Список файлів +void handleFileList() { + if (!server.hasArg("dir")){ + server.send(500, "text/plain", "BAD ARGS"); + return; + } + String path = server.arg("dir"); + Dir dir = SPIFFS.openDir(path); + path = String(); + String output = "["; + while (dir.next()) { + File entry = dir.openFile("r"); + if (output != "[") output += ','; + bool isDir = false; + output += "{\"type\":\""; + output += (isDir) ? "dir" : "file"; + output += "\",\"name\":\""; + output += String(entry.name()).substring(1); + output += "\"}"; + entry.close(); + } + output += "]"; + server.send(200, "text/json", output); +} diff --git a/fonts.h b/fonts.h new file mode 100644 index 0000000..040053a --- /dev/null +++ b/fonts.h @@ -0,0 +1,418 @@ +const uint8_t znaki5x8[] PROGMEM = { 6, +0x02, 0x03,0x03,0x00,0x00,0x00, // градус +0x05, 0x7E,0x81,0x81,0xc3,0x42, // C +0x01, 0xC0,0x00,0x00,0x00,0x00, // . +0x03, 0xF2,0x97,0x62,0x00,0x00, // +D +0x03, 0xF2,0x92,0x62,0x00,0x00, // -D +0x03, 0xB2,0xA7,0x72,0x00,0x00, // +U +0x03, 0xB2,0xA2,0x72,0x00,0x00, // -U +0x05, 0x78,0x84,0x83,0x84,0x78, // кропля +0x05, 0x83,0x63,0x18,0xC6,0xC1, // % +0x05, 0x88,0x90,0xbf,0x90,0x88, // тиск +0x04, 0xff,0x08,0x08,0xff,0x00, // H +0x03, 0x98,0xa4,0x78,0x00,0x00, // g +0x05, 0x20,0xBC,0x7E,0x3C,0x20, // колокол л +0x05, 0x20,0x3C,0x7E,0xBC,0x20, // колокол п +0x02, 0xC0,0xC0,0x00,0x00,0x00, // . жирная +0x05, 0x7F,0x08,0x70,0x00,0x00, // h +0x05, 0x7f,0x09,0x09,0x06,0x00, // P +0x03, 0xF2,0x27,0xF2,0x00,0x00, // +H +0x03, 0xF2,0x22,0xF2,0x00,0x00, // -H +0x03, 0x12,0xF7,0x12,0x00,0x00, // +T +0x03, 0x12,0xF2,0x12,0x00,0x00, // -T +0x03, 0x72,0x47,0x42,0x00,0x00, // +L +0x03, 0xF2,0x82,0x82,0x00,0x00, // -L +0x05, 0x78,0xFC,0xFF,0xFC,0x78, // кропля1 (полная) +0x05, 0x78,0xE3,0xE4,0xE3,0x78, // кропля2 (низ) +0x05, 0x78,0xFC,0xFF,0x84,0x78, // кропля3 (лева) +0x05, 0x78,0xFC,0xC7,0xFC,0x78, // кропля4 (центр) +0x05, 0xFE,0xF3,0xF3,0xF3,0xFE, // батарейка +0x05, 0xE8,0xCC,0xAA,0x19,0x08, // молния +0x05, 0x3F,0x40,0x80,0x40,0x3F, // вольты +0x05, 0xFC,0x12,0x11,0x12,0xFC, // амперы +0x03, 0x62,0x97,0x92,0x00,0x00, // +C +0x03, 0x62,0x92,0x92,0x00,0x00, // -C +}; +//========================================== +const uint8_t dig3x6[] PROGMEM = { 4, +0x03, 0x3C, 0x42, 0x3C, //0 +0x03, 0x44, 0x7E, 0x40, //1 +0x03, 0x64, 0x52, 0x4C, //2 +0x03, 0x22, 0x4A, 0x34, //3 +0x03, 0x1E, 0x10, 0x7E, //4 +0x03, 0x2E, 0x4A, 0x32, //5 +0x03, 0x3C, 0x4A, 0x32, //6 +0x03, 0x62, 0x12, 0x0E, //7 +0x03, 0x34, 0x4A, 0x34, //8 +0x03, 0x4C, 0x52, 0x3C //9 +}; +//========================================== +const uint8_t dig3x7[] PROGMEM = { 4, +0x03, 0x7C, 0x82, 0x7C, //0 +0x03, 0x84, 0xFE, 0x80, //1 +0x03, 0xE4, 0x92, 0x8C, //2 +0x03, 0x44, 0x92, 0x6C, //3 +0x03, 0x1E, 0x10, 0xFE, //4 +0x03, 0x4E, 0x8A, 0x72, //5 +0x03, 0x7C, 0x92, 0x64, //6 +0x03, 0xE2, 0x12, 0x0E, //7 +0x03, 0x6C, 0x92, 0x6C, //8 +0x03, 0x4C, 0x92, 0x7C //9 +}; +//========================================== +const uint8_t dig4x8[] PROGMEM = { 5, +0x04, 0x7E,0x81,0x81,0x7E, +0x04, 0x00,0x82,0xFF,0x80, +0x04, 0xC2,0xA1,0x91,0x8E, +0x04, 0x42,0x89,0x89,0x76, +0x04, 0x1C,0x12,0x11,0xFF, +0x04, 0x4F,0x89,0x89,0x71, +0x04, 0x7E,0x89,0x89,0x72, +0x04, 0x01,0xF1,0x09,0x07, +0x04, 0x76,0x89,0x89,0x76, +0x04, 0x46,0x89,0x89,0x7E +}; +//========================================== +const uint8_t dig4x8dig[] PROGMEM = { 5, +0x04, 0xFF,0x81,0x81,0xFF, +0x04, 0x00,0x00,0xFF,0x00, +0x04, 0xF9,0x89,0x89,0x8F, +0x04, 0x81,0x89,0x89,0xFF, +0x04, 0x0F,0x08,0x08,0xFF, +0x04, 0x8F,0x89,0x89,0xF9, +0x04, 0xFF,0x89,0x89,0xF9, +0x04, 0x01,0x01,0x01,0xFF, +0x04, 0xFF,0x89,0x89,0xFF, +0x04, 0x8F,0x89,0x89,0xFF +}; +//====================================================================================================== +const uint8_t dig5x8[] PROGMEM = { 6, +0x05, 0x7E,0x81,0x81,0x81,0x7E, //0 +0x05, 0x00,0x82,0xFF,0x80,0x00, //1 +0x05, 0xE2,0x91,0x91,0x89,0xC6, //2 +0x05, 0x42,0x89,0x89,0x89,0x76, //3 +0x05, 0x38,0x24,0x22,0xF1,0x20, //4 +0x05, 0x47,0x89,0x89,0x89,0x71, //5 +0x05, 0x7E,0x89,0x89,0x89,0x72, //6 +0x05, 0x01,0x01,0xF1,0x09,0x07, //7 +0x05, 0x76,0x89,0x89,0x89,0x76, //8 +0x05, 0x46,0x89,0x89,0x89,0x7E //9 +}; +//========================================== +const uint8_t dig5x8dig[] PROGMEM = { 6, +0x05, 0xFF,0x81,0x81,0x81,0xFF, +0x05, 0x00,0x00,0x00,0xFF,0x00, +0x05, 0xF9,0x89,0x89,0x89,0x8F, +0x05, 0x89,0x89,0x89,0x89,0xFF, +0x05, 0x0F,0x08,0x08,0x08,0xFF, +0x05, 0x8F,0x89,0x89,0x89,0xF9, +0x05, 0xFF,0x89,0x89,0x89,0xF9, +0x05, 0x01,0x01,0x01,0x01,0xFF, +0x05, 0xFF,0x89,0x89,0x89,0xFF, +0x05, 0x8F,0x89,0x89,0x89,0xFF +}; +//=========================================== +const uint8_t dig5x8rn[] PROGMEM = { 6, +0x05, 0x7E, 0x81, 0x81, 0xFF, 0x7E, //0 +0x05, 0x04, 0x02, 0xFF, 0xFF, 0x00, //1 +0x05, 0xF1, 0x89, 0x89, 0x8F, 0x86, //2 +0x05, 0x81, 0x89, 0x89, 0xFF, 0x76, //3 +0x05, 0x1F, 0x10, 0x10, 0xFE, 0xFE, //4 +0x05, 0x8F, 0x89, 0x89, 0xF9, 0x71, //5 +0x05, 0x7E, 0x89, 0x89, 0xF9, 0x70, //6 +0x05, 0x01, 0xC1, 0xF1, 0x3F, 0x0F, //7 +0x05, 0x76, 0x89, 0x89, 0xFF, 0x76, //8 +0x05, 0x0E, 0x91, 0x91, 0xFF, 0x7E //9 +}; +//========================================== +const uint8_t dig5x8rndig[] PROGMEM = { 6, +0x05, 0xFF,0x81,0x81,0xFF,0xFF, //0 +0x05, 0x00,0x00,0xFF,0xFF,0x00, //1 +0x05, 0xF9,0x89,0x89,0x8F,0x8F, //2 +0x05, 0x89,0x89,0x89,0xFF,0xFF, //3 +0x05, 0x0F,0x08,0x08,0xFF,0xFF, //4 +0x05, 0x8F,0x89,0x89,0xF9,0xF9, //5 +0x05, 0xFF,0x89,0x89,0xF9,0xF9, //6 +0x05, 0x01,0x01,0x01,0xFF,0xFF, //7 +0x05, 0xFF,0x89,0x89,0xFF,0xFF, //8 +0x05, 0x8F,0x89,0x89,0xFF,0xFF //9 +}; +//====================================================================================================== +const uint8_t dig5x7sec[] PROGMEM = { 6, +0x05, 0x3E,0x7F,0x41,0x7F,0x3E, // 0 +0x05, 0x00,0x42,0x7F,0x7F,0x40, // 1 +0x05, 0x62,0x73,0x59,0x4F,0x46, // 2 +0x05, 0x22,0x63,0x49,0x7F,0x36, // 3 +0x05, 0x18,0x1C,0x16,0x7F,0x7F, // 4 +0x05, 0x2F,0x6F,0x49,0x79,0x31, // 5 +0x05, 0x3E,0x7F,0x49,0x7B,0x32, // 6 +0x05, 0x01,0x71,0x79,0x0F,0x07, // 7 +0x05, 0x36,0x7F,0x49,0x7F,0x36, // 8 +0x05, 0x26,0x6F,0x49,0x7F,0x3E // 9 +}; +//====================================================================================================== +const uint8_t dig5x8sec[] PROGMEM = { 6, +0x05, 0x7E,0xFF,0x81,0xFF,0x7E, // 0 +0x05, 0x00,0x82,0xFF,0xFF,0x80, // 1 +0x05, 0xC2,0xE3,0xB1,0x9F,0x8E, // 2 +0x05, 0x42,0xC3,0x89,0xFF,0x76, // 3 +0x05, 0x38,0x3C,0x26,0xFF,0xFF, // 4 +0x05, 0x4F,0xCF,0x89,0xF9,0x71, // 5 +0x05, 0x7E,0xFF,0x89,0xFB,0x72, // 6 +0x05, 0x01,0xE1,0xF1,0x1F,0x0F, // 7 +0x05, 0x76,0xFF,0x89,0xFF,0x76, // 8 +0x05, 0x4E,0xDF,0x91,0xFF,0x7E // 9 +}; +//====================================================================================================== +const uint8_t dig6x8[] PROGMEM = { 7, +0x06, 0x7E,0xFF,0x81,0x81,0xFF,0x7E, +0x06, 0x00,0x82,0xFF,0xFF,0x80,0x00, +0x06, 0xC2,0xE3,0xB1,0x99,0x8F,0x86, +0x06, 0x42,0xC3,0x89,0x89,0xFF,0x76, +0x06, 0x38,0x3C,0x26,0x23,0xFF,0xFF, +0x06, 0x4F,0xCF,0x89,0x89,0xF9,0x71, +0x06, 0x7E,0xFF,0x89,0x89,0xFB,0x72, +0x06, 0x01,0x01,0xF1,0xF9,0x0F,0x07, +0x06, 0x76,0xFF,0x89,0x89,0xFF,0x76, +0x06, 0x4E,0xDF,0x91,0x91,0xFF,0x7E +}; +//========================================== +const uint8_t dig6x8dig[] PROGMEM = { 7, +0x06, 0xFF,0xFF,0x81,0x81,0xFF,0xFF, +0x06, 0x00,0x00,0xFF,0xFF,0x00,0x00, +0x06, 0xF9,0xF9,0x89,0x89,0x8F,0x8F, +0x06, 0x89,0x89,0x89,0x89,0xFF,0xFF, +0x06, 0x0F,0x0F,0x08,0x08,0xFF,0xFF, +0x06, 0x8F,0x8F,0x89,0x89,0xF9,0xF9, +0x06, 0xFF,0xFF,0x89,0x89,0xF9,0xF9, +0x06, 0x01,0x01,0x01,0x01,0xFF,0xFF, +0x06, 0xFF,0xFF,0x89,0x89,0xFF,0xFF, +0x06, 0x8F,0x8F,0x89,0x89,0xFF,0xFF +}; +//====================================================================================================== +const uint8_t fontUA_RU_PL_DE[] PROGMEM = {8, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 32 - 'Space' + 0x01, 0x5f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, // 33 - '!' + 0x03, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, // 34 - '"' + 0x05, 0x14, 0x7f, 0x14, 0x7f, 0x14, 0x00, 0x00, // 35 - '#' + 0x05, 0x24, 0x2a, 0x7f, 0x2a, 0x12, 0x00, 0x00, // 36 - '$' + 0x05, 0x23, 0x13, 0x08, 0x64, 0x62, 0x00, 0x00, // 37 - '%' + 0x05, 0x36, 0x49, 0x56, 0x20, 0x50, 0x00, 0x00, // 38 - '&' + 0x03, 0x08, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, // 39 - ''' + 0x03, 0x1c, 0x22, 0x41, 0x00, 0x00, 0x00, 0x00, // 40 - '(' + 0x03, 0x41, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x00, // 41 - ')' + 0x05, 0x2a, 0x1c, 0x7f, 0x1c, 0x2a, 0x00, 0x00, // 42 - '*' + 0x05, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, // 43 - '+' + 0x03, 0x80, 0x70, 0x30, 0x00, 0x00, 0x00, 0x00, // 44 - ',' + 0x05, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, // 45 - '-' + 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 46 - '.' + 0x05, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, // 47 - '/' + 0x05, 0x3e, 0x51, 0x49, 0x45, 0x3e, 0x00, 0x00, // 48 - '0' + 0x05, 0x00, 0x42, 0x7f, 0x40, 0x00, 0x00, 0x00, // 49 - '1' + 0x05, 0x72, 0x49, 0x49, 0x49, 0x46, 0x00, 0x00, // 50 - '2' + 0x05, 0x21, 0x41, 0x49, 0x4d, 0x33, 0x00, 0x00, // 51 - '3' + 0x05, 0x18, 0x14, 0x12, 0x7f, 0x10, 0x00, 0x00, // 52 - '4' + 0x05, 0x27, 0x45, 0x45, 0x45, 0x39, 0x00, 0x00, // 53 - '5' + 0x05, 0x3c, 0x4a, 0x49, 0x49, 0x31, 0x00, 0x00, // 54 - '6' + 0x05, 0x41, 0x21, 0x11, 0x09, 0x07, 0x00, 0x00, // 55 - '7' + 0x05, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00, // 56 - '8' + 0x05, 0x46, 0x49, 0x49, 0x29, 0x1e, 0x00, 0x00, // 57 - '9' + 0x02, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, // 58 - ':' + 0x02, 0x80, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, // 59 - ';' + 0x04, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00, 0x00, // 60 - '<' + 0x05, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00, // 61 - '=' + 0x04, 0x41, 0x22, 0x14, 0x08, 0x00, 0x00, 0x00, // 62 - '>' + 0x05, 0x02, 0x01, 0x59, 0x09, 0x06, 0x00, 0x00, // 63 - '?' + 0x05, 0x3e, 0x41, 0x5d, 0x59, 0x4e, 0x00, 0x00, // 64 - '@' + 0x05, 0x7c, 0x12, 0x11, 0x12, 0x7c, 0x00, 0x00, // 65 - 'A' + 0x05, 0x7f, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00, // 66 - 'B' + 0x05, 0x3e, 0x41, 0x41, 0x41, 0x22, 0x00, 0x00, // 67 - 'C' + 0x05, 0x7f, 0x41, 0x41, 0x41, 0x3e, 0x00, 0x00, // 68 - 'D' + 0x05, 0x7f, 0x49, 0x49, 0x49, 0x41, 0x00, 0x00, // 69 - 'E' + 0x05, 0x7f, 0x09, 0x09, 0x09, 0x01, 0x00, 0x00, // 70 - 'F' + 0x05, 0x3e, 0x41, 0x41, 0x51, 0x73, 0x00, 0x00, // 71 - 'G' + 0x05, 0x7f, 0x08, 0x08, 0x08, 0x7f, 0x00, 0x00, // 72 - 'H' + 0x03, 0x41, 0x7f, 0x41, 0x00, 0x00, 0x00, 0x00, // 73 - 'I' + 0x05, 0x20, 0x40, 0x41, 0x3f, 0x01, 0x00, 0x00, // 74 - 'J' + 0x05, 0x7f, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00, // 75 - 'K' + 0x05, 0x7f, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, // 76 - 'L' + 0x05, 0x7f, 0x02, 0x1c, 0x02, 0x7f, 0x00, 0x00, // 77 - 'M' + 0x05, 0x7f, 0x04, 0x08, 0x10, 0x7f, 0x00, 0x00, // 78 - 'N' + 0x05, 0x3e, 0x41, 0x41, 0x41, 0x3e, 0x00, 0x00, // 79 - 'O' + 0x05, 0x7f, 0x09, 0x09, 0x09, 0x06, 0x00, 0x00, // 80 - 'P' + 0x05, 0x3e, 0x41, 0x51, 0x21, 0x5e, 0x00, 0x00, // 81 - 'Q' + 0x05, 0x7f, 0x09, 0x19, 0x29, 0x46, 0x00, 0x00, // 82 - 'R' + 0x05, 0x26, 0x49, 0x49, 0x49, 0x32, 0x00, 0x00, // 83 - 'S' + 0x05, 0x03, 0x01, 0x7f, 0x01, 0x03, 0x00, 0x00, // 84 - 'T' + 0x05, 0x3f, 0x40, 0x40, 0x40, 0x3f, 0x00, 0x00, // 85 - 'U' + 0x05, 0x1f, 0x20, 0x40, 0x20, 0x1f, 0x00, 0x00, // 86 - 'V' + 0x05, 0x3f, 0x40, 0x38, 0x40, 0x3f, 0x00, 0x00, // 87 - 'W' + 0x05, 0x63, 0x14, 0x08, 0x14, 0x63, 0x00, 0x00, // 88 - 'X' + 0x05, 0x03, 0x04, 0x78, 0x04, 0x03, 0x00, 0x00, // 89 - 'Y' + 0x05, 0x61, 0x51, 0x49, 0x45, 0x43, 0x00, 0x00, // 90 - 'Z' + 0x03, 0x7f, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, // 91 - '[' + 0x05, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, // 92 - '\' + 0x03, 0x41, 0x41, 0x7f, 0x00, 0x00, 0x00, 0x00, // 93 - ']' + 0x05, 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, 0x00, // 94 - '^' + 0x05, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, // 95 - '_' + 0x02, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, // 96 - '`' + 0x05, 0x20, 0x54, 0x54, 0x78, 0x40, 0x00, 0x00, // 97 - 'a' + 0x05, 0x7f, 0x28, 0x44, 0x44, 0x38, 0x00, 0x00, // 98 - 'b' + 0x05, 0x38, 0x44, 0x44, 0x44, 0x28, 0x00, 0x00, // 99 - 'c' + 0x05, 0x38, 0x44, 0x44, 0x28, 0x7f, 0x00, 0x00, // 100 - 'd' + 0x05, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x00, // 101 - 'e' + 0x04, 0x08, 0x7e, 0x09, 0x02, 0x00, 0x00, 0x00, // 102 - 'f' + 0x05, 0x18, 0xa4, 0xa4, 0x9c, 0x78, 0x00, 0x00, // 103 - 'g' + 0x05, 0x7f, 0x08, 0x04, 0x04, 0x78, 0x00, 0x00, // 104 - 'h' + 0x03, 0x44, 0x7d, 0x40, 0x00, 0x00, 0x00, 0x00, // 105 - 'i' + 0x04, 0x40, 0x80, 0x80, 0x7a, 0x00, 0x00, 0x00, // 106 - 'j' + 0x04, 0x7f, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, // 107 - 'k' + 0x03, 0x41, 0x7f, 0x40, 0x00, 0x00, 0x00, 0x00, // 108 - 'l' + 0x05, 0x7c, 0x04, 0x78, 0x04, 0x78, 0x00, 0x00, // 109 - 'm' + 0x05, 0x7c, 0x08, 0x04, 0x04, 0x78, 0x00, 0x00, // 110 - 'n' + 0x05, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, // 111 - 'o' + 0x05, 0xfc, 0x18, 0x24, 0x24, 0x18, 0x00, 0x00, // 112 - 'p' + 0x05, 0x18, 0x24, 0x24, 0x18, 0xfc, 0x00, 0x00, // 113 - 'q' + 0x05, 0x7c, 0x08, 0x04, 0x04, 0x08, 0x00, 0x00, // 114 - 'r' + 0x05, 0x48, 0x54, 0x54, 0x54, 0x24, 0x00, 0x00, // 115 - 's' + 0x04, 0x04, 0x3f, 0x44, 0x24, 0x00, 0x00, 0x00, // 116 - 't' + 0x05, 0x3c, 0x40, 0x40, 0x20, 0x7c, 0x00, 0x00, // 117 - 'u' + 0x05, 0x1c, 0x20, 0x40, 0x20, 0x1c, 0x00, 0x00, // 118 - 'v' + 0x05, 0x3c, 0x40, 0x30, 0x40, 0x3c, 0x00, 0x00, // 119 - 'w' + 0x05, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, // 120 - 'x' + 0x05, 0x4c, 0x90, 0x90, 0x90, 0x7c, 0x00, 0x00, // 121 - 'y' + 0x05, 0x44, 0x64, 0x54, 0x4c, 0x44, 0x00, 0x00, // 122 - 'z' + 0x03, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, 0x00, // 123 - '{' + 0x01, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 124 - '|' + 0x03, 0x41, 0x36, 0x08, 0x00, 0x00, 0x00, 0x00, // 125 - '}' + 0x05, 0x02, 0x01, 0x02, 0x04, 0x02, 0x00, 0x00, // 126 - '~' + 0x05, 0x3c, 0x26, 0x23, 0x26, 0x3c, 0x00, 0x00, // 127 - 'Hollow Up Arrow' + 0x07, 0x0E, 0x1F, 0x3F, 0x7E, 0x3F, 0x1F, 0x0E, // 128 (200) - heart СЕРЦЕ + 0x07, 0x0E, 0x11, 0x04, 0x7A, 0x04, 0x11, 0x0E, // 129 (201)антена точки доступа + 0x04, 0x06, 0x09, 0x09, 0x06, 0x00, 0x00, 0x00, // 130 (202) - градус цельсия + 0x05, 0x7E, 0x81, 0x81, 0xC3, 0x42, 0x00, 0x00, // 131 (203) - C - большая + 0x05, 0x3e, 0x49, 0x49, 0x49, 0x22, 0x00, 0x00, // 132 - 'Є ukr' + 0x05, 0x7E, 0x02, 0x02, 0x02, 0x01, 0x00, 0x00, // 133 - 'Ґ ukr' + 0x03, 0x41, 0x7f, 0x41, 0x00, 0x00, 0x00, 0x00, // 134 - 'I ukr' + 0x05, 0x01, 0x40, 0x7E, 0x40, 0x01, 0x00, 0x00, // 135 - 'Ї ukr' + 0x05, 0x04, 0x02, 0x7F, 0x02, 0x04, 0x00, 0x00, // 136 (210) - 'стрелка вверх 0 градусов' + 0x05, 0x10, 0x20, 0x7F, 0x20, 0x10, 0x00, 0x00, // 137 (211) - 'стрелка вниз 180 градусов' + 0x05, 0x60, 0xFE, 0xF9, 0xFE, 0x60, 0x00, 0x00, // 138 (212) - 'Градусник' + 0x05, 0x38, 0x44, 0x43, 0x44, 0x38, 0x00, 0x00, // 139 (213) - 'Капелька' + 0x06, 0x24, 0x12, 0x12, 0x24, 0x24, 0x12, 0x00, // 140 (214) - 'Ветер' + 0x05, 0x44, 0x48, 0x5F, 0x48, 0x44, 0x00, 0x00, // 141 (215) - 'Давление' + 0x07, 0x1C, 0x22, 0x22, 0x24, 0x28, 0x24, 0x18, // 142 (216) - 'Облачность' + 0x07, 0x3C, 0x42, 0x95, 0xA1, 0x95, 0x42, 0x3C, // 143 (217) - ' :) ' + 0x07, 0x3C, 0x42, 0xA5, 0x91, 0xA5, 0x42, 0x3C, // 144 (220) - ' :( ' + 0x05, 0x14, 0x3E, 0x55, 0x41, 0x22, 0x00, 0x00, // 145 (221) - 'Евро' + 0x05, 0x14, 0x35, 0x5D, 0x56, 0x14, 0x00, 0x00, // 146 (222) - 'Гривна' + 0x07, 0x64, 0x54, 0x4C, 0x00, 0x08, 0x7F, 0x04, // 147 (223) - 'Злотый' + 0x05, 0x38, 0x54, 0x54, 0x44, 0x28, 0x00, 0x00, // 148 (224) - 'є ukr' + 0x04, 0x7c, 0x04, 0x04, 0x02, 0x00, 0x00, 0x00, // 149 (225) - 'ґ ukr' + 0x03, 0x44, 0x7d, 0x40, 0x00, 0x00, 0x00, 0x00, // 150 (226) - 'i ukr' + 0x03, 0x4A, 0x78, 0x42, 0x00, 0x00, 0x00, 0x00, // 151 (227) - 'ї ukr' + 0x07, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x08, // 152 (230) - 'Стрелка влево 270 градусов' + 0x07, 0x08, 0x08, 0x08, 0x08, 0x2A, 0x1C, 0x08, // 153 (231) - 'Стрелка вправо 90 градусов' + 0x07, 0x40, 0x20, 0x10, 0x09, 0x05, 0x03, 0x0F, // 154 (232) - 'Стрелка 45 градусов' + 0x07, 0x01, 0x02, 0x04, 0x48, 0x50, 0x60, 0x78, // 155 (233) - 'Стрелка 135 градусов' + 0x07, 0x78, 0x60, 0x50, 0x48, 0x04, 0x02, 0x01, // 156 (234) - 'Стрелка 225 градусов' + 0x07, 0x0F, 0x03, 0x05, 0x09, 0x10, 0x20, 0x40, // 157 (235) - 'Стрелка 315 градусов' + 0x06, 0x7c, 0x12, 0x11, 0x12, 0x7c, 0x80, 0x00, // 158 - 'Ą pl' + 0x05, 0x20, 0x54, 0x54, 0x78, 0x80, 0x00, 0x00, // 159 - 'ą pl' + 0x05, 0x70, 0x88, 0x8a, 0x89, 0x50, 0x00, 0x00, // 160 - 'Ć pl' + 0x04, 0x30, 0x48, 0x4a, 0x49, 0x00, 0x00, 0x00, // 161 - 'ć pl' + 0x06, 0x08, 0x7f, 0x44, 0x40, 0x40, 0x40, 0x00, // 162 - 'Ł pl' + 0x03, 0x49, 0x7f, 0x44, 0x00, 0x00, 0x00, 0x00, // 163 - 'ł pl' + 0x05, 0xf8, 0x10, 0x22, 0x41, 0xf8, 0x00, 0x00, // 164 - 'Ń pl' + 0x05, 0x78, 0x10, 0x0a, 0x09, 0x70, 0x00, 0x00, // 165 - 'ń pl' + 0x05, 0x70, 0x88, 0x8a, 0x89, 0x70, 0x00, 0x00, // 166 - 'Ó pl' + 0x05, 0x30, 0x48, 0x4a, 0x49, 0x30, 0x00, 0x00, // 167 - 'ó pl' + 0x05, 0x7f, 0x49, 0x49, 0x49, 0x80, 0x00, 0x00, // 168 - 'Ę pl' + 0x05, 0x38, 0x54, 0x54, 0x54, 0x98, 0x00, 0x00, // 169 - 'ę pl' + 0x05, 0x90, 0xa8, 0xaa, 0xa9, 0x48, 0x00, 0x00, // 170 - 'Ś pl' + 0x05, 0x08, 0x54, 0x56, 0x55, 0x20, 0x00, 0x00, // 171 - 'ś pl' + 0x05, 0x88, 0xc8, 0xaa, 0x99, 0x88, 0x00, 0x00, // 172 - 'Ź pl' + 0x04, 0x48, 0x6a, 0x59, 0x48, 0x00, 0x00, 0x00, // 173 - 'ź pl' + 0x05, 0x44, 0x64, 0x55, 0x4c, 0x44, 0x00, 0x00, // 174 - 'Ż pl' + 0x04, 0x48, 0x6a, 0x58, 0x48, 0x00, 0x00, 0x00, // 175 - 'ż pl' + 0x04, 0x06, 0x09, 0x09, 0x06, 0x00, 0x00, 0x00, // 176 - 'градус Цельсия'' + 0x05, 0xf8, 0x25, 0x22, 0x25, 0xf8, 0x00, 0x00, // 177 - 'Ä' Deutsch + 0x05, 0x20, 0x55, 0x54, 0x54, 0x79, 0x00, 0x00, // 178 - 'ä' Deutsch + 0x05, 0x78, 0x85, 0x84, 0x85, 0x78, 0x00, 0x00, // 179 - 'Ö' Deutsch + 0x05, 0x38, 0x45, 0x44, 0x45, 0x38, 0x00, 0x00, // 180 - 'ö' Deutsch + 0x05, 0x7c, 0x81, 0x80, 0x81, 0x7c, 0x00, 0x00, // 181 - 'Ü' Deutsch + 0x05, 0x3c, 0x41, 0x40, 0x21, 0x7c, 0x00, 0x00, // 182 - 'ü' Deutsch + 0x05, 0x85, 0xff, 0x49, 0x4e, 0x30, 0x00, 0x00, // 183 - 'ß' Deutsch + 0x05, 0x14, 0x14, 0xf7, 0x00, 0xff, 0x00, 0x00, // 184 - 'Right T double all' + 0x05, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, // 185 - 'Right side double' + 0x05, 0x14, 0x14, 0xf4, 0x04, 0xfc, 0x00, 0x00, // 186 - 'Top Right double' + 0x05, 0x14, 0x14, 0x17, 0x10, 0x1f, 0x00, 0x00, // 187 - 'Bot Right double' + 0x05, 0x10, 0x10, 0x1f, 0x10, 0x1f, 0x00, 0x00, // 188 - 'Bot Right double V' + 0x05, 0x14, 0x14, 0x14, 0x14, 0x1f, 0x00, 0x00, // 189 - 'Bot Right double H' + 0x05, 0x10, 0x10, 0x10, 0x10, 0xf0, 0x00, 0x00, // 190 - 'Top Right' + 0x05, 0x00, 0x00, 0x00, 0x1f, 0x10, 0x00, 0x00, // 191 - 'Bot Left' + 0x05, 0x7e, 0x11, 0x11, 0x11, 0x7e, 0x00, 0x00, // 192 - 'А' x0c0 + 0x05, 0x7f, 0x49, 0x49, 0x49, 0x31, 0x00, 0x00, // 193 - 'Б' x0c1 + 0x05, 0x7f, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00, // 194 - 'B' x0c2 + 0x05, 0x7f, 0x01, 0x01, 0x01, 0x03, 0x00, 0x00, // 195 - 'Г' x0c3 + 0x06, 0xc0, 0x7e, 0x41, 0x41, 0x7e, 0xc0, 0x00, // 196 - 'Д' x0c4 + 0x05, 0x7f, 0x49, 0x49, 0x49, 0x41, 0x00, 0x00, // 197 - 'E' x0c5 + 0x05, 0x77, 0x08, 0x7f, 0x08, 0x77, 0x00, 0x00, // 198 - 'Ж' x0c6 + 0x05, 0x41, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00, // 199 - 'З' x0c7 + 0x05, 0x7f, 0x10, 0x08, 0x04, 0x7f, 0x00, 0x00, // 200 - 'И' x0c8 + 0x05, 0x7f, 0x10, 0x09, 0x04, 0x7f, 0x00, 0x00, // 201 - 'Й' x0c9 + 0x05, 0x7f, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00, // 202 - 'K' x0ca + 0x05, 0x40, 0x3e, 0x01, 0x01, 0x7f, 0x00, 0x00, // 203 - 'Л' x0cb + 0x05, 0x7f, 0x02, 0x0c, 0x02, 0x7f, 0x00, 0x00, // 204 - 'M' x0cc + 0x05, 0x7f, 0x08, 0x08, 0x08, 0x7f, 0x00, 0x00, // 205 - 'H' x0cd + 0x05, 0x3e, 0x41, 0x41, 0x41, 0x3e, 0x00, 0x00, // 206 - 'O' x0ce + 0x05, 0x7f, 0x01, 0x01, 0x01, 0x7f, 0x00, 0x00, // 207 - 'П' x0cf + 0x05, 0x7f, 0x09, 0x09, 0x09, 0x06, 0x00, 0x00, // 208 - 'Р' x0d0 + 0x05, 0x3e, 0x41, 0x41, 0x41, 0x22, 0x00, 0x00, // 209 - 'C' x0d1 + 0x05, 0x03, 0x01, 0x7f, 0x01, 0x03, 0x00, 0x00, // 210 - 'T' x0d2 + 0x05, 0x27, 0x48, 0x48, 0x48, 0x3f, 0x00, 0x00, // 211 - 'У' x0d3 + 0x07, 0x1c, 0x22, 0x22, 0x7f, 0x22, 0x22, 0x1c, // 212 - 'Ф' x0d4 + 0x05, 0x63, 0x14, 0x08, 0x14, 0x63, 0x00, 0x00, // 213 - 'X' x0d5 + 0x06, 0x7f, 0x40, 0x40, 0x40, 0x7f, 0xc0, 0x00, // 214 - 'Ц' x0d6 + 0x05, 0x07, 0x08, 0x08, 0x08, 0x7f, 0x00, 0x00, // 215 - 'Ч' x0d7 + 0x05, 0x7f, 0x40, 0x7e, 0x40, 0x7f, 0x00, 0x00, // 216 - 'Ш' x0d8 + 0x06, 0x7f, 0x40, 0x7e, 0x40, 0x7f, 0xc0, 0x00, // 217 - 'Щ' x0d9 + 0x07, 0x03, 0x01, 0x7f, 0x48, 0x48, 0x30, 0x00, // 218 - 'Ъ' x0da + 0x07, 0x7f, 0x48, 0x48, 0x30, 0x00, 0x7F, 0x00, // 219 - 'Ы' x0db + 0x05, 0x7f, 0x48, 0x48, 0x48, 0x30, 0x00, 0x00, // 220 - 'Ь' x0dc + 0x05, 0x22, 0x41, 0x49, 0x49, 0x3e, 0x00, 0x00, // 221 - 'Э' x0dd + 0x06, 0x7f, 0x08, 0x3e, 0x41, 0x41, 0x3e, 0x00, // 222 - 'Ю' x0de + 0x05, 0x46, 0x29, 0x19, 0x09, 0x7f, 0x00, 0x00, // 223 - 'Я' x0df + 0x05, 0x20, 0x54, 0x54, 0x54, 0x78, 0x00, 0x00, // 224 - 'а' x0e0 + 0x05, 0x3c, 0x4a, 0x4a, 0x49, 0x31, 0x00, 0x00, // 225 - 'б' x0e1 + 0x05, 0x7c, 0x54, 0x54, 0x54, 0x28, 0x00, 0x00, // 226 - 'в' x0e2 + 0x04, 0x7c, 0x04, 0x04, 0x0c, 0x00, 0x00, 0x00, // 227 - 'г' x0e3 + 0x06, 0xc0, 0x78, 0x44, 0x44, 0x78, 0xc0, 0x00, // 228 - 'д' x0e4 + 0x05, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x00, // 229 - 'e' x0e5 + 0x05, 0x6c, 0x10, 0x7c, 0x10, 0x6c, 0x00, 0x00, // 230 - 'ж' x0e6 + 0x05, 0x44, 0x54, 0x54, 0x54, 0x28, 0x00, 0x00, // 231 - 'з' x0e7 + 0x05, 0x7c, 0x20, 0x10, 0x08, 0x7c, 0x00, 0x00, // 232 - 'и' x0e8 + 0x05, 0x7c, 0x20, 0x12, 0x08, 0x7c, 0x00, 0x00, // 233 - 'й' x0e9 + 0x05, 0x7c, 0x10, 0x10, 0x28, 0x44, 0x00, 0x00, // 234 - 'к' x0ea + 0x05, 0x40, 0x38, 0x04, 0x04, 0x7c, 0x00, 0x00, // 235 - 'л' x0eb + 0x05, 0x7c, 0x08, 0x10, 0x08, 0x7c, 0x00, 0x00, // 236 - 'м' x0ec + 0x05, 0x7c, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, // 237 - 'н' x0ed + 0x05, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, // 238 - 'o' x0ee + 0x05, 0x7c, 0x04, 0x04, 0x04, 0x7c, 0x00, 0x00, // 239 - 'п' x0ef + 0x05, 0xfc, 0x24, 0x24, 0x24, 0x18, 0x00, 0x00, // 240 - 'р' x0f0 + 0x04, 0x38, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, // 241 - 'с' x0f1 + 0x05, 0x0c, 0x04, 0x7c, 0x04, 0x0c, 0x00, 0x00, // 242 - 'т' x0f2 + 0x05, 0x4c, 0x90, 0x90, 0x50, 0x3c, 0x00, 0x00, // 243 - 'у' x0f3 + 0x07, 0x10, 0x28, 0x28, 0xfc, 0x28, 0x28, 0x10, // 244 - 'ф' x0f4 + 0x05, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, // 245 - 'x' x0f5 + 0x05, 0x7c, 0x40, 0x40, 0x7c, 0xc0, 0x00, 0x00, // 246 - 'ц' x0f6 + 0x05, 0x0c, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, // 247 - 'ч' x0f7 + 0x05, 0x7c, 0x40, 0x78, 0x40, 0x7c, 0x00, 0x00, // 248 - 'ш' x0f8 + 0x06, 0x7c, 0x40, 0x78, 0x40, 0x7c, 0xc0, 0x00, // 249 - 'щ' x0f9 + 0x06, 0x04, 0x7c, 0x50, 0x50, 0x50, 0x20, 0x00, // 250 - 'ъ' x0fa + 0x05, 0x7c, 0x50, 0x50, 0x20, 0x7c, 0x00, 0x00, // 251 - 'ы' x0fb + 0x05, 0x7c, 0x50, 0x50, 0x50, 0x20, 0x00, 0x00, // 252 - 'ь' x0fc + 0x05, 0x28, 0x44, 0x54, 0x54, 0x38, 0x00, 0x00, // 253 - 'э' x0fd + 0x06, 0x7c, 0x10, 0x38, 0x44, 0x44, 0x38, 0x00, // 254 - 'ю' x0fe + 0x05, 0x48, 0x34, 0x14, 0x14, 0x7c, 0x00, 0x00 // 255 - 'я' x0ff +}; diff --git a/globals.h b/globals.h new file mode 100644 index 0000000..a498661 --- /dev/null +++ b/globals.h @@ -0,0 +1,14 @@ + +bool printCom = true; + +int hour = 2, minute = 40, second = 42, month = 4, day = 6, dayOfWeek = 6, year = 2018; + + +int secFr, lastSecond, lastMinute; + +byte kuOn = 7; +byte kuOff = 23; + +bool isActiveBuzzer = 1; + +String tMes, tNow, tCurr, tPress, tPress0, tSpeed, tMin, tTom, tYour, tPoint, tIp, tPass, tWeatrTN, tWeatrNot, tAlarm; diff --git a/langModule.ino b/langModule.ino new file mode 100644 index 0000000..609f73c --- /dev/null +++ b/langModule.ino @@ -0,0 +1,257 @@ + + +//==========КОНВЕРТАЦІЯ СИМВОЛІВ В РАЗІ ВИКОРИСТАННЯ УКРАЇНСЬКИХ ЛІТЕР================== +byte dualChar = 0; +unsigned char convert_UA_RU_PL_DE(unsigned char _c) { + unsigned char c = _c; + // конвертирование латиницы + if (c == 208) { + dualChar = 1; + return 0; + } + else if (c == 209 || c == 210) { + dualChar = 2; + return 0; + } + if (c == 32 && dualChar != 3) { + dualChar = 3; + return c; + } + if (dualChar == 1) { + if (c >= 144 && c < 192) { + c += 48; + } + dualChar = 0; + return c; + } + if (dualChar == 2) { + if (c >= 128 && c < 144) { + c += 112; + } + switch (_c) { + case 144: c = 133; break; + case 145: c = 149; break; + } + dualChar = 0; + return c; + } + // конвертирование польского и немецкого + if (c == 195) { + dualChar = 4; + return 0; + } + if (c == 196) { + dualChar = 5; + return 0; + } + if (c == 197) { + dualChar = 6; + return 0; + } + if (dualChar == 4) { + switch (_c) { + case 132: c = 177; break; + case 147: c = 166; break; + case 150: c = 179; break; + case 156: c = 181; break; + case 159: c = 183; break; + case 164: c = 178; break; + case 179: c = 167; break; + case 182: c = 180; break; + case 188: c = 182; break; + } + dualChar = 0; + return c; + } + if (dualChar == 5) { + if (c >= 132 && c < 136) { + c += 26; + } + switch (_c) { + case 152: c = 168; break; + case 153: c = 169; break; + } + dualChar = 0; + return c; + } + if (dualChar == 6) { + if (c >= 129 && c < 133) { + c += 33; + } + if (c >= 154 && c < 156) { + c += 16; + } + if (c >= 185 && c < 189) { + c -= 13; + } + dualChar = 0; + return c; + } +} + +// ===========================КОНВЕРТАЦІЯ НАЗВ ДНІВ ТИЖНЯ НА УКРАЇНСЬКУ МОВУ============================================ +void convertDw(){ + switch(dayOfWeek){ + case 1 : dw = tSunday; break; + case 2 : dw = tMonday; break; + case 3 : dw = tTuesday; break; + case 4 : dw = tWednesday; break; + case 5 : dw = tThursday; break; + case 6 : dw = tFriday; break; + case 7 : dw = tSaturday; break; + } +} +// ===========================КОНВЕРТАЦІЯ НАЗВ МІСЯЦІВ НА УКРАЇНСЬКУ МОВУ============================================ +void convertMonth(){ + switch(month){ + case 1 : _month = tJanuary; break; + case 2 : _month = tFebruary; break; + case 3 : _month = tMarch; break; + case 4 : _month = tApril; break; + case 5 : _month = tMay; break; + case 6 : _month = tJune; break; + case 7 : _month = tJuly; break; + case 8 : _month = tAugust; break; + case 9 : _month = tSeptember; break; + case 10 : _month = tOctober; break; + case 11 : _month = tNovember; break; + case 12 : _month = tDecember; break; + } +} + +//----------------------------------------------------- +void initLang() { + if (weatherLang == "uk") { + tNow = "Зараз"; + tPress0 = "гПа"; + tPress = "ммРс"; + tSpeed = "м/с"; + tMin = "хв."; + tCurr = "Сьогодні"; + tTom = "Завтра"; + tYour = "Ваш"; + tPoint = "Підключіться до"; + tIp = "та перейдіть за адресою"; + tPass = "пароль"; + tWeatrNot = " Немає оновлень погоди більше 6 годин!!! "; + tWeatrTN = "Немає оновлень погоди."; + tJanuary = "січня"; + tFebruary = "лютого"; + tMarch = "березня"; + tApril = "квітня"; + tMay = "травня"; + tJune = "червня"; + tJuly = "липня"; + tAugust = "серпня"; + tSeptember = "вересня"; + tOctober = "жовтня"; + tNovember = "листопада"; + tDecember = "грудня"; + tMonday = "Понеділок"; + tTuesday = "Вівторок"; + tWednesday = "Середа"; + tThursday = "Четвер"; + tFriday = "П'ятниця"; + tSaturday = "Субота"; + tSunday = "Неділя"; + tAlarm = "УВАГА!!! "; + sgpCo2Message[0] = "Допустимий рівень повітря"; + sgpCo2Message[1] = "Важке повітря. Необхідно провітрювання"; + sgpCo2Message[2] = "Можлива сонливість, втома, головний біль"; + sgpCo2Message[3] = "Серйозне погіршення здоров'я !!!"; + sgpCo2Message[4] = "Гранично допустима концентрація протягом 8 годин!!!"; + sgpTvocMessage [0] = "Допустимий рівень ЛОС"; + sgpTvocMessage [1] = "Рекомендується вентиляція"; + sgpTvocMessage [2] = "Рекомендується інтенсивна вентиляція"; + sgpTvocMessage [3] = "Інтенсивна вентиляція і провітрювання необхідні"; + sgpTvocMessage [4] = "Дуже інтенсивна вентиляція суворо необхідна !!!"; + } else if (weatherLang == "ru") { + tNow = "Сейчас"; + tPress0 = "гПа"; + tPress = "ммРс"; + tSpeed = "м/с"; + tMin = "мин."; + tCurr = "Сегодня"; + tTom = "Завтра"; + tYour = "Ваш"; + tPoint = "Подключитесь к точке доступа"; + tIp = "и введите в браузере адрес"; + tPass = "пароль"; + tWeatrNot = " Нет обновления погоды более 6 часов!!! "; + tWeatrTN = "Нет обновления погоды."; + tJanuary = "января"; + tFebruary = "февраля"; + tMarch = "марта"; + tApril = "апреля"; + tMay = "мая"; + tJune = "июня"; + tJuly = "июля"; + tAugust = "августа"; + tSeptember = "сентября"; + tOctober = "октября"; + tNovember = "ноября"; + tDecember = "декабря"; + tMonday = "Понедельник"; + tTuesday = "Вторник"; + tWednesday = "Среда"; + tThursday = "Четверг"; + tFriday = "Пятница"; + tSaturday = "Суббота"; + tSunday = "Воскресенье"; + tAlarm = "ВНИМАНИЕ!!! "; + sgpCo2Message[0] = "Допустимый уровень возуха"; + sgpCo2Message[1] = "Тяжелый воздух. Необходимо проветривание"; + sgpCo2Message[2] = "Возможно сонливость, усталость, головная боль"; + sgpCo2Message[3] = "Серьезное ухудшение здоровья!!!"; + sgpCo2Message[4] = "Предельно допустимая концентрация в течении 8 часов"; + sgpTvocMessage[0] = "Допустимый уровень ЛОС"; + sgpTvocMessage[1] = "Рекомендуется вентиляция"; + sgpTvocMessage[2] = "Рекомендуется интенсивная вентиляция"; + sgpTvocMessage[3] = "Интенсивная вентиляция и проветривание необходимы"; + sgpTvocMessage[4] = "Очень интенсивная вентиляция строжайше необходима!!!"; + } else if (weatherLang == "en") { + tNow = "now"; + tPress0 = "gPa"; + tPress = "mmHg"; + tSpeed = "m/s"; + tMin = "min."; + tCurr = "Today"; + tTom = "Tomorrow"; + tYour = "Your"; + tPoint = "Connect to access point the"; + tIp = "and enter in the browser the address"; + tPass = "password"; + tWeatrNot = " There is no weather update for more than 6 hours !!! "; + tWeatrTN = "No weather updates."; + tJanuary = "January"; + tFebruary = "February"; + tMarch = "Martha"; + tApril = "April"; + tMay = "May"; + tJune = "June"; + tJuly = "July"; + tAugust = "August"; + tSeptember = "September"; + tOctober = "October"; + tNovember = "November"; + tDecember = "December"; + tMonday = "Monday"; + tTuesday = "Tuesday"; + tWednesday = "Wednesday"; + tThursday = "Thursday"; + tFriday = "Friday"; + tSaturday = "Saturday"; + tSunday = "Sunday"; + tAlarm = "ATTENTION!!! "; + sgpCo2Message[0] = "Permissible level of air"; + sgpCo2Message[1] = "Heavy air. Ventilation is necessary"; + sgpCo2Message[2] = "Drowsiness, fatigue, headache is possible"; + sgpCo2Message[3] = "Serious deterioration of health !!!"; + sgpCo2Message[4] = "Maximum permissible concentration within 8 hours"; + sgpTvocMessage [0] = "Allowable VOC Level"; + sgpTvocMessage [1] = "Recommended ventilation"; + sgpTvocMessage [2] = "Recommended intensive ventilation"; + sgpTvocMessage [3] = "Intensive ventilation and ventilation are necessary"; + sgpTvocMessage [4] = "Very intensive ventilation is strictly necessary !!!"; + } +} diff --git a/max7219.h b/max7219.h new file mode 100644 index 0000000..26d54a1 --- /dev/null +++ b/max7219.h @@ -0,0 +1,107 @@ +// MAX7219 commands: +#define CMD_NOOP 0 +#define CMD_DIGIT0 1 +#define CMD_DIGIT1 2 +#define CMD_DIGIT2 3 +#define CMD_DIGIT3 4 +#define CMD_DIGIT4 5 +#define CMD_DIGIT5 6 +#define CMD_DIGIT6 7 +#define CMD_DIGIT7 8 +#define CMD_DECODEMODE 9 +#define CMD_INTENSITY 10 +#define CMD_SCANLIMIT 11 +#define CMD_SHUTDOWN 12 +#define CMD_DISPLAYTEST 15 + +byte scr[136]; + +byte MAX7219_NUM = 4; +int MAX7219_ROTATE = 90; //0, 90, 180, 270 + + +//====================================================================================================== +void sendCmdAll(byte cmd, byte data) { + digitalWrite(CS_PIN, LOW); + for(int i = MAX7219_NUM - 1; i >= 0; i--) { + shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, cmd); + shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, data); + } + digitalWrite(CS_PIN, HIGH); +} +//====================================================================================================== +void refreshAll() { + byte mask = (MAX7219_ROTATE == 270 ? 0x01 : 0x80); + for(int c = 0; c < 8; c++) { + digitalWrite(CS_PIN, LOW); + for(int i = (MAX7219_ROTATE == 180 ? 0 : MAX7219_NUM - 1); (MAX7219_ROTATE == 180 ? (i < MAX7219_NUM) : (i >= 0)); (MAX7219_ROTATE == 180 ? i++ : i--)) { + byte bt = 0; + if(MAX7219_ROTATE == 270) { + for(int b = 0; b < 8; b++) { + bt <<= 1; + if(scr[i * 8 + b] & mask) { + bt |= 0x01; + } + } + shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, CMD_DIGIT0 + c); + shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, bt); + } else if(MAX7219_ROTATE == 90) { + for(int b = 0; b < 8; b++) { + bt >>= 1; + if(scr[i * 8 + b] & mask) { + bt |= 0x80; + } + } + shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, CMD_DIGIT0 + c); + shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, bt); + } else { + shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, CMD_DIGIT0 + c); + shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, scr[i * 8 + c]); + } + } + digitalWrite(CS_PIN, HIGH); + if(MAX7219_ROTATE == 270) { + mask <<= 1; + } + if(MAX7219_ROTATE == 90) { + mask >>= 1; + } + } +} + +//====================================================================================================== +void clr() { + for(int i = 0; i < MAX7219_NUM * 8; i++) { + scr[i] = 0; + } +} + +//====================================================================================================== +void scrollLeft() { + for(int i = 0; i < MAX7219_NUM * 8 + 7; i++) { + scr[i] = scr[i + 1]; + } +} + +//====================================================================================================== +void invert() { + for(int i = 0; i < MAX7219_NUM * 8; i++) { + scr[i] =~ scr[i]; + } +} + +//====================================================================================================== +void initMAX7219() { + pinMode(DIN_PIN, OUTPUT); + pinMode(CLK_PIN, OUTPUT); + pinMode(CS_PIN, OUTPUT); + digitalWrite(CS_PIN, HIGH); + delay(500); + sendCmdAll(CMD_DISPLAYTEST, 0); + sendCmdAll(CMD_SCANLIMIT, 7); + sendCmdAll(CMD_DECODEMODE, 0); + sendCmdAll(CMD_INTENSITY, 0); + sendCmdAll(CMD_SHUTDOWN, 0); + clr(); + refreshAll(); +} diff --git a/ntpModule.ino b/ntpModule.ino new file mode 100644 index 0000000..e69de29 diff --git a/rtc.h b/rtc.h new file mode 100644 index 0000000..3913502 --- /dev/null +++ b/rtc.h @@ -0,0 +1,59 @@ +int BCD2DEC(int x) { return ((x)>>4)*10+((x)&0xf); } +int DEC2BCD(int x) { return (((x)/10)<<4)+((x)%10); } + +#define I2CStart(x) Wire.beginTransmission(x) +#define I2CStop() Wire.endTransmission() +#define I2CWrite(x) Wire.write(x) +#define I2CRead() Wire.read() +#define I2CReq(x,y) Wire.requestFrom(x,y) +#define I2CReady while(!Wire.available()) {}; + +#define DS_RTC_TIME 0x00 +#define DS_RTC_DOW 0x03 +#define DS_RTC_DATE 0x04 +#define DS_RTC_MEM 0x08 + +int rtcAddr = 0x68; + +typedef struct { + int hour, minute, second, month, day, dayOfWeek, year; +} RtcStruct; + +RtcStruct rtcStruct; + +void setRTCDateTime() { + I2CStart(rtcAddr); + I2CWrite(DS_RTC_TIME); + I2CWrite(DEC2BCD(rtcStruct.second)); + I2CWrite(DEC2BCD(rtcStruct.minute)); + I2CWrite(DEC2BCD(rtcStruct.hour)); + I2CWrite(DEC2BCD(rtcStruct.dayOfWeek)); + I2CWrite(DEC2BCD(rtcStruct.day)); + I2CWrite(DEC2BCD(rtcStruct.month)); + I2CWrite(DEC2BCD(rtcStruct.year - 2000)); + I2CStop(); +} + +void getRTCDateTime(void) { + int v; + I2CStart(rtcAddr); + I2CWrite(DS_RTC_TIME); + I2CStop(); + I2CReq(rtcAddr, 7); + I2CReady; + v = I2CRead() & 0x7f; + rtcStruct.second = BCD2DEC(v); + v = I2CRead() & 0x7f; + rtcStruct.minute = BCD2DEC(v); + v = I2CRead() & 0x3f; + rtcStruct.hour = BCD2DEC(v); + v = I2CRead() & 0x07; + rtcStruct.dayOfWeek = BCD2DEC(v); + v = I2CRead() & 0x3f; + rtcStruct.day = BCD2DEC(v); + v = I2CRead() & 0x3f; + rtcStruct.month = BCD2DEC(v); + v = I2CRead() & 0xff; + rtcStruct.year = BCD2DEC(v) + 2000; + I2CStop(); +} diff --git a/sgpModule.h b/sgpModule.h new file mode 100644 index 0000000..d9866ba --- /dev/null +++ b/sgpModule.h @@ -0,0 +1,136 @@ + +Adafruit_SGP30 sgp; + +boolean sgpFound = false; +int sgpCo2 = 400; + +byte sgpCo2LivelAlarm = 2; +boolean eCo2AlarmEsp = true; + +boolean eCo2Led = true; +String sgpCo2Message[] = {"","","","",""}; +int sgpTvoc = 0; +byte sgpTvocLivelAlarm = 2; + +boolean tvocAlarmEsp = true; + +boolean tvocLed = true; + +String sgpTvocMessage[] = {"","","","",""}; + +byte setSgpCorr = 0; //0-нет коррекции, 1-BME-280, 2-Si7021, 3-AHTx0, 4-DHT11/22 + +float sgpCorrTemp = 22.1; // [°C] +float sgpCorrHumi = 45.2; // [%RH] + +typedef struct { + byte co2Livel = 0; //0=400-699, 1=700-999, 2=1000-2499, 3=2500-4999, 4=5000++ + int co2Livel1 = 700; + int co2Livel2 = 1000; + int co2Livel3 = 2500; + int co2Livel4 = 5000; + byte tvocLivel = 0; //0=0-64, 1=65-219, 2=220-659, 3=660-2199, 4=2200++ + int tvocLivel1 = 65; + int tvocLivel2 = 220; + int tvocLivel3 = 660; + int tvocLivel4 = 2200; +} SgpValues; + +SgpValues sgpValues; + +uint32_t getAbsoluteHumidity(float temperature, float humidity) { + // approximation formula from Sensirion SGP30 Driver Integration chapter 3.15 + const float absoluteHumidity = 216.7f * ((humidity / 100.0f) * 6.112f * exp((17.62f * temperature) / (243.12f + temperature)) / (273.15f + temperature)); // [g/m^3] + const uint32_t absoluteHumidityScaled = static_cast(1000.0f * absoluteHumidity); // [mg/m^3] + return absoluteHumidityScaled; +} + +void sgp30() { + // If you have a temperature / humidity sensor, you can set the absolute humidity to enable the humditiy compensation for the air quality signals + if(setSgpCorr) { + sgp.setHumidity(getAbsoluteHumidity(sgpCorrTemp, sgpCorrHumi)); + } + printTime(); + if(!sgp.IAQmeasure()) { + if(printCom) { + Serial.println("Measurement failed"); + } + return; + } + sgpCo2 = sgp.eCO2; + sgpTvoc = sgp.TVOC; + if(printCom) { + Serial.print("TVOC = " + String(sgpTvoc) + " ppb, "); + } + if(printCom) { + Serial.print("eCO2 = " + String(sgpCo2) + " ppm, "); + } + if(sgpCo2 < sgpValues.co2Livel1) { + sgpValues.co2Livel = 0; + } else if(sgpCo2 < sgpValues.co2Livel2) { + sgpValues.co2Livel = 1; + } else if(sgpCo2 < sgpValues.co2Livel3) { + sgpValues.co2Livel = 2; + } else if(sgpCo2 < sgpValues.co2Livel4) { + sgpValues.co2Livel = 3; + } else { + sgpValues.co2Livel = 4; + } + if(sgpTvoc < sgpValues.tvocLivel1) { + sgpValues.tvocLivel = 0; + } else if(sgpTvoc < sgpValues.tvocLivel2) { + sgpValues.tvocLivel = 1; + } else if(sgpTvoc < sgpValues.tvocLivel3) { + sgpValues.tvocLivel = 2; + } else if(sgpTvoc < sgpValues.tvocLivel4) { + sgpValues.tvocLivel = 3; + } else { + sgpValues.tvocLivel = 4; + } + + if(!sgp.IAQmeasureRaw()) { + if(printCom) { + Serial.println("Raw Measurement failed"); + } + } else { + if(printCom) { + Serial.print("Raw H2 = " + String(sgp.rawH2) + ", "); + } + if(printCom) { + Serial.println("Raw Ethanol = " + String(sgp.rawEthanol)); + } + if (minute % 5 == 0) { + uint16_t TVOC_base, eCO2_base; + if(!sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) { + if(printCom){ + printTime(); + Serial.println("Failed to get baseline readings"); + } + return; + } + if(printCom) { + printTime(); + Serial.print("****Baseline values: eCO2: 0x" + String (eCO2_base, HEX)); + Serial.println(" & TVOC: 0x" + String(TVOC_base, HEX)); + } + } + } + + String livelCo2 = tAlarm + sgpCo2Message[sgpValues.co2Livel] + " eCO2 = " + String(sgpCo2) + " ppm "; + if(sgpValues.co2Livel >= sgpCo2LivelAlarm) { + if(eCo2AlarmEsp) { + bip(4); + clr(); + printStringWithShift((" " + livelCo2).c_str(), timeScrollSpeed); + } + } + + String livelTvoc = tAlarm + sgpTvocMessage[sgpValues.tvocLivel] + " TVOC = " + String(sgpTvoc) + " ppb "; + if(sgpValues.tvocLivel >= sgpTvocLivelAlarm) { + if(tvocAlarmEsp) { + bip(4); + clr(); + printStringWithShift((" " + livelTvoc).c_str(), timeScrollSpeed); + } + } +} diff --git a/soundModule.h b/soundModule.h new file mode 100644 index 0000000..056a876 --- /dev/null +++ b/soundModule.h @@ -0,0 +1,26 @@ + +void bip() { + if (!isActiveBuzzer) { + tone(buzzerPin, 2000, 40); + delay(250); + noTone(buzzerPin); + } else { + digitalWrite(buzzerPin, HIGH); + delay(120); + digitalWrite(buzzerPin, LOW); + delay(120); + } +} + +void bip(uint8_t count) { + for(uint8_t i = 0; i < count; i++) { + bip(); + } +} + +void checkNeedHourSound() { + if(minute == 0 && second == 0 && secFr == 0 && (hour >= kuOn && hour < kuOff)) { + bip(); + bip(); + } +} diff --git a/weatherModule.ino b/weatherModule.ino new file mode 100644 index 0000000..2f60f3e --- /dev/null +++ b/weatherModule.ino @@ -0,0 +1,501 @@ + +static const uint8_t monthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // Кількість днів у місяцях + +String weatherMain = ""; +String weatherDescription = ""; +String weatherLocation = ""; +String country; +String tempz; +int clouds; +int windDeg; +float windSpeed; +String dw, _month; + +//===============================================================================================================================// +// БЕРЕМО ПОГОДУ З САЙТУ https://www.weatherbit.io // +//===============================================================================================================================// +void getWeatherData0() { + if(weatherKey0=="" || !displayForecast) return; + if(!WIFI_connected) { + updateForecast++; + return; + } + if(printCom) { + Serial.println("======== START GET WEATHER FROM WEATHERBIT.IO ========="); + printTime(); + } + location_name = ""; + location_region = ""; + location_country = ""; + location_localtime = ""; + location_temp = 0; + location_app_temp = 0; + location_rh = 0; + location_pres = 0; + location_wind_spd = 0; + location_wind_cdir_full = ""; + location_sunrise = ""; + location_sunset = ""; + location_clouds = 0; + location_vis = 0; + location_uv = 0; + location_weather_description = ""; + if(ESPclient.connect(weatherHost0.c_str(), 80)){} + else { + if(printCom){ + Serial.println(" Not connection server!!!"); + Serial.println("======== END =========================================="); + } + updateForecast++; + return; + } + HTTPClient http; + String line=""; + String reqline="http://"+weatherHost0+"/v2.0/current/daily?city="+urlencode(cityID0)+"&lang="+weatherLang+"&key="+weatherKey0; + if(printCom) Serial.print(reqline); + if(http.begin(ESPclient, reqline)){ + int httpCode = http.GET(); + if(httpCode > 0) { + if(printCom) Serial.printf(" [HTTP] GET... code: %d\n", httpCode); + if(httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) { + line = http.getString(); + } + } else { + if(printCom){ + Serial.printf(" [HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); + Serial.println("======== END =========================================="); + } + http.end(); + updateForecast++; + return; + } + http.end(); + } else { + if(printCom){ + Serial.printf(" [HTTP] Unable to connect\n"); + Serial.println("======== END =========================================="); + } + updateForecast++; + return; + } + if(line==""){ + if(printCom){ + printTime(); + Serial.printf("[HTTP] The answer is empty\n"); + Serial.println("======== END =========================================="); + } + updateForecast++; + return; + } + const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(37) + 1128; //https://arduinojson.org/v6/assistant/ + DynamicJsonDocument doc(capacity); + deserializeJson(doc, line); + if(!doc.capacity()){ + if(printCom){ + printTime(); + Serial.println("Parse weather forecast - FAILED!!!"); + Serial.println("======== END =========================================="); + } + updateForecast++; + return; + } + JsonObject data = doc["data"][0]; + location_rh = data["rh"]; // 69 + location_pres = data["pres"]; // 999.3 + if(pressSys == 1) location_pres /= 1.3332239; + const char* data_timezone = data["timezone"]; // "Europe/Kiev" + location_region = data_timezone; + const char* data_ob_time = data["ob_time"]; // "2019-09-19 17:57" + location_localtime = data_ob_time; + const char* data_country_code = data["country_code"]; // "UA" + location_country = data_country_code; + location_clouds = data["clouds"]; // 4 + const char* data_city_name = data["city_name"]; // "Kiev" + location_name = data_city_name; + location_wind_spd = data["wind_spd"]; // 1 + const char* data_wind_cdir_full = data["wind_cdir_full"]; // "пі́вдень-пі́вдень-схід" + location_wind_cdir_full = data_wind_cdir_full; + location_vis = data["vis"]; // 5 + const char* data_sunset = data["sunset"]; // "16:01" + location_sunset = data_sunset; + location_uv = data["uv"]; // 0 + int data_wind_dir = data["wind_dir"]; // 166 + const char* data_sunrise = data["sunrise"]; // "03:39" + location_sunrise = data_sunrise; //int data_dni = data["dni"]; // 0 + JsonObject data_weather = data["weather"]; + const char* data_weather_description = data_weather["description"]; // "ясного неба" + location_weather_description = data_weather_description; + location_temp = data["temp"]; // 10.6 + location_app_temp = data["app_temp"]; // 10.6 + String windDegString; + if(data_wind_dir >= 345 || data_wind_dir <= 22) windDegString = "\211"; //"Північний"; + if(data_wind_dir >= 23 && data_wind_dir <= 68) windDegString = "\234"; //"Північно-східний"; + if(data_wind_dir >= 69 && data_wind_dir <= 114) windDegString = "\230"; //"Східний"; + if(data_wind_dir >= 115 && data_wind_dir <= 160) windDegString = "\235"; //"Південно-східний"; + if(data_wind_dir >= 161 && data_wind_dir <= 206) windDegString = "\210"; //"Південний"; + if(data_wind_dir >= 207 && data_wind_dir <= 252) windDegString = "\232"; //"Південно-західний"; + if(data_wind_dir >= 253 && data_wind_dir <= 298) windDegString = "\231"; //"Західний"; + if(data_wind_dir >= 299 && data_wind_dir <= 344) windDegString = "\233"; //"Північно-західний"; + weatherString = space; + if(displayCityName){ + String PCN=personalCityName; + if(PCN.length() > 0) weatherString += PCN; + else weatherString += String(location_name); + weatherString += ", "; + } + if(displayForecastNow){ + weatherString += tNow + ": \212 " + String(location_temp, 1)+" ("+String(location_app_temp,1)+")"+("\202")+"C"; + weatherString += " \213 " + String(location_rh) + "%"; + weatherString += " \215 " + String((location_pres), 0) + (pressSys == 1 ? tPress : tPress0); + weatherString += " \214 " + windDegString + String(location_wind_spd, 1) + tSpeed; + weatherString += " \216 " + String(location_clouds) + "% " + data_weather_description + space; + } + updateForecast = 0; + updateForecastNot = false; + if(printCom){ + printTime(); + Serial.println("line =" + line); + Serial.println("======== END =========================================="); + } +} + +//===============================================================================================================================// +// БЕРЕМО ПОГОДУ З САЙТУ openweathermap.org // +//===============================================================================================================================// +void getWeatherData1(){ + if(weatherKey1=="" || !displayForecast) return; + if(!WIFI_connected){ + updateForecast++; + return; + } + if(printCom){ // + Serial.println("======== START GET WEATHER FROM OPENWEATHERMAP.ORG ===="); + printTime(); + } + location_name = ""; + location_region = ""; + location_country = ""; + location_localtime = ""; + location_temp = 0; + location_app_temp = 0; + location_rh = 0; + location_pres = 0; + location_wind_spd = 0; + location_wind_cdir_full = ""; + location_sunrise = ""; + location_sunset = ""; + location_clouds = 0; + location_vis = 0; + location_uv = 0; + location_weather_description = ""; + if(ESPclient.connect(weatherHost1.c_str(), 80)){} + else{ + if(printCom){ + Serial.println(" Not connection server!!!"); + Serial.println("======== END =========================================="); + } + updateForecast++; + return; + } + HTTPClient http; + String line=""; + String reqline="http://"+weatherHost1+"/data/2.5/weather?id="+urlencode(cityID1)+"&lang="+weatherLang+"&units=metric&appid="+weatherKey1; + if(printCom) Serial.print(reqline); + if(http.begin(ESPclient, reqline)){ + int httpCode = http.GET(); + if(httpCode > 0) { + if(printCom) Serial.printf(" [HTTP] GET... code: %d\n", httpCode); + if(httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY){ + line = http.getString(); + } + } else { + if(printCom){ + Serial.printf(" [HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); + Serial.println("======== END =========================================="); + } + http.end(); + updateForecast++; + return; + } + http.end(); + } else { + if(printCom){ + Serial.printf(" [HTTP] Unable to connect\n"); + Serial.println("======== END =========================================="); + } + updateForecast++; + return; + } + if(line==""){ + if(printCom){ + printTime(); + Serial.printf("[HTTP] The answer is empty\n"); + Serial.println("======== END =========================================="); + } + updateForecast++; + return; + } + const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + 2*JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(13) + 751; //https://arduinojson.org/v6/assistant/ + DynamicJsonDocument doc(capacity); + deserializeJson(doc, line); + if(!doc.capacity()){ + if(printCom){ + printTime(); + Serial.println("Parse weather forecast - FAILED!!!"); + Serial.println("======== END =========================================="); + } + updateForecast++; + return; + } + JsonObject weather_0 = doc["weather"][0]; + const char* data_weather_description = weather_0["description"]; // "fog" + location_weather_description = data_weather_description; + JsonObject main = doc["main"]; + location_temp = main["temp"]; // 10.34 + location_pres = main["pressure"]; // 1023 + if(pressSys == 1) location_pres /= 1.3332239; + location_rh = main["humidity"]; // 100 + float location_temp_min = main["temp_min"]; // 7 + float location_temp_max = main["temp_max"]; // 12.22 + location_vis = doc["visibility"]; // 1000 + location_vis /= 1000; + location_wind_spd = doc["wind"]["speed"]; // 1 + int data_wind_dir = doc["wind"]["deg"]; // 230 + location_clouds = doc["clouds"]["all"]; // 20 + JsonObject sys = doc["sys"]; + const char* data_country_code = sys["country"]; // "UA" + location_country = data_country_code; + const char* data_city_name = doc["name"]; // "Kyiv" + location_name = data_city_name; + String windDegString; + if(data_wind_dir >= 345 || data_wind_dir <= 22) windDegString = "\211"; //"Північний"; + if(data_wind_dir >= 23 && data_wind_dir <= 68) windDegString = "\234"; //"Північно-східний"; + if(data_wind_dir >= 69 && data_wind_dir <= 114) windDegString = "\230"; //"Східний"; + if(data_wind_dir >= 115 && data_wind_dir <= 160) windDegString = "\235"; //"Південно-східний"; + if(data_wind_dir >= 161 && data_wind_dir <= 206) windDegString = "\210"; //"Південний"; + if(data_wind_dir >= 207 && data_wind_dir <= 252) windDegString = "\232"; //"Південно-західний"; + if(data_wind_dir >= 253 && data_wind_dir <= 298) windDegString = "\231"; //"Західний"; + if(data_wind_dir >= 299 && data_wind_dir <= 344) windDegString = "\233"; //"Північно-західний"; + weatherString = space; + if(displayCityName){ + String PCN=personalCityName; + if(PCN.length() > 0) weatherString += PCN; + else weatherString += String(location_name); + weatherString += ", "; + } + if(displayForecastNow){ + weatherString += tNow + ": \212 "+String(location_temp, 1)+" ("+String(location_temp_min,1)+"..."+String(location_temp_max,1)+")"+("\202")+"C"; + weatherString += " \213 " + String(location_rh) + "%"; + weatherString += " \215 " + String((location_pres), 0) + (pressSys == 1 ? tPress : tPress0) ; + weatherString += " \214 " + windDegString + String(location_wind_spd, 1) + tSpeed; + weatherString += " \216 " + String(location_clouds) + "% " + data_weather_description + space; + } + updateForecast = 0; + updateForecastNot = false; + if(printCom){ + printTime(); + Serial.println("line =" + line); + Serial.println("======== END =========================================="); + } +} + +// ============================================================================// +// Беремо ПРОГНОЗ!!! погоди з сайту https://www.weatherbit.io // +// ============================================================================// +void getWeatherDataz0() { + if(weatherKey0=="" || !displayForecastTomorrow) return; + if(!WIFI_connected) { + updateForecasttomorrow++; + return; + } + if(printCom){ + Serial.println("======== START GET FORECAST FROM WEATHERBIT.IO ========"); + printTime(); + } + HTTPClient http; + String line=""; + String reqline="http://"+weatherHost0+"/v2.0/forecast/daily?city="+urlencode(cityID0)+"&lang="+weatherLang+"&days=2&key="+weatherKey0; + if(printCom) Serial.print(reqline); + if(http.begin(ESPclient, reqline)){ + int httpCode = http.GET(); + if(httpCode > 0) { + if(printCom) Serial.printf(" [HTTP] GET... code: %d\n", httpCode); + if(httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) { + line = http.getString(); + } + } else { + if(printCom){ + Serial.printf(" [HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); + Serial.println("======== END =========================================="); + } + http.end(); + updateForecasttomorrow++; + return; + } + http.end(); + } else { + if(printCom){ + Serial.printf(" [HTTP] Unable to connect\n"); + Serial.println("======== END =========================================="); + } + updateForecasttomorrow++; + return; + } + if(line==""){ + if(printCom){ + printTime(); + Serial.printf("[HTTP] The answer is empty\n"); + Serial.println("======== END =========================================="); + } + updateForecasttomorrow++; + return; + } + const size_t capacity = JSON_ARRAY_SIZE(2) + 2*JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(7) + 2*JSON_OBJECT_SIZE(37) + 2321; + DynamicJsonDocument doc(capacity); + deserializeJson(doc, line); + if(!doc.capacity()){ + if(printCom){ + printTime(); + Serial.println("Parse weather forecast - FAILED!!!"); + Serial.println("======== END =========================================="); + } + updateForecasttomorrow++; + return; + } + JsonObject data_0 = doc["data"][0]; + JsonObject data_0_weather = data_0["weather"]; + const char* data_0_weather_description = data_0_weather["description"]; // "Помірний дощ" + float data_0_max_temp = data_0["max_temp"]; // 13.4 + float data_0_min_temp = data_0["min_temp"]; // 10.9 + JsonObject data_1 = doc["data"][1]; + int data_1_rh = data_1["rh"]; // 75 + int data_1_clouds = data_1["clouds"]; // 58 + float data_1_wind_spd = data_1["wind_spd"]; // 3.75302 + JsonObject data_1_weather = data_1["weather"]; + const char* data_1_weather_description = data_1_weather["description"]; // "Світло душ дощ" + float data_1_max_temp = data_1["max_temp"]; // 16.3 + float data_1_min_temp = data_1["min_temp"]; // 10 + weatherStringZ = ""; + if(displayForecastToday){ + if(hour<18) weatherStringZ += tCurr + ":"; + if(hour<12) weatherStringZ += " \212" + String(data_0_min_temp, 1) + "...." + String(data_0_max_temp, 1) + "\202" + "C "; + if(hour<18) weatherStringZ += " " + String(data_0_weather_description) + " "; + } + if(displayForecastTomorrow) { + weatherStringZ += tTom + ": \212" + String(data_1_min_temp, 1) + "...." + String(data_1_max_temp, 1) + "\202" + "C"; + weatherStringZ += " \213 " + String(data_1_rh) + "%"; + weatherStringZ += " \214 " + String(data_1_wind_spd, 1) + tSpeed; + weatherStringZ += " " + String(data_1_weather_description); + weatherStringZ += space; + } + if(printCom) Serial.println(" Getting weather forecast for tomorrow - is OK."); + updateForecasttomorrow = 0; + updateForecastNot = false; + if(printCom){ + printTime(); + Serial.println("line =" + line); + Serial.println("======== END =========================================="); + } +} + +// =======================================================================// +// Беремо ПРОГНОЗ!!! погоди з сайту openweathermap.org // +// =======================================================================// +void getWeatherDataz1(){ + if(weatherKey1=="" || !displayForecastTomorrow) return; + if(!WIFI_connected) { + updateForecasttomorrow++; + return; + } + if(printCom){ + Serial.println("======== START GET FORECAST FROM OPENWEATHERMAP.ORG ==="); + printTime(); + } + HTTPClient http; + String line=""; + String reqline="http://"+weatherHost1+"/data/2.5/forecast/daily?id="+urlencode(cityID1)+"&units=metric&appid="+weatherKey1+"&lang="+weatherLang+"&cnt=2"; + if(printCom) Serial.print(reqline); + if(http.begin(ESPclient, reqline)){ + int httpCode = http.GET(); + if (httpCode > 0) { + if(printCom) Serial.printf(" [HTTP] GET... code: %d\n", httpCode); + if(httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) { + line = http.getString(); + } + } else { + if(printCom){ + Serial.printf(" [HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); + Serial.println("======== END =========================================="); + } + http.end(); + updateForecasttomorrow++; + return; + } + http.end(); + } else { + if(printCom){ + Serial.printf(" [HTTP] Unable to connect\n"); + Serial.println("======== END =========================================="); + } + updateForecasttomorrow++; + return; + } + if(line==""){ + if(printCom){ + printTime(); + Serial.printf("[HTTP] The answer is empty\n"); + Serial.println("======== END =========================================="); + } + updateForecasttomorrow++; + return; + } + const size_t capacity = 2*JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(2) + JSON_OBJECT_SIZE(2) + 2*JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + 3*JSON_OBJECT_SIZE(6) + 2*JSON_OBJECT_SIZE(10) + 1281; + DynamicJsonDocument doc(capacity); + deserializeJson(doc, line); + if(!doc.capacity()){ + if(printCom){ + printTime(); + Serial.println("Parse weather forecast - FAILED!!!"); + Serial.println("======== END =========================================="); + } + updateForecasttomorrow++; + return; + } + JsonObject city = doc["city"]; + JsonObject list_0 = doc["list"][0]; + JsonObject list_0_temp = list_0["temp"]; + float data_0_min_temp = list_0_temp["min"]; // 9.63 + float data_0_max_temp = list_0_temp["max"]; // 9.69 + JsonObject list_0_weather_0 = list_0["weather"][0]; + const char* data_0_weather_description = list_0_weather_0["description"]; // "облачно" + JsonObject list_1 = doc["list"][1]; + JsonObject list_1_temp = list_1["temp"]; + float data_1_day_temp = list_1_temp["day"]; // 18.13 + float data_1_min_temp = list_1_temp["min"]; // 10.67 + float data_1_max_temp = list_1_temp["max"]; // 20.32 + int data_1_rh = list_1["humidity"]; // 56 + JsonObject list_1_weather_0 = list_1["weather"][0]; + const char* data_1_weather_description = list_1_weather_0["description"]; // "слегка облачно" + float data_1_wind_spd = list_1["speed"]; // 0.7 + int data_1_clouds = list_1["clouds"]; // 38 + weatherStringZ = ""; + if(displayForecastToday){ + if(hour<18) weatherStringZ += tCurr + ":"; + if(hour<12) weatherStringZ += " \212" + String(data_0_min_temp, 1) + "...." + String(data_0_max_temp, 1) + "\202" + "C "; + if(hour<18) weatherStringZ += " " + String(data_0_weather_description) + " "; + } + if(displayForecastTomorrow) { + weatherStringZ += tTom + ": \212" + String(data_1_min_temp, 1) + "...." + String(data_1_day_temp, 1) + "...." + String(data_1_max_temp, 1) + "\202" + "C"; + weatherStringZ += " \213 " + String(data_1_rh) + "%"; + weatherStringZ += " \214 " + String(data_1_wind_spd, 1) + tSpeed; + weatherStringZ += " \216 " + String(data_1_clouds) + "% " + String(data_1_weather_description); + weatherStringZ += space; + } + updateForecasttomorrow = 0; + updateForecastNot = false; + if(printCom){ + printTime(); + Serial.println("line =" + line); + Serial.println("======== END =========================================="); + } +}