diff --git a/Cmd.ino b/Cmd.ino new file mode 100644 index 00000000..a62d9438 --- /dev/null +++ b/Cmd.ino @@ -0,0 +1,505 @@ +void CMD_init() { + + sCmd.addCommand("button", button); + sCmd.addCommand("buttonSet", buttonSet); + + sCmd.addCommand("pinSet", pinSet); + + sCmd.addCommand("pwm", pwm); + sCmd.addCommand("pwmSet", pwmSet); + + sCmd.addCommand("switch", switch_); + + sCmd.addCommand("analog", analog); + sCmd.addCommand("ph", ph); + sCmd.addCommand("level", level); + sCmd.addCommand("dallas", dallas); + + sCmd.addCommand("logging", logging); + + sCmd.addCommand("input", input); + sCmd.addCommand("valueUpSet", valueUpSet); + sCmd.addCommand("valueDownSet", valueDownSet); + + sCmd.addCommand("text", text); + sCmd.addCommand("textSet", textSet); + + // sCmd.addCommand("time", time); + // sCmd.addCommand("timeSet", timeSet); + + sCmd.addCommand("timerStart", timerStart); + sCmd.addCommand("timerStop", timerStop); + + sCmd.addCommand("mqtt", mqttOrderSend); + sCmd.addCommand("http", httpOrderSend); + //!sCmd.addCommand("push", pushControl); + + //handleCMD_ticker(); +} + + +//========================================================================================================== +//==========================================Модуль кнопок=================================================== +void button() { + + String button_number = sCmd.next(); + String button_param = sCmd.next(); + String viget_name = sCmd.next(); + String page_name = sCmd.next(); + String start_state = sCmd.next(); + String page_number = sCmd.next(); + + jsonWrite(optionJson, "button_param" + button_number, button_param); + jsonWrite(configJson, "buttonSet" + button_number, start_state); + + if (isDigitStr (button_param)) { + pinMode(button_param.toInt(), OUTPUT); + digitalWrite(button_param.toInt(), start_state.toInt()); + } + + if (button_param == "scenario") { + jsonWrite(configSetup, "scenario", start_state); + Scenario_init(); + saveConfig(); + } + + if (button_param.indexOf("line") != -1) { + String str = button_param; + while (str.length() != 0) { + if (str == "") return; + String tmp = selectToMarker (str, ","); //line1, + String number = deleteBeforeDelimiter(tmp, "e"); //1, + number.replace(",", ""); + Serial.println(number); + int number_int = number.toInt(); + scenario_line_status[number_int] = start_state.toInt(); + str = deleteBeforeDelimiter(str, ","); + } + } + + + createViget (viget_name, page_name, page_number, "vigets/viget.toggle.json", "buttonSet" + button_number); +} + +void buttonSet() { + + String button_number = sCmd.next(); + String button_state = sCmd.next(); + String button_param = jsonRead(optionJson, "button_param" + button_number); + + if (button_param != "na" || button_param != "scenario" || button_param.indexOf("line") != -1) { + digitalWrite(button_param.toInt(), button_state.toInt()); + } + + if (button_param == "scenario") { + jsonWrite(configSetup, "scenario", button_state); + Scenario_init(); + saveConfig(); + } + + if (button_param.indexOf("line") != -1) { + String str = button_param; + while (str.length() != 0) { + if (str == "") return; + String tmp = selectToMarker (str, ","); //line1, + String number = deleteBeforeDelimiter(tmp, "e"); //1, + number.replace(",", ""); + Serial.println(number); + int number_int = number.toInt(); + scenario_line_status[number_int] = button_state.toInt(); + str = deleteBeforeDelimiter(str, ","); + } + } + + eventGen ("buttonSet", button_number); + + jsonWrite(configJson, "buttonSet" + button_number, button_state); + sendSTATUS("buttonSet" + button_number, button_state); +} + +void pinSet() { + + String pin_number = sCmd.next(); + String pin_state = sCmd.next(); + pinMode(pin_number.toInt(), OUTPUT); + digitalWrite(pin_number.toInt(), pin_state.toInt()); + +} +//================================================================================================================== +//==========================================Модуль управления ШИМ=================================================== +void pwm() { + + static boolean flag = true; + String pwm_number = sCmd.next(); + String pwm_pin = sCmd.next(); + String viget_name = sCmd.next(); + viget_name.replace("#", " "); + String page_name = sCmd.next(); + String start_state = sCmd.next(); + String page_number = sCmd.next(); + + + uint8_t pwm_pin_int = pwm_pin.toInt(); + jsonWrite(optionJson, "pwm_pin" + pwm_number, pwm_pin); + pinMode(pwm_pin_int, INPUT); + analogWrite(pwm_pin_int, start_state.toInt()); + jsonWrite(configJson, "pwmSet" + pwm_number, start_state); + + createViget (viget_name, page_name, page_number, "vigets/viget.range.json", "pwmSet" + pwm_number); +} + +void pwmSet() { + + String pwm_number = sCmd.next(); + String pwm_state = sCmd.next(); + int pwm_state_int = pwm_state.toInt(); + + int pin = jsonReadtoInt(optionJson, "pwm_pin" + pwm_number); + analogWrite(pin, pwm_state_int); + + eventGen ("pwmSet", pwm_number); + + jsonWrite(configJson, "pwmSet" + pwm_number, pwm_state); + sendSTATUS("pwmSet" + pwm_number, pwm_state); +} +//================================================================================================================== +//==========================================Модуль физической кнопки================================================ +void switch_ () { + + String switch_number = sCmd.next(); + String switch_pin = sCmd.next(); + String switch_delay = sCmd.next(); + + buttons[switch_number.toInt()].attach(switch_pin.toInt()); + buttons[switch_number.toInt()].interval(switch_delay.toInt()); + but[switch_number.toInt()] = true; +} + +void handleButton() { + + static uint8_t switch_number = 1; + + if (but[switch_number]) { + buttons[switch_number].update(); + if (buttons[switch_number].fell()) { + + eventGen ("switchSet", String(switch_number)); + + jsonWrite(configJson, "switchSet" + String(switch_number), "1"); + } + if (buttons[switch_number].rose()) { + + eventGen ("switchSet", String(switch_number)); + + jsonWrite(configJson, "switchSet" + String(switch_number), "0"); + } + } + switch_number++; + if (switch_number == NUM_BUTTONS) switch_number = 0; +} + +//===================================================================================================================================== +//=========================================Добавление окна ввода переменной============================================================ +void input() { + + String name_ = sCmd.next(); + String number = name_.substring(5); + String start_value = sCmd.next(); + String step_ = sCmd.next(); + String value_name = sCmd.next(); + String page_name = sCmd.next(); + String page_number = sCmd.next(); + + int psn1 = start_value.indexOf("."); //ищем позицию запятой + int digits = 0; + if (psn1 != -1) { //если она есть + String last_part = deleteBeforeDelimiter(start_value, "."); + digits = last_part.length() + 1; + } + + createViget ("", page_name, page_number, "vigets/viget.button.json", "valueDownSet" + number, "title", "-"); + createViget (value_name, page_name, String(page_number.toInt() + 1), "vigets/viget.alertbg.json", name_); + createViget ("", page_name, String(page_number.toInt() + 2), "vigets/viget.button.json", "valueUpSet" + number , "title", "+"); + + //jsonWrite(valuesJson, name_, start_value); + //saveValues (); + sendSTATUS(name_, start_value); + + jsonWrite(configJson, name_ + "step", step_); + jsonWrite(configJson, name_ + "digits", digits); +} + +void valueUpSet() { + String number = sCmd.next(); + float val = jsonRead(configJson, "value" + number).toFloat(); + float step_ = jsonRead(configJson, "value" + number + "step").toFloat(); + int digits = jsonRead(configJson, "value" + number + "digits").toInt(); + val = val + step_; + String val_str = String(val); + val_str = selectToMarkerPlus (val_str, ".", digits); + jsonWrite(configJson, "value" + number, val_str); + //jsonWrite(valuesJson, "value" + number, val_str); + //saveValues (); + sendSTATUS("value" + number, val_str); +} + +void valueDownSet() { + String number = sCmd.next(); + float val = jsonRead(configJson, "value" + number).toFloat(); + float step_ = jsonRead(configJson, "value" + number + "step").toFloat(); + int digits = jsonRead(configJson, "value" + number + "digits").toInt(); + val = val - step_; + String val_str = String(val); + val_str = selectToMarkerPlus (val_str, ".", digits); + jsonWrite(configJson, "value" + number, val_str); + //jsonWrite(valuesJson, "value" + number, val_str); + //saveValues (); + sendSTATUS("value" + number, val_str); +} + +//===================================================================================================================================== +//=========================================Добавление текстового виджета============================================================ +void text() { + + String number = sCmd.next(); + String viget_name = sCmd.next(); + String page_name = sCmd.next(); + String page_number = sCmd.next(); + + createViget (viget_name, page_name, page_number, "vigets/viget.alertsm.json", "textSet" + number); +} + + +void textSet() { + + String number = sCmd.next(); + String text = sCmd.next(); + text.replace("_", " "); + + if (text.indexOf("-time") >= 0) { + text.replace("-time", ""); + String time = GetTime(); + time.replace(":", "."); + text = GetDataDigital() + " " + time + " " + text; + } + + jsonWrite(configJson, "textSet" + number, text); + sendSTATUS("textSet" + number, text); +} + +//=================================================Глобальные команды удаленного управления=========================================================== + +void mqttOrderSend() { + + String id = sCmd.next(); + String order = sCmd.next(); + + String all_line = prefix + "/" + id + "/order"; + //Serial.print(all_line); + //Serial.print("->"); + //Serial.println(order); + int send_status = client.publish (all_line.c_str(), order.c_str(), false); +} + +void httpOrderSend() { + + String ip = sCmd.next(); + String order = sCmd.next(); + order.replace("_", "%20"); + String url = "http://" + ip + "/cmd?command=" + order; + getURL(url); +} + + + +//============================================================================================================================== +//============================выполнение команд (в лупе) по очереди из строки order============================================= +void handleCMD_loop() { + + if (order_loop != "") { + + String tmp = selectToMarker(order_loop, ","); //выделяем из страки order первую команду rel 5 1, + sCmd.readStr(tmp); //выполняем первую команду + Serial.println("[ORDER] => " + order_loop); + order_loop = deleteBeforeDelimiter(order_loop, ","); //осекаем выполненную команду + } +} + +//=============================выполнение команд (через период) по очереди из строки order======================================= +/*void handleCMD_ticker() { + + ts.add(CMD, CMD_update_int, [&](void*) { + if (!busy) { + if (order_ticker != "") { + + String tmp = selectToMarker(order_ticker, ","); //выделяем из страки order первую команду pus title body + if (tmp != "no_command") sCmd.readStr(tmp); //выполняем первую команду + Serial.println("order_ticker => " + order_ticker); + order_ticker = deleteBeforeDelimiter(order_ticker, ","); //осекаем выполненную команду + } + } + }, nullptr, true); + }*/ + + + +//======================================================================================================================================= +//======================================================================================================================================= +void txtExecution(String file) { + + String command_all = readFile(file, 2048) + "\r\n"; //2048 + + command_all.replace("\r\n", "\n"); + command_all.replace("\r", "\n"); + + while (command_all.length() != 0) { + + String tmp = selectToMarker (command_all, "\n"); + //if (tmp.indexOf("//") < 0) + sCmd.readStr(tmp); + command_all = deleteBeforeDelimiter(command_all, "\n"); + } +} +void stringExecution(String str) { + + String command_all = str + "\r\n"; //"\r\n" + + command_all.replace("\r\n", "\n"); + command_all.replace("\r", "\n"); + + while (command_all.length() != 0) { + + String tmp = selectToMarker (command_all, "\n"); + //if (tmp.indexOf("//") < 0) + sCmd.readStr(tmp); + command_all = deleteBeforeDelimiter(command_all, "\n"); + } +} + +//====================================================================================================================== +//===============================================Создание виджетов======================================================= + +void createViget (String viget_name, String page_name, String page_number, String file, String topic) { + + String viget; + viget = readFile(file, 1024); + + if (viget == "Failed") return; + if (viget == "Large") return; + + viget_name.replace("#", " "); + page_name.replace("#", " "); + + jsonWrite(viget, "page", page_name); + jsonWrite(viget, "pageId", page_number); + jsonWrite(viget, "descr", viget_name); + jsonWrite(viget, "topic", prex + "/" + topic); + all_vigets += viget + "\r\n"; + viget = ""; +} +void createViget (String viget_name, String page_name, String page_number, String file, String topic, String key, String value) { + + String viget; + viget = readFile(file, 1024); + + if (viget == "Failed") return; + if (viget == "Large") return; + + viget_name.replace("#", " "); + page_name.replace("#", " "); + + value.replace("#", " "); + + viget = vidgetConfigWrite(viget, key, value); + + jsonWrite(viget, "page", page_name); + jsonWrite(viget, "pageId", page_number); + jsonWrite(viget, "descr", viget_name); + jsonWrite(viget, "topic", prex + "/" + topic); + + all_vigets += viget + "\r\n"; + viget = ""; +} + +void createViget (String viget_name, String page_name, String page_number, String file, String topic, String key, String value, String key2, String value2) { + + String viget; + viget = readFile(file, 1024); + + if (viget == "Failed") return; + if (viget == "Large") return; + + viget_name.replace("#", " "); + page_name.replace("#", " "); + + value.replace("#", " "); + + viget = vidgetConfigWrite(viget, key, value); + viget = vidgetConfigWrite(viget, key2, value2); + + jsonWrite(viget, "page", page_name); + jsonWrite(viget, "pageId", page_number); + jsonWrite(viget, "descr", viget_name); + jsonWrite(viget, "topic", prex + "/" + topic); + + all_vigets += viget + "\r\n"; + viget = ""; +} + +String vidgetConfigWrite(String viget, String key, String value) { + + if (viget == "") return ""; + if (viget == "{}") return ""; + int psn1 = viget.indexOf("{"); + if (psn1 != -1) { + psn1 = viget.indexOf("{", psn1 + 1); + if (psn1 != -1) { + int psn2 = viget.indexOf("}", psn1); + String WigetConfig = viget.substring(psn1, psn2) + "}"; + jsonWrite(WigetConfig, key, value); + String part1 = viget.substring(0, psn1); + viget = part1 + WigetConfig + "}"; + return viget; + + } + } +} + + + + + + + + + + + + +//============разное + +/* + void delAlert() { + + String alert_id = sCmd.next(); + delViget(alert_id); + sendAllWigets(); + } + + + void delViget(String text_in_viget) { + String viget = all_vigets; + while (viget.length() != 0) { + String tmp = selectToMarkerPlus (viget, "\r\n", 2); + if (tmp.indexOf(text_in_viget) > 0) { + + all_vigets.replace(tmp, ""); + //Serial.println(all_vigets); + + viget = deleteBeforeDelimiter(viget, "\r\n"); + } else { + viget = deleteBeforeDelimiter(viget, "\r\n"); + } + } + } +*/ diff --git a/Init.ino b/Init.ino new file mode 100644 index 00000000..dcfca754 --- /dev/null +++ b/Init.ino @@ -0,0 +1,50 @@ +void All_init() { + + server.on("/all_modules_init", HTTP_GET, [](AsyncWebServerRequest * request) { + Device_init(); + request->send(200, "text/text", "OK"); // отправляем ответ о выполнении + }); + + + server.on("/scenario", HTTP_GET, [](AsyncWebServerRequest * request) { + if (request->hasArg("status")) { + jsonWrite(configSetup, "scenario", request->getParam("status")->value()); + } + saveConfig(); + Scenario_init(); + request->send(200, "text/text", "OK"); // отправляем ответ о выполнении + }); + + server.on("/cleanlog", HTTP_GET, [](AsyncWebServerRequest * request) { + SPIFFS.remove("/log.analog.txt"); + SPIFFS.remove("/log.dallas.txt"); + SPIFFS.remove("/log.level.txt"); + SPIFFS.remove("/log.ph.txt"); + SPIFFS.remove("/log.txt"); + request->send(200, "text/text", "OK"); // отправляем ответ о выполнении + }); + + Device_init(); + Scenario_init(); + Timer_countdown_init(); +} + +void Device_init() { + + ts.remove(LEVEL); + ts.remove(ANALOG_); + ts.remove(PH); + ts.remove(DALLAS); + + all_vigets = ""; + txtExecution("config.all.txt"); + //outcoming_date(); + +} +//-------------------------------сценарии----------------------------------------------------- + +void Scenario_init() { + if (jsonRead(configSetup, "scenario") == "1") { + scenario = readFile(scenarioFileNameS, 2048); + } +} diff --git a/Scenario.ino b/Scenario.ino new file mode 100644 index 00000000..8a1b5ac9 --- /dev/null +++ b/Scenario.ino @@ -0,0 +1,85 @@ +void handleScenario() { + + if (jsonRead(configSetup, "scenario") == "1") { + if ((jsonRead(optionJson, "scenario_status") != "")) { + int i = 0; + String str = scenario; //читаем переменную с сценариями (то что из файла на странице) + str += "\n"; + str.replace("\r\n", "\n"); + str.replace("\r", "\n"); + while (str.length() != 0) { + //----------------------------------------------------------------------------------------------------------------------- + String tmp = selectToMarker (str, "end"); //выделяем первый сценарий из файла вместе с командами + if (tmp == "") return; + i++; + + if (scenario_line_status[i] == 1) { + //Serial.println(i); + String condition = selectToMarker (tmp, "\n"); //выделяем первую строку самого сценария button1 = 1 (условие) + String param_name = selectFromMarkerToMarker(condition, " " , 0); //из первой страки берем имя параметра button1 и вставляем в него Set и получаем buttonSet1 + String num1 = param_name.substring(param_name.length() - 1); + String num2 = param_name.substring(param_name.length() - 2, param_name.length() - 1); + if (isDigitStr(num1) && isDigitStr(num2)) { + param_name = param_name.substring(0, param_name.length() - 2) + "Set" + num2 + num1; + } else { + if (isDigitStr(num1)) { + param_name = param_name.substring(0, param_name.length() - 1) + "Set" + num1; + } + } //преобразуем из button1 в вид buttonSet1 ,param_name = buttonSet1 + String order = jsonRead(optionJson, "scenario_status"); //читаем весь файл событий + String param = selectToMarker (order, ","); //читаем первое событие из файла событий + if (param_name == param) { //если поступившее событие равно событию заданному buttonSet1 в файле начинаем его обработку + + String sign = selectFromMarkerToMarker(condition, " " , 1); //читаем знак (=) + String value = selectFromMarkerToMarker(condition, " " , 2); //читаем значение (1) + if (value.indexOf("value") != -1) { + value = jsonRead(configJson, value); + } + boolean flag = false; //если одно из значений совпало то только тогда начинаем выполнять комнады + if (sign == "=") { + if (jsonRead(configJson, param_name) == value) flag = true; + } + if (sign == "!=") { + if (jsonRead(configJson, param_name) != value) flag = true; + } + if (sign == "<") { + if (jsonRead(configJson, param_name).toFloat() < value.toFloat()) flag = true; + } + if (sign == ">") { + if (jsonRead(configJson, param_name).toFloat() > value.toFloat()) flag = true; + } + if (sign == ">=") { + if (jsonRead(configJson, param_name).toFloat() >= value.toFloat()) flag = true; + } + if (sign == "<=") { + if (jsonRead(configJson, param_name).toFloat() <= value.toFloat()) flag = true; + } + + if (flag) { + tmp = deleteBeforeDelimiter(tmp, "\n"); //удаляем строку самого сценария оставляя только команды + stringExecution(tmp); //выполняем все команды + + Serial.println("[SCENARIO] '" + condition + "'"); + //Serial.println(" " + tmp); + } + } + } + str = deleteBeforeDelimiter(str, "end\n"); //удаляем первый сценарий + //----------------------------------------------------------------------------------------------------------------------- + } + String tmp2 = jsonRead(optionJson, "scenario_status"); //читаем файл событий + tmp2 = deleteBeforeDelimiter(tmp2, ","); //удаляем выполненное событие + jsonWrite(optionJson, "scenario_status", tmp2); //записываем обновленный файл событий + i = 0; + } + } +} + +void eventGen (String event_name, String number) { //событие выглядит как имя плюс set плюс номер: button+Set+1 + + if (jsonRead(configSetup, "scenario") == "1") { + String tmp = jsonRead(optionJson, "scenario_status") ; //генерирование события + //Serial.println(event_name); + jsonWrite(optionJson, "scenario_status", tmp + event_name + number + ","); + } +} diff --git a/Sensors.ino b/Sensors.ino new file mode 100644 index 00000000..d8c92552 --- /dev/null +++ b/Sensors.ino @@ -0,0 +1,315 @@ +//=============================================================================================================================== +//=========================================Модуль аналогового сенсора============================================================ +void analog() { + + static boolean flag = true; + String viget_name = sCmd.next(); + String page_name = sCmd.next(); + String type = sCmd.next(); + String analog_start = sCmd.next(); + String analog_end = sCmd.next(); + String analog_start_out = sCmd.next(); + String analog_end_out = sCmd.next(); + String page_number = sCmd.next(); + + jsonWrite(optionJson, "analog_start", analog_start); + jsonWrite(optionJson, "analog_end", analog_end); + jsonWrite(optionJson, "analog_start_out", analog_start_out); + jsonWrite(optionJson, "analog_end_out", analog_end_out); + + if (type == "text") createViget (viget_name, page_name, page_number, "vigets/viget.alertsm.json", "analog"); + if (type == "gauge") createViget (viget_name, page_name, page_number, "vigets/viget.fillgauge.json", "analog"); + if (type == "gauge2") createViget (viget_name, page_name, page_number, "vigets/viget.gauge.json", "analog", "maximum", analog_end_out); + if (type == "termometr") createViget (viget_name, page_name, page_number, "vigets/viget.termometr.json", "analog", "titleString", viget_name); + + ts.add(ANALOG_, analog_update_int, [&](void*) { + + static int analog_old; + + int analog_in = analogRead(35); + jsonWrite(configJson, "analog_in", analog_in); + + int analog = map(analog_in, + jsonReadtoInt(optionJson, "analog_start") , + jsonReadtoInt(optionJson, "analog_end"), + jsonReadtoInt(optionJson, "analog_start_out"), + jsonReadtoInt(optionJson, "analog_end_out")); + + jsonWrite(configJson, "analog", analog); + + // if (analog_old != analog) { + + eventGen ("analog", ""); + sendSTATUS("analog", String(analog)); + if (client.connected()) { + Serial.println("[i] sensor analog send date " + String(analog)); + } + // } + analog_old = analog; + }, nullptr, true); +} + +//=============================================================================================================================== +//=========================================Модуль аналогового сенсора============================================================ +void ph() { + + String viget_name = sCmd.next(); + String page_name = sCmd.next(); + String type = sCmd.next(); + String offset = sCmd.next(); + String page_number = sCmd.next(); + + jsonWrite(optionJson, "ph_offset", offset); + + if (type == "text") createViget (viget_name, page_name, page_number, "vigets/viget.alertsm.json", "ph"); + if (type == "gauge") createViget (viget_name, page_name, page_number, "vigets/viget.fillgauge.json", "ph"); + if (type == "gauge2") createViget (viget_name, page_name, page_number, "vigets/viget.gauge.json", "ph"); + if (type == "termometr") createViget (viget_name, page_name, page_number, "vigets/viget.termometr.json", "ph", "titleString", viget_name); + + + ts.add(PH, ph_shooting_interval, [&](void*) { + + static float pHValue_old; + static int counter; + + float offset = jsonRead(optionJson, "ph_offset").toFloat(); + + int analog = analogRead(A0); + analog = medianFilter.filtered(analog); + float voltage = analog * 3.2 / 1024; + float pHValue = 3.5 * voltage + offset; + String pHValue_str = String(pHValue); + + pHValue_str = selectToMarkerPlus(pHValue_str, "." , 2); + + counter++; + + if (counter > ph_times_to_send) { + counter = 0; + + jsonWrite(configJson, "ph", pHValue_str); + + //if (pHValue_old != pHValue) { + + eventGen ("ph", ""); + sendSTATUS("ph", pHValue_str); + if (client.connected()) { + Serial.println("[i] sensor ph send date " + pHValue_str); + Serial.println("voltage " + String(voltage)); + } + //} + pHValue_old = pHValue; + } + }, nullptr, true); +} +//=================================================================================================================================== +//=========================================Модуль измерения уровня в баке============================================================ +void level() { + + static boolean flag = true; + String viget_name = sCmd.next(); + String page_name = sCmd.next(); + String type = sCmd.next(); + String empty_level = sCmd.next(); + String full_level = sCmd.next(); + String page_number = sCmd.next(); + + jsonWrite(optionJson, "empty_level", empty_level); + jsonWrite(optionJson, "full_level", full_level); + + pinMode(14, OUTPUT); + pinMode(12, INPUT); + + if (type == "text") createViget (viget_name, page_name, page_number, "vigets/viget.alertsm.json", "level"); + if (type == "gauge") createViget (viget_name, page_name, page_number, "vigets/viget.fillgauge.json", "level"); + if (type == "gauge2") createViget (viget_name, page_name, page_number, "vigets/viget.gauge.json", "level", "maximum", "100"); + if (type == "termometr") createViget (viget_name, page_name, page_number, "vigets/viget.termometr.json", "level", "titleString", viget_name); + + ts.add(LEVEL, tank_level_shooting_interval, [&](void*) { + + long duration_; + int distance_cm; + int level; + static int level_old; //переменная static сохраняет свое значение между вызовами функции + static int counter; + + digitalWrite(14, LOW); + delayMicroseconds(2); + digitalWrite(14, HIGH); + delayMicroseconds(10); + digitalWrite(14, LOW); + duration_ = pulseIn(12, HIGH, 30000); // 3000 µs = 50cm // 30000 µs = 5 m + distance_cm = duration_ / 29 / 2; + distance_cm = medianFilter.filtered(distance_cm);//отсечение промахов медианным фильтром + + counter++; + + if (counter > tank_level_times_to_send) { + counter = 0; + jsonWrite(configJson, "level_in", distance_cm); + + level = map(distance_cm, + jsonReadtoInt(optionJson, "empty_level"), + jsonReadtoInt(optionJson, "full_level"), 0, 100); + + //jsonWrite(configJson, "level", level); + + //if (level_old != level) { + + eventGen ("level", ""); + sendSTATUS("level", String(level)); + if (client.connected()) { + Serial.println("[i] sensor tank level send date " + String(level)); + } + //} + level_old = level; + } + }, nullptr, true); +} + +//========================================================================================================================================== +//=========================================Модуль температурного сенсора ds18b20============================================================ +void dallas() { + + static boolean flag = true; + String pin = sCmd.next(); + String viget_name = sCmd.next(); + String page_name = sCmd.next(); + String type = sCmd.next(); + String page_number = sCmd.next(); + + oneWire = new OneWire((uint8_t) pin.toInt()); + sensors.setOneWire(oneWire); + sensors.begin(); + sensors.setResolution(12); + + if (type == "text") createViget (viget_name, page_name, page_number, "vigets/viget.alertsm.json", "dallas"); + if (type == "gauge") createViget (viget_name, page_name, page_number, "vigets/viget.fillgauge.json", "dallas"); + if (type == "gauge2") createViget (viget_name, page_name, page_number, "vigets/viget.gauge.json", "dallas"); + if (type == "termometr") createViget (viget_name, page_name, page_number, "vigets/viget.termometr.json", "dallas", "titleString", viget_name); + + ts.add(DALLAS, temp_update_int, [&](void*) { + + float temp = 0; + static float temp_old; + sensors.requestTemperatures(); + temp = sensors.getTempCByIndex(0); + + jsonWrite(configJson, "dallas", String(temp)); + + //if (temp_old != temp) { + + eventGen ("dallas", ""); + sendSTATUS("dallas", String(temp)); + if (client.connected()) { + Serial.println("[i] sensor dallas send date " + String(temp)); + } + //} + + temp_old = temp; + }, nullptr, true); +} + +//====================================================================================================================== +//===============================================Логирование============================================================ + +void logging() { + + static boolean flag = true; + + String sensor_name = sCmd.next(); + String period_min = sCmd.next(); + String maxCount = sCmd.next(); + String viget_name = sCmd.next(); + viget_name.replace("#", " "); + String page_name = sCmd.next(); + String page_number = sCmd.next(); + + if (sensor_name == "analog") jsonWrite(optionJson, "analog_logging_count", maxCount); + if (sensor_name == "level") jsonWrite(optionJson, "level_logging_count", maxCount); + if (sensor_name == "dallas") jsonWrite(optionJson, "dallas_logging_count", maxCount); + if (sensor_name == "ph") jsonWrite(optionJson, "ph_logging_count", maxCount); + + if (sensor_name == "analog") createViget (viget_name, page_name, page_number, "vigets/viget.chart.json", "loganalog", "maxCount", maxCount); + if (sensor_name == "level") createViget (viget_name, page_name, page_number, "vigets/viget.chart.json", "loglevel", "maxCount", maxCount); + if (sensor_name == "dallas") createViget (viget_name, page_name, page_number, "vigets/viget.chart.json", "logdallas", "maxCount", maxCount); + if (sensor_name == "ph") createViget (viget_name, page_name, page_number, "vigets/viget.chart.json", "logph", "maxCount", maxCount); + + if (sensor_name == "analog") { + flagLoggingAnalog = true; + ts.remove(ANALOG_LOG); + ts.add(ANALOG_LOG, period_min.toInt() * 1000 * 60, [&](void*) { + deleteOldDate("log.analog.txt", jsonReadtoInt(optionJson, "analog_logging_count"), jsonRead(configJson, "analog"), false); + }, nullptr, true); + } + + if (sensor_name == "level") { + flagLoggingLevel = true; + ts.remove(LEVEL_LOG); + ts.add(LEVEL_LOG, period_min.toInt() * 1000 * 60, [&](void*) { + deleteOldDate("log.level.txt", jsonReadtoInt(optionJson, "level_logging_count"), jsonRead(configJson, "level"), false); + }, nullptr, true); + } + + if (sensor_name == "dallas") { + flagLoggingDallas = true; + ts.remove(DALLAS_LOG); + ts.add(DALLAS_LOG, period_min.toInt() * 1000 * 60, [&](void*) { + deleteOldDate("log.dallas.txt", jsonReadtoInt(optionJson, "dallas_logging_count"), jsonRead(configJson, "dallas"), false); + }, nullptr, true); + } + + if (sensor_name == "ph") { + flagLoggingPh = true; + ts.remove(PH_LOG); + ts.add(PH_LOG, period_min.toInt() * 1000 * 60, [&](void*) { + deleteOldDate("log.ph.txt", jsonReadtoInt(optionJson, "ph_logging_count"), jsonRead(configJson, "ph"), false); + }, nullptr, true); + } +} + +void deleteOldDate(String file, int seted_number_of_lines, String date_to_add, boolean date_time) { + + String current_time; + + if (date_time) { + current_time = GetDataDigital() + " " + GetTimeWOsec(); + current_time.replace(".", ""); + current_time.replace(":", ""); + } else { + current_time = ""; + } + + String log_date = readFile(file, 5000); + getMemoryLoad("[i] after logging procedure"); + + //предел количества строк 255 + + log_date.replace("\r\n", "\n"); + log_date.replace("\r", "\n"); + + int current_number_of_lines = count(log_date, "\n"); + Serial.println("[i] in log file " + file + " " + current_number_of_lines + " lines"); + + + if (current_number_of_lines > seted_number_of_lines + 1) { + SPIFFS.remove("/" + file); + current_number_of_lines = 0; + } + if (current_number_of_lines == 0) { + SPIFFS.remove("/" + file); + current_number_of_lines = 0; + } + if (current_number_of_lines > seted_number_of_lines) { + log_date = deleteBeforeDelimiter(log_date, "\n"); + log_date += current_time + " " + date_to_add + "\n"; + writeFile(file, log_date); + + } else { + if (date_time) { + addFile(file, current_time + " " + date_to_add); + } else { + addFile(file, date_to_add); + } + } +} diff --git a/Time_esp32.ino b/Time_esp32.ino new file mode 100644 index 00000000..d70ceb99 --- /dev/null +++ b/Time_esp32.ino @@ -0,0 +1,20 @@ +#ifdef ESP32 + +void Time_Init() { + + //init and get the time + configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); + printLocalTime(); + +} + +void printLocalTime() { + struct tm timeinfo; + if (!getLocalTime(&timeinfo)) { + Serial.println("[E] Failed to obtain time"); + return; + } + Serial.println(&timeinfo, "[V] %A, %B %d %Y %H:%M:%S"); +} + +#endif diff --git a/Time_esp8266.ino b/Time_esp8266.ino new file mode 100644 index 00000000..7b75a4d8 --- /dev/null +++ b/Time_esp8266.ino @@ -0,0 +1,112 @@ +#ifdef ESP8266 + +#include +void Time_Init() { + server.on("/Time", HTTP_GET, [](AsyncWebServerRequest * request) { + //handle_Time(); + request->send(200, "text/text", "OK"); // отправляем ответ о выполнении + }); + server.on("/timeZone", HTTP_GET, [](AsyncWebServerRequest * request) { + //handle_time_zone(); + request->send(200, "text/text", "OK"); // отправляем ответ о выполнении + }); + + timeSynch(jsonReadtoInt(configSetup, "timezone")); +} + + +void timeSynch(int zone) { + if (WiFi.status() == WL_CONNECTED) { + // Настройка соединения с NTP сервером + configTime(zone * 3600, 0, "pool.ntp.org", "ru.pool.ntp.org"); + // int i = 0; + // Serial.println("\nWaiting for time"); + // while (!time(nullptr) && i < 10) { + // Serial.print("."); + // i++; + // delay(1000); + // } + Serial.println(""); + Serial.println("ITime Ready!"); + delay(1000); + Serial.println(GetTime()); + Serial.println(GetDate()); + } +} +/*// Установка параметров времянной зоны по запросу вида http://192.168.0.101/timeZone?timeZone=3 +void handle_time_zone() { + if (request->hasArg("timeZone")) { + jsonWrite(configSetup, "timeZone", request->getParam("timeZone")->value()); + } + saveConfig(); + //request->send(200, "text/text", "OK"); +} + +void handle_Time() { + timeSynch(jsonReadtoInt(configSetup, "timezone")); + //request->send(200, "text/text", "OK"); +} +*/ +#endif + +// Получение текущего времени +String GetTime() { + time_t now = time(nullptr); // получаем время с помощью библиотеки time.h + String Time = ""; // Строка для результатов времени + Time += ctime(&now); // Преобразуем время в строку формата Thu Jan 19 00:55:35 2017 + int i = Time.indexOf(":"); //Ишем позицию первого символа : + Time = Time.substring(i - 2, i + 6); // Выделяем из строки 2 символа перед символом : и 6 символов после + return Time; // Возврашаем полученное время +} + +String GetTimeWOsec() { + time_t now = time(nullptr); // получаем время с помощью библиотеки time.h + String Time = ""; // Строка для результатов времени + Time += ctime(&now); // Преобразуем время в строку формата Thu Jan 19 00:55:35 2017 + int i = Time.indexOf(":"); //Ишем позицию первого символа : + Time = Time.substring(i - 2, i + 3); // Выделяем из строки 2 символа перед символом : и 6 символов после + return Time; // Возврашаем полученное время +} + +// Получение даты +String GetDate() { + time_t now = time(nullptr); // получаем время с помощью библиотеки time.h + String Data = ""; // Строка для результатов времени + Data += ctime(&now); // Преобразуем время в строку формата Thu Jan 19 00:55:35 2017 + Data.replace("\n", ""); + uint8_t i = Data.lastIndexOf(" "); //Ишем позицию последнего символа пробел + String Time = Data.substring(i - 8, i + 1); // Выделяем время и пробел + Data.replace(Time, ""); // Удаляем из строки 8 символов времени и пробел + return Data; // Возврашаем полученную дату +} + +String GetDataDigital() { + String date = GetDate(); + + date = deleteBeforeDelimiter(date, " "); + + date.replace("Jan", "01"); + date.replace("Feb", "02"); + date.replace("Mar", "03"); + date.replace("Apr", "04"); + date.replace("May", "05"); + date.replace("Jun", "06"); + date.replace("Jul", "07"); + date.replace("Aug", "08"); + date.replace("Sep", "09"); + date.replace("Oct", "10"); + date.replace("Nov", "11"); + date.replace("Dec", "12"); + + String month = date.substring(0, 2); + String day = date.substring(3, 5); + String year = date.substring(8, 10); + + String out = day; + out += "."; + out += month; + out += "."; + out += year; + + return out; +} diff --git a/Timers.ino b/Timers.ino new file mode 100644 index 00000000..37dc9fb9 --- /dev/null +++ b/Timers.ino @@ -0,0 +1,184 @@ +//================================================================================================================ +//=========================================Таймера================================================================= +void Timer_countdown_init() { + + ts.add(TIMER_COUNTDOWN, 1000, [&](void*) { + + String old_line = jsonRead(optionJson, "timers"); + + + if (old_line != "") { + + Serial.println(old_line); + + int i = 0; + + do { + + String timer = selectFromMarkerToMarker(old_line, "," , i); + // Serial.print("timer no " + String (i) + ": "); + // Serial.println(timer); + if (timer == "not found" || timer == "") return; + int number = selectToMarker (timer, ":").toInt(); + int time = readTimer(number); + if (time == 0) { + + delTimer (String (number)); + + jsonWrite(configJson, "timerSet" + String(number), "0"); + + eventGen ("timerSet", String(number)); + + } else { + time--; + addTimer(String (number), String (time)); + } + i++; + } while (i <= 9); + + } + }, nullptr, true); +} + + + +void timerStart() { + + String number = sCmd.next(); + String period_of_time = sCmd.next(); + String type = sCmd.next(); + + if (period_of_time.indexOf("value") != -1) { + period_of_time = jsonRead(configJson, period_of_time); + } + + if (type == "sec") period_of_time = period_of_time; + if (type == "min") period_of_time = String(period_of_time.toInt() * 60); + if (type == "hours") period_of_time = String(period_of_time.toInt() * 60 * 60); + + addTimer(number, period_of_time); + jsonWrite(configJson, "timerSet" + number, "1"); +} +void addTimer(String number, String time) { + + String tmp = jsonRead(optionJson, "timers"); //1:60,2:120, + String new_timer = number + ":" + time; + int psn1 = tmp.indexOf(number + ":"); //0 ищем позицию таймера который надо заменить + + if (psn1 != -1) { //если он есть + + int psn2 = tmp.indexOf(",", psn1); //4 от этой позиции находим позицию запятой + + String timer = tmp.substring(psn1, psn2); //1:60 выделяем таймер который надо заменить + ///tmp.replace(timer, new_timer); //заменяем таймер на новый (во всей стороке) + tmp.replace(timer + ",", ""); + tmp += new_timer + ","; + + } else { //если его нет + tmp += new_timer + ","; + } + jsonWrite(optionJson, "timers", tmp); + //Serial.println("ura"); +} + + +void timerStop() { + + String number = sCmd.next(); + delTimer(number); + +} +void delTimer (String number) { + + String tmp = jsonRead(optionJson, "timers"); //1:60,2:120, + int psn1 = tmp.indexOf(number + ":"); //0 ищем позицию таймера который надо удалить + + if (psn1 != -1) { //если он есть + int psn2 = tmp.indexOf(",", psn1); //4 от этой позиции находим позицию запятой + String timer = tmp.substring(psn1, psn2) + ","; //1:60, выделяем таймер который надо удалить + tmp.replace(timer, ""); //удаляем таймер + jsonWrite(optionJson, "timers", tmp); + } +} + +int readTimer(int number) { + + String tmp = jsonRead(optionJson, "timers"); //1:60,2:120, + + int psn1 = tmp.indexOf(String(number) + ":"); //0 ищем позицию таймера который надо прочитать + + String timer; + + if (psn1 != -1) { //если он есть + int psn2 = tmp.indexOf(",", psn1); //4 от этой позиции находим позицию запятой + timer = tmp.substring(psn1, psn2); //1:60 выделяем таймер который надо прочитать + timer = deleteBeforeDelimiter(timer, ":"); + } + return timer.toInt(); +} + +/*void timer() { + + String seted_time = sCmd.next(); + String order = sCmd.next(); + order.replace("_", " "); + if (seted_time == current_time) { + + order_loop += order + ","; + + } +}*/ + +//------------------------------таймеры------------------------------------------------------ +void time() { + + String time_number = sCmd.next(); + String time = sCmd.next(); + + String time_to_add = time_number + "-" + time; + + String replace_line = jsonRead(optionJson, "times") ; + int psn1 = replace_line.indexOf(time_number + "-") ; //ищем позицию времени которое надо заменить + + if (psn1 != -1) { //если оно есть + + int psn2 = replace_line.indexOf(",", psn1); //от этой позиции находим позицию запятой + + String timer = replace_line.substring(psn1, psn2); //выделяем таймер который надо заменить + ///tmp.replace(timer, new_timer); //заменяем таймер на новый (во всей стороке) + replace_line.replace(timer + ",", ""); + replace_line += time_to_add + ","; + + } else { //если его нет + replace_line += time_to_add + ","; + } + + + jsonWrite(optionJson, "times", replace_line); + + jsonWrite(configJson, "timeSet" + time_number, "1"); + + ts.add(TIMERS, 1000, [&](void*) { + + current_time = GetTime(); + Serial.println(current_time); + + String seted_times = jsonRead(optionJson, "times"); + + while (seted_times.length() != 0) { + String tmp = selectToMarker (seted_times, ","); + + String time_number = selectToMarker(tmp, "-"); + String seted_time = deleteBeforeDelimiter(tmp, "-"); + + Serial.println(seted_time); + + if (current_time == seted_time) { + jsonWrite(configJson, "timeSet" + time_number, "0"); + eventGen ("timeSet", time_number); + } + + seted_times = deleteBeforeDelimiter(seted_times, ","); + } + }, nullptr, true); +} diff --git a/Web_server.ino b/Web_server.ino new file mode 100644 index 00000000..0cb5a214 --- /dev/null +++ b/Web_server.ino @@ -0,0 +1,222 @@ +void Web_server_init() { + +//========================================OTA============================================ +#ifdef OTA_enable + //Send OTA events to the browser + ArduinoOTA.onStart([]() { + events.send("Update Start", "ota"); + }); + + ArduinoOTA.onEnd([]() { + events.send("Update End", "ota"); + }); + + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { + char p[32]; + sprintf(p, "Progress: %u%%\n", (progress / (total / 100))); + events.send(p, "ota"); + }); + + ArduinoOTA.onError([](ota_error_t error) { + if (error == OTA_AUTH_ERROR) events.send("Auth Failed", "ota"); + else if (error == OTA_BEGIN_ERROR) events.send("Begin Failed", "ota"); + else if (error == OTA_CONNECT_ERROR) events.send("Connect Failed", "ota"); + else if (error == OTA_RECEIVE_ERROR) events.send("Recieve Failed", "ota"); + else if (error == OTA_END_ERROR) events.send("End Failed", "ota"); + }); + ArduinoOTA.setHostname(hostName); + + ArduinoOTA.begin(); +#endif +//========================================MDNS============================================ +#ifdef MDNS_enable + MDNS.addService("http", "tcp", 80); +#endif + + //SPIFFS.begin(); + +//========================================WS============================================ +#ifdef WS_enable + ws.onEvent(onWsEvent); + server.addHandler(&ws); + + events.onConnect([](AsyncEventSourceClient * client) { + client->send("hello!", NULL, millis(), 1000); + }); + + server.addHandler(&events); +#endif +//====================================================================================== + +#ifdef ESP32 + server.addHandler(new SPIFFSEditor(SPIFFS, http_username, http_password)); +#elif defined(ESP8266) + server.addHandler(new SPIFFSEditor(http_username, http_password)); +#endif + + server.on("/heap", HTTP_GET, [](AsyncWebServerRequest * request) { + request->send(200, "text/plain", String(ESP.getFreeHeap())); + }); + + + server.serveStatic("/css/", SPIFFS, "/css/").setCacheControl("max-age=31536000"); + server.serveStatic("/js/", SPIFFS, "/js/").setCacheControl("max-age=31536000"); + server.serveStatic("/", SPIFFS, "/favicon.ico").setCacheControl("max-age=31536000"); + + server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.htm") + .setAuthentication(http_username, http_password); + + + server.onNotFound([](AsyncWebServerRequest * request) { + Serial.printf("NOT_FOUND: "); + if (request->method() == HTTP_GET) + Serial.printf("GET"); + else if (request->method() == HTTP_POST) + Serial.printf("POST"); + else if (request->method() == HTTP_DELETE) + Serial.printf("DELETE"); + else if (request->method() == HTTP_PUT) + Serial.printf("PUT"); + else if (request->method() == HTTP_PATCH) + Serial.printf("PATCH"); + else if (request->method() == HTTP_HEAD) + Serial.printf("HEAD"); + else if (request->method() == HTTP_OPTIONS) + Serial.printf("OPTIONS"); + else + Serial.printf("UNKNOWN"); + Serial.printf(" http://%s%s\n", request->host().c_str(), request->url().c_str()); + + if (request->contentLength()) { + Serial.printf("_CONTENT_TYPE: %s\n", request->contentType().c_str()); + Serial.printf("_CONTENT_LENGTH: %u\n", request->contentLength()); + } + + int headers = request->headers(); + int i; + for (i = 0; i < headers; i++) { + AsyncWebHeader* h = request->getHeader(i); + Serial.printf("_HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str()); + } + + int params = request->params(); + for (i = 0; i < params; i++) { + AsyncWebParameter* p = request->getParam(i); + if (p->isFile()) { + Serial.printf("_FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size()); + } else if (p->isPost()) { + Serial.printf("_POST[%s]: %s\n", p->name().c_str(), p->value().c_str()); + } else { + Serial.printf("_GET[%s]: %s\n", p->name().c_str(), p->value().c_str()); + } + } + + request->send(404); + }); + server.onFileUpload([](AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t *data, size_t len, bool final) { + if (!index) + Serial.printf("UploadStart: %s\n", filename.c_str()); + Serial.printf("%s", (const char*)data); + if (final) + Serial.printf("UploadEnd: %s (%u)\n", filename.c_str(), index + len); + }); + server.onRequestBody([](AsyncWebServerRequest * request, uint8_t *data, size_t len, size_t index, size_t total) { + if (!index) + Serial.printf("BodyStart: %u\n", total); + Serial.printf("%s", (const char*)data); + if (index + len == total) + Serial.printf("BodyEnd: %u\n", total); + }); + + server.begin(); + + //=============================Устанавливаем реакции на запросы к серверу============================ + + // --------------------Выдаем данные configJson //config.live.json - динамические данные + server.on("/config.live.json", HTTP_GET, [](AsyncWebServerRequest * request) { + request->send(200, "application/json", configJson); + }); + // --------------------Выдаем данные optionJson //config.option.json - данные не являющиеся событиями + server.on("/config.option.json", HTTP_GET, [](AsyncWebServerRequest * request) { + request->send(200, "application/json", optionJson); + }); + // -------------------Выдаем данные configSetup //config.setup.json - для хранения постоянных данных + server.on("/config.setup.json", HTTP_GET, [](AsyncWebServerRequest * request) { + request->send(200, "application/json", configSetup); + }); +} +//========================================WS========================================================================================= +#ifdef WS_enable +void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len) { + if (type == WS_EVT_CONNECT) { + Serial.printf("ws[%s][%u] connect\n", server->url(), client->id()); + client->printf(configJson.c_str(), client->id()); + client->ping(); + } else if (type == WS_EVT_DISCONNECT) { + Serial.printf("ws[%s][%u] disconnect\n", server->url(), client->id()); + } else if (type == WS_EVT_ERROR) { + Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t*)arg), (char*)data); + } else if (type == WS_EVT_PONG) { + Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len) ? (char*)data : ""); + } else if (type == WS_EVT_DATA) { + AwsFrameInfo * info = (AwsFrameInfo*)arg; + String msg = ""; + if (info->final && info->index == 0 && info->len == len) { + //the whole message is in a single frame and we got all of it's data + Serial.printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT) ? "text" : "binary", info->len); + + if (info->opcode == WS_TEXT) { + for (size_t i = 0; i < info->len; i++) { + msg += (char) data[i]; + } + } else { + char buff[3]; + for (size_t i = 0; i < info->len; i++) { + sprintf(buff, "%02x ", (uint8_t) data[i]); + msg += buff ; + } + } + Serial.printf("%s\n", msg.c_str()); + + if (info->opcode == WS_TEXT) + client->text("{}"); + else + client->binary("{}"); + } else { + //message is comprised of multiple frames or the frame is split into multiple packets + if (info->index == 0) { + if (info->num == 0) + Serial.printf("ws[%s][%u] %s-message start\n", server->url(), client->id(), (info->message_opcode == WS_TEXT) ? "text" : "binary"); + Serial.printf("ws[%s][%u] frame[%u] start[%llu]\n", server->url(), client->id(), info->num, info->len); + } + + Serial.printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT) ? "text" : "binary", info->index, info->index + len); + + if (info->opcode == WS_TEXT) { + for (size_t i = 0; i < len; i++) { + msg += (char) data[i]; + } + } else { + char buff[3]; + for (size_t i = 0; i < len; i++) { + sprintf(buff, "%02x ", (uint8_t) data[i]); + msg += buff ; + } + } + Serial.printf("%s\n", msg.c_str()); + + if ((info->index + len) == info->len) { + Serial.printf("ws[%s][%u] frame[%u] end[%llu]\n", server->url(), client->id(), info->num, info->len); + if (info->final) { + Serial.printf("ws[%s][%u] %s-message end\n", server->url(), client->id(), (info->message_opcode == WS_TEXT) ? "text" : "binary"); + if (info->message_opcode == WS_TEXT) + client->text("I got your text message"); + else + client->binary("I got your binary message"); + } + } + } + } +} +#endif +//=================================================================================================================================== diff --git a/WiFi.ino b/WiFi.ino new file mode 100644 index 00000000..280b0dd2 --- /dev/null +++ b/WiFi.ino @@ -0,0 +1,188 @@ +void WIFI_init() { + + // --------------------Получаем ssid password со страницы + server.on("/ssid", HTTP_GET, [](AsyncWebServerRequest * request) { + if (request->hasArg("ssid")) { + jsonWrite(configSetup, "ssid", request->getParam("ssid")->value()); + } + if (request->hasArg("password")) { + jsonWrite(configSetup, "password", request->getParam("password")->value()); + } + saveConfig(); // Функция сохранения данных во Flash + request->send(200, "text/text", "OK"); // отправляем ответ о выполнении + }); + // --------------------Получаем ssidAP passwordAP со страницы + server.on("/ssidap", HTTP_GET, [](AsyncWebServerRequest * request) { + if (request->hasArg("ssidAP")) { + jsonWrite(configSetup, "ssidAP", request->getParam("ssidAP")->value()); + } + if (request->hasArg("passwordAP")) { + jsonWrite(configSetup, "passwordAP", request->getParam("passwordAP")->value()); + } + saveConfig(); // Функция сохранения данных во Flash + request->send(200, "text/text", "OK"); // отправляем ответ о выполнении + }); + + + // Попытка подключения к точке доступа + + WiFi.mode(WIFI_STA); + + byte tries = 20; + String _ssid = jsonRead(configSetup, "ssid"); + String _password = jsonRead(configSetup, "password"); + //WiFi.persistent(false); + + if (_ssid == "" && _password == "") { + WiFi.begin(); + } + else { + WiFi.begin(_ssid.c_str(), _password.c_str()); + } + // Делаем проверку подключения до тех пор пока счетчик tries + // не станет равен нулю или не получим подключение + while (--tries && WiFi.status() != WL_CONNECTED) + { + if (WiFi.status() == WL_CONNECT_FAILED) { + Serial.println("[E] password is not correct"); + tries = 1; + jsonWrite(optionJson, "pass_status", 1); + } + Serial.print("."); + delay(1000); + } + + if (WiFi.status() != WL_CONNECTED) + { + // Если не удалось подключиться запускаем в режиме AP + Serial.println(""); + // WiFi.disconnect(true); + StartAPMode(); + + } + else { + // Иначе удалось подключиться отправляем сообщение + // о подключении и выводим адрес IP + Serial.println(""); + Serial.println("[V] WiFi connected"); + Serial.println("[V] IP address: "); + Serial.println(WiFi.localIP()); + jsonWrite(configJson, "ip", WiFi.localIP().toString()); + + } +} + +bool StartAPMode() { + /* + Serial.println("WiFi up AP"); + IPAddress apIP(192, 168, 4, 1); + IPAddress staticGateway(192, 168, 4, 1); + IPAddress staticSubnet(255, 255, 255, 0); + WiFi.disconnect(); + WiFi.mode(WIFI_AP); + WiFi.softAPConfig(apIP, staticGateway, staticSubnet); + String _ssidAP = jsonRead(configSetup, "ssidAP"); + String _passwordAP = jsonRead(configSetup, "passwordAP"); + WiFi.softAP(_ssidAP.c_str(), _passwordAP.c_str()); + jsonWrite(configJson, "ip", apIP.toString()); + */ + Serial.println("WiFi up AP"); + WiFi.disconnect(); + + WiFi.mode(WIFI_AP); + + String _ssidAP = jsonRead(configSetup, "ssidAP"); + String _passwordAP = jsonRead(configSetup, "passwordAP"); + WiFi.softAP(_ssidAP.c_str(), _passwordAP.c_str()); + IPAddress myIP = WiFi.softAPIP(); + Serial.print("AP IP address: "); + Serial.println(myIP); + + if (jsonReadtoInt(optionJson, "pass_status") != 1) { + ts.add(ROUTER_SEARCHING, 30 * 1000, [&](void*) { + Serial.println("->try find router"); + if (RouterFind(jsonRead(configSetup, "ssid"))) { + ts.remove(ROUTER_SEARCHING); + WIFI_init(); + MQTT_init(); + } + }, nullptr, true); + } + return true; +} + + +boolean RouterFind(String ssid) { + int n = WiFi.scanComplete (); + if (n == -2) { //Сканирование не было запущено, запускаем + WiFi.scanNetworks (true, false); //async, show_hidden + return false; + } + if (n == -1) { //Сканирование все еще выполняется + return false; + } + if (n > 0) { + for (int i = 0; i <= n; i++) { + if (WiFi.SSID (i) == ssid) { + WiFi.scanDelete(); + return true; + } else { + Serial.print(i); + Serial.print(")"); + Serial.print(ssid); + Serial.print("<=>"); + Serial.println(WiFi.SSID(i)); + } + } + WiFi.scanDelete(); + return false; + } +} + + +/* + boolean RouterFind(String ssid) { + + int n = WiFi.scanComplete(); + + Serial.print("status="); + Serial.println(n); + + if (n == -2) { //Сканирование не было запущено, запускаем + Serial.println("->enter to scanning function"); + WiFi.mode(WIFI_AP); + WiFi.scanNetworks (true, false, false, 5000); //async, show_hidden + Serial.println("->out of scanning function"); + return false; + + } + if (n == -1) { //Сканирование все еще выполняется + Serial.println("->scanning in progress"); + return false; + + } + if (n > 0) { //Найдено несколько сетей + for (int i = 0; i <= n; i++) { + if (WiFi.SSID(i) == ssid) { + Serial.println("router found"); + WiFi.scanDelete(); + return true; + } else { + Serial.print(i); + Serial.print(")"); + Serial.print(ssid); + Serial.print("<=>"); + Serial.println(WiFi.SSID(i)); + } + } + WiFi.scanDelete(); + Serial.println("->scanning deleted"); + return false; + } + } + + void wifi_reset() { + WiFi.mode(WIFI_STA); + WiFi.disconnect(true, true); + } +*/ diff --git a/certificates.ino b/certificates.ino new file mode 100644 index 00000000..e3fcfeaf --- /dev/null +++ b/certificates.ino @@ -0,0 +1,72 @@ +/* +const char* local_root_ca1 = \ + "-----BEGIN CERTIFICATE-----\n" \ + "MIIFdDCCBFygAwIBAgIQJ2buVutJ846r13Ci/ITeIjANBgkqhkiG9w0BAQwFADBv\n" \ + "MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk\n" \ + "ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF\n" \ + "eHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFow\n" \ + "gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO\n" \ + "BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD\n" \ + "VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkq\n" \ + "hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNw\n" \ + "AHG8U9/E+ioSj0t/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR6\n" \ + "2RRr55yzhaCCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onr\n" \ + "ayzT7Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt\n" \ + "4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSENnTnIq\n" \ + "m1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK8sYxrfV8g/\n" \ + "vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0Czr56ENCHonYhMsT\n" \ + "8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0iTMARgexWO/bTouJbt7IE\n" \ + "IlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31BqVUa/oKMoYX9w0MOiqiwhqkfO\n" \ + "KJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3xaG4Nj/QN370EKIf6MzOi5cHkERgWPO\n" \ + "GHFrK+ymircxXDpqR+DDeVnWIBqv8mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/\n" \ + "s1Hap0flhFMCAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBStvZh6NLQm9/rEJlTvA73g\n" \ + "JMtUGjAdBgNVHQ4EFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQD\n" \ + "AgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQGA1UdHwQ9\n" \ + "MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9BZGRUcnVzdEV4dGVy\n" \ + "bmFsQ0FSb290LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6\n" \ + "Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggEBAGS/g/FfmoXQ\n" \ + "zbihKVcN6Fr30ek+8nYEbvFScLsePP9NDXRqzIGCJdPDoCpdTPW6i6FtxFQJdcfj\n" \ + "Jw5dhHk3QBN39bSsHNA7qxcS1u80GH4r6XnTq1dFDK8o+tDb5VCViLvfhVdpfZLY\n" \ + "Uspzgb8c8+a4bmYRBbMelC1/kZWSWfFMzqORcUx8Rww7Cxn2obFshj5cqsQugsv5\n" \ + "B5a6SE2Q8pTIqXOi6wZ7I53eovNNVZ96YUWYGGjHXkBrI/V5eu+MtWuLt29G9Hvx\n" \ + "PUsE2JOAWVrgQSQdso8VYFhH2+9uRv0V9dlfmrPb2LjkQLPNlzmuhbsdjrzch5vR\n" \ + "pu/xO28QOG8=\n" \ + "-----END CERTIFICATE-----\n"; + +const char* local_root_ca2 = \ + "-----BEGIN CERTIFICATE-----\n" \ + "MIIGCDCCA/CgAwIBAgIQKy5u6tl1NmwUim7bo3yMBzANBgkqhkiG9w0BAQwFADCB\n" \ + "hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\n" \ + "A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV\n" \ + "BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwMjEy\n" \ + "MDAwMDAwWhcNMjkwMjExMjM1OTU5WjCBkDELMAkGA1UEBhMCR0IxGzAZBgNVBAgT\n" \ + "EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR\n" \ + "Q09NT0RPIENBIExpbWl0ZWQxNjA0BgNVBAMTLUNPTU9ETyBSU0EgRG9tYWluIFZh\n" \ + "bGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n" \ + "ADCCAQoCggEBAI7CAhnhoFmk6zg1jSz9AdDTScBkxwtiBUUWOqigwAwCfx3M28Sh\n" \ + "bXcDow+G+eMGnD4LgYqbSRutA776S9uMIO3Vzl5ljj4Nr0zCsLdFXlIvNN5IJGS0\n" \ + "Qa4Al/e+Z96e0HqnU4A7fK31llVvl0cKfIWLIpeNs4TgllfQcBhglo/uLQeTnaG6\n" \ + "ytHNe+nEKpooIZFNb5JPJaXyejXdJtxGpdCsWTWM/06RQ1A/WZMebFEh7lgUq/51\n" \ + "UHg+TLAchhP6a5i84DuUHoVS3AOTJBhuyydRReZw3iVDpA3hSqXttn7IzW3uLh0n\n" \ + "c13cRTCAquOyQQuvvUSH2rnlG51/ruWFgqUCAwEAAaOCAWUwggFhMB8GA1UdIwQY\n" \ + "MBaAFLuvfgI9+qbxPISOre44mOzZMjLUMB0GA1UdDgQWBBSQr2o6lFoL2JDqElZz\n" \ + "30O0Oija5zAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV\n" \ + "HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGwYDVR0gBBQwEjAGBgRVHSAAMAgG\n" \ + "BmeBDAECATBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9kb2NhLmNv\n" \ + "bS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcB\n" \ + "AQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9E\n" \ + "T1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21v\n" \ + "ZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAE4rdk+SHGI2ibp3wScF9BzWRJ2p\n" \ + "mj6q1WZmAT7qSeaiNbz69t2Vjpk1mA42GHWx3d1Qcnyu3HeIzg/3kCDKo2cuH1Z/\n" \ + "e+FE6kKVxF0NAVBGFfKBiVlsit2M8RKhjTpCipj4SzR7JzsItG8kO3KdY3RYPBps\n" \ + "P0/HEZrIqPW1N+8QRcZs2eBelSaz662jue5/DJpmNXMyYE7l3YphLG5SEXdoltMY\n" \ + "dVEVABt0iN3hxzgEQyjpFv3ZBdRdRydg1vs4O2xyopT4Qhrf7W8GjEXCBgCq5Ojc\n" \ + "2bXhc3js9iPc0d1sjhqPpepUfJa3w/5Vjo1JXvxku88+vZbrac2/4EjxYoIQ5QxG\n" \ + "V/Iz2tDIY+3GH5QFlkoakdH368+PUq4NCNk+qKBR6cGHdNXJ93SrLlP7u3r7l+L4\n" \ + "HyaPs9Kg4DdbKDsx5Q5XLVq4rXmsXiBmGqW5prU5wfWYQ//u+aen/e7KJD2AFsQX\n" \ + "j4rBYKEMrltDR5FL1ZoXX/nUh8HCjLfn4g8wGTeGrODcQgPmlKidrv0PJFGUzpII\n" \ + "0fxQ8ANAe4hZ7Q7drNJ3gjTcBpUC2JD5Leo31Rpg0Gcg19hCC0Wvgmje3WYkN5Ap\n" \ + "lBlGGSW4gNfL1IYoakRwJiNiqZ+Gb7+6kHDSVneFeO/qJakXzlByjAA6quPbYzSf\n" \ + "+AZxAeKCINT+b72x\n" \ + "-----END CERTIFICATE-----\n"; +*/ diff --git a/data/.exclude.files b/data/.exclude.files new file mode 100644 index 00000000..955397fa --- /dev/null +++ b/data/.exclude.files @@ -0,0 +1,2 @@ +/*.js.gz +/.exclude.files diff --git a/data/ace.js.gz b/data/ace.js.gz new file mode 100644 index 00000000..7b175c1c Binary files /dev/null and b/data/ace.js.gz differ diff --git a/data/config.all.json b/data/config.all.json new file mode 100644 index 00000000..b01644ad --- /dev/null +++ b/data/config.all.json @@ -0,0 +1,144 @@ +{ + "configs": [ + + "/config.live.json", + "/config.setup.json", + "/config.option.json" + ], + "class":"col-sm-offset-1 col-sm-10", + "content": [ + { + "type": "h5", + "title": "{{SSDP}}", + "class":"alert-warning" + }, +{ + "type": "h4", + "title": "Device ID: {{chipID}}" + }, +{ + "type": "h4", + "title": "IP address: {{ip}}" + }, + { + "type": "hr" + }, +{ + "type": "h2", + "title": "Конфигурация устройства" + }, + { + "type":"file", + "state":"config.all.txt", + "style":"width:100%;height:400px", + "title": "Сохранить", + "action": "/all_modules_init", + "class":"btn btn-block btn-success" + }, + { + "type": "link", + "title": "Инструкция", + "action": "https://github.com/DmitryBorisenko33/esp8266_iot-manager_modules_firmware/wiki/Instruction", + "class": "btn btn-block btn-primary" + }, +{ + "type": "h2", + "title": "Сценарии" + }, +{ +"type": "checkbox", +"name":"scenario", +"title": "Включить сценарии", +"action": "/scenario?status=[[scenario]]", +"state": "{{scenario}}" +}, +{ + "type": "h6", + "title": "" + }, +{ + "type":"file", + "state":"scenario.all.txt", + "style":"width:100%;height:400px", + "title": "Сохранить и включить", + "action": "/scenario?status=1", + "class":"btn btn-block btn-success" + }, +{ + "type": "h2", +"title": "Данные модулей" + }, +{ + "type": "hr" + }, +{ + "type": "h4", + "title": "Модуль уровня воды (level)", +"style": "width:100%" + }, + + { + "type": "h6", + "title": "Расстояние от датчика до воды: {{level_in}} см" + }, +{ + "type": "h6", + "title": " Заполнение бака: {{level}} %" + }, +{ + "type": "hr" + }, +{ + "type": "h4", + "title": "Модуль аналогового входа (analog)", +"style": "width:100%" + }, +{ + "type": "h6", + "title": "Прочитанное значение: {{analog_in}}" + }, +{ + "type": "h6", + "title": "Преобразованное значение: {{analog}}" + }, + { + "type": "hr" + }, +{ + "type": "h4", + "title": "Модуль температурного датчика (dallas)", +"style": "width:100%" + }, +{ + "type": "h6", + "title": "Текущее значение: {{dallas}} °C" + }, +{ + "type": "hr" + }, +{ + "type": "h4", + "title": "Модуль pH сенсора от df robot (ph)", +"style": "width:100%" + }, +{ + "type": "h6", + "title": "Текущее значение: {{ph}}" + }, +{ + "type": "hr" + }, + { + "type": "link", + "title": "Очистить все логи", + "action": "/cleanlog", + "class": "btn btn-block btn-success" + }, + { + "type": "link", + "title": "Главная", + "action": "/page.htm?index", + "class": "btn btn-block btn-danger btn-sm" + } + ] +} diff --git a/data/config.all.txt b/data/config.all.txt new file mode 100644 index 00000000..c66ef541 --- /dev/null +++ b/data/config.all.txt @@ -0,0 +1,19 @@ +button 1 na Включить#все Освещение 0 1 +button 2 13 Прихожая Освещение 0 2 +button 3 14 Кухня Освещение 0 3 +pwm 1 3 Яркость#коредор: Освещение 1023 4 +pwm 2 4 Яркость#ванная: Освещение 510 5 +analog Аналоговый#вход,#% Датчики text 1 1024 1 1024 6 +logging analog 1 144 график Датчики 7 +input value1 20.0 5 порог.#значение Датчики 8 +button 4 na Вкл#по#analog>20 Датчики 0 11 +//dallas 2 Водонагреватель,#t°C Датчики termometr 14 +//level Вода#в#баке,#% Датчики gauge 125 20 15 +//ph pH Датчики text 0 16 +input value2 8.0 1 период#сек Таймер 117 +button 5 na Вкл#обратный#таймер Таймер 0 20 +button 6 5 Включится#по#таймеру Таймер 0 21 +switch 1 0 20 +text 1 Квартира Двери 22 +button 7 scenario Сценарии Настройки 1 23 +button 8 line1,line2, 2строки#сценариев Освещение 1 24 \ No newline at end of file diff --git a/data/config.json b/data/config.json new file mode 100644 index 00000000..7e08ab5b --- /dev/null +++ b/data/config.json @@ -0,0 +1 @@ +{"SSDP":"MODULES","chipID":"12884479-1458415","ssidAP":"WiFi","passwordAP":"","ssid":"MGTS_GPON_DC15","password":"HKC4MRE4","timezone":3,"mqttServer":"91.204.228.124","mqttPort":1883,"mqttUser":"rise","mqttPass":"23ri22se32","scenario":"1","timers":"0","pushingbox_id":"v670C4F8A2581A11"} \ No newline at end of file diff --git a/data/css/build.css.gz b/data/css/build.css.gz new file mode 100644 index 00000000..4bf6e060 Binary files /dev/null and b/data/css/build.css.gz differ diff --git a/data/edit.htm b/data/edit.htm new file mode 100644 index 00000000..5e2f46ce --- /dev/null +++ b/data/edit.htm @@ -0,0 +1,572 @@ + + + + ESP Editor + + + + + + +
+
+
+ + + + diff --git a/data/edit.htm.gz b/data/edit.htm.gz new file mode 100644 index 00000000..f1e48f7e Binary files /dev/null and b/data/edit.htm.gz differ diff --git a/data/favicon.ico b/data/favicon.ico new file mode 100644 index 00000000..198474d2 Binary files /dev/null and b/data/favicon.ico differ diff --git a/data/index.htm b/data/index.htm new file mode 100644 index 00000000..f48e3673 --- /dev/null +++ b/data/index.htm @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + +
+ + +
+ + + + +
+ + diff --git a/data/index.htm.gz b/data/index.htm.gz new file mode 100644 index 00000000..139f0040 Binary files /dev/null and b/data/index.htm.gz differ diff --git a/data/index.json b/data/index.json new file mode 100644 index 00000000..567cc9c4 --- /dev/null +++ b/data/index.json @@ -0,0 +1,56 @@ +{ + "configs": [ + "/config.live.json", + "/config.setup.json" + ], + "title": "Главная", + "class": "col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", + "content": [ + { + "type": "h5", + "title": "{{SSDP}}", + "class": "alert-warning" + }, + { + "type": "h4", + "title": "Device ID: {{chipID}}" + }, + { + "type": "h4", + "title": "IP address: {{ip}}" + }, + { + "type": "link", + "title": "Конфигурация устройства", + "action": "/page.htm?config.all", + "class": "btn btn-block btn-primary" + }, + { + "type": "hr" + }, + { + "type": "link", + "title": "Конфигурация WIFI", + "action": "/page.htm?setup", + "class": "btn btn-block btn-success" + }, + { + "type": "link", + "title": "Конфигурация MQTT", + "action": "/page.htm?mqtt", + "class": "btn btn-block btn-success" + }, + { + "type": "link", + "title": "Конфигурация push", + "action": "/page.htm?pushingbox", + "class": "btn btn-block btn-success" + }, + { + "type": "link", + "title": "Скачать приложение IoT Manager", + "action": "https://github.com/DmitryBorisenko33/esp8266_iot-manager_modules_firmware/raw/master/iot_manager/IoT%20Manager%201.5.5.apk", + "class": "btn btn-block btn-success" + } + ] +} diff --git a/data/js/build.chart.js.gz b/data/js/build.chart.js.gz new file mode 100644 index 00000000..ac021668 Binary files /dev/null and b/data/js/build.chart.js.gz differ diff --git a/data/js/function.js.gz b/data/js/function.js.gz new file mode 100644 index 00000000..d9e2a2cd Binary files /dev/null and b/data/js/function.js.gz differ diff --git a/data/lang/lang.en.json.gz b/data/lang/lang.en.json.gz new file mode 100644 index 00000000..47332483 Binary files /dev/null and b/data/lang/lang.en.json.gz differ diff --git a/data/lang/lang.lv.json.gz b/data/lang/lang.lv.json.gz new file mode 100644 index 00000000..99d2b8e7 Binary files /dev/null and b/data/lang/lang.lv.json.gz differ diff --git a/data/lang/lang.ru.json.gz b/data/lang/lang.ru.json.gz new file mode 100644 index 00000000..2ce395ac Binary files /dev/null and b/data/lang/lang.ru.json.gz differ diff --git a/data/lang/lang.ua.json.gz b/data/lang/lang.ua.json.gz new file mode 100644 index 00000000..8f038344 Binary files /dev/null and b/data/lang/lang.ua.json.gz differ diff --git a/data/mode-html.js.gz b/data/mode-html.js.gz new file mode 100644 index 00000000..26b53532 Binary files /dev/null and b/data/mode-html.js.gz differ diff --git a/data/mqtt.json b/data/mqtt.json new file mode 100644 index 00000000..cf7d98da --- /dev/null +++ b/data/mqtt.json @@ -0,0 +1,73 @@ +{ + "configs": [ +"/config.setup.json" + ], + "class":"col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", + "content": [ + { + "type": "h5", + "title": "{{SSDP}}", + "class":"alert-warning" + }, + { + "type": "h4", + "title": "Server name:" + }, +{ + "type": "input", + "title": "", + "name":"1", + "state": "{{mqttServer}}" + }, +{ + "type": "h4", + "title": "Port:" + }, +{ + "type": "input", + "title": "", + "name":"2", + "state": "{{mqttPort}}" + }, +{ + "type": "h4", + "title": "User name:" + }, +{ + "type": "input", + "title": "", + "name":"3", + "state": "{{mqttUser}}" + }, +{ + "type": "h4", + "title": "Password:" + }, +{ + "type": "input", + "title": "", + "name":"4", + "state": "{{mqttPass}}" + }, +{ + "type":"h3", + "name":"my-block", +"style":"position:fixed;top:30%;left:50%;width:400px;margin-left:-200px;text-align:center;", + "class":"hidden" + }, +{ + "type": "button", + "title":"Сохранить и проверить соединение", + "action": "mqttSave?mqttServer=[[1]]&mqttPort=[[2]]&mqttUser=[[3]]&mqttPass=[[4]]", + "response":"[[my-block]]", + "class": "btn btn-block btn-success", + "style": "width:100%;display:inline" + }, + { + "type": "link", + "title": "Главная", + "action": "/page.htm?index", + "class": "btn btn-block btn-danger btn-sm" + } + ] +} diff --git a/data/page.htm.gz b/data/page.htm.gz new file mode 100644 index 00000000..2213e165 Binary files /dev/null and b/data/page.htm.gz differ diff --git a/data/push.json b/data/push.json new file mode 100644 index 00000000..5ae4af98 --- /dev/null +++ b/data/push.json @@ -0,0 +1,92 @@ +{ + "configs": [ +"/config.setup.json" + ], + "class":"col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", + "content": [ + { + "type": "h5", + "title": "{{SSDP}}", + "class":"alert-warning" + }, + { + "type": "h4", + "title": "Host name:" + }, +{ + "type": "input", + "title": "", + "name":"1", + "state": "{{pushHost}}" + }, +{ + "type": "h4", + "title": "Port:" + }, +{ + "type": "input", + "title": "", + "name":"2", + "state": "{{pushPort}}" + }, +{ + "type": "h4", + "title": "Fingerprint:" + }, +{ + "type": "input", + "title": "", + "name":"3", + "state": "{{pushFingerprint}}" + }, +{ + "type": "h4", + "title": "Access Token:" + }, +{ + "type": "input", + "title": "", + "name":"4", + "state": "{{pushAccessToken}}" + }, +{ + "type":"h3", + "name":"my-block", +"style":"position:fixed;top:30%;left:50%;width:400px;margin-left:-200px;text-align:center;", + "class":"hidden" + }, +{ + "type": "button", + "title":"Сохранить и проверить соединение", + "action": "pushDate?pushHost=[[1]]&pushPort=[[2]]&pushFingerprint=[[3]]&pushAccessToken=[[4]]", + "response":"[[my-block]]", + "class": "btn btn-block btn-success", + "style": "width:100%;display:inline" + }, +{ + "type": "hr" + }, +{ +"type": "checkbox", +"name":"start-push", +"title": "Отправлять push при включении устройства", +"action": "startPush?status=[[start-push]]", +"state": "{{startPush}}" +}, +{ + "type": "hr" + }, + { + "type": "link", + "title": "Перезагрузить устройство", + "action": "javascript:if(confirm(renameBlock(jsonResponse,'Перезагрузить?'))){send_request(this,'/restart?device=ok');}", + "class": "btn btn-block btn-warning" + }, + { + "type": "link", + "title": "Главная", + "action": "/page.htm?index", + "class": "btn btn-block btn-danger btn-sm" + } + ] +} diff --git a/data/pushingbox.json b/data/pushingbox.json new file mode 100644 index 00000000..0679489a --- /dev/null +++ b/data/pushingbox.json @@ -0,0 +1,46 @@ +{ + "configs": [ +"/config.setup.json" + ], + "class":"col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", + "content": [ + { + "type": "h5", + "title": "{{SSDP}}", + "class":"alert-warning" + }, + { + "type": "h4", + "title": "Device id:" + }, +{ + "type": "input", + "title": "", + "name":"1", + "state": "{{pushingbox_id}}" + }, + +{ + "type": "button", + "title":"Сохранить", + "action": "pushingboxDate?pushingbox_id=[[1]]", + "class": "btn btn-block btn-success", + "style": "width:100%;display:inline" + }, +{ + "type": "hr" + }, + { + "type": "link", + "title": "Перезагрузить устройство", + "action": "javascript:if(confirm(renameBlock(jsonResponse,'Перезагрузить?'))){send_request(this,'/restart?device=ok');}", + "class": "btn btn-block btn-warning" + }, + { + "type": "link", + "title": "Главная", + "action": "/page.htm?index", + "class": "btn btn-block btn-danger btn-sm" + } + ] +} diff --git a/data/scenario.all.txt b/data/scenario.all.txt new file mode 100644 index 00000000..54a790b1 --- /dev/null +++ b/data/scenario.all.txt @@ -0,0 +1,31 @@ +button1 = 1 +buttonSet 2 1 +buttonSet 3 1 +pwmSet 2 1024 +end +button1 = 0 +buttonSet 2 0 +buttonSet 3 0 +pwmSet 2 0 +end +analog > value1 +buttonSet 4 1 +end +button5 = 1 +timerStart 1 value2 sec +end +button5 = 0 +timerStart 2 value2 sec +end +timer1 = 0 +buttonSet 6 1 +end +timer2 = 0 +buttonSet 6 0 +end +switch1 = 1 +textSet 1 закрыто-time +end +switch1 = 0 +textSet 1 открыто-time +end \ No newline at end of file diff --git a/data/setup.json b/data/setup.json new file mode 100644 index 00000000..c6bb2fd4 --- /dev/null +++ b/data/setup.json @@ -0,0 +1,154 @@ +{ + "configs": [ + "/config.setup.json" + ], + "title": "Конфигурация", + "class":"col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", + "content": [ + { + "type": "h5", + "title": "{{SSDP}}", + "class":"alert-warning" + }, + { + "type": "link", + "title": "Главная", + "action": "/", + "class": "btn btn-block btn-danger" + }, + { + "type": "hr" + }, + { + "type": "h2", + "title": "Имя устройства" + }, + { + "type": "input", + "title": "Имя устройства", + "name":"ssdp", + "state": "{{SSDP}}", + "pattern": "[0-9a-zA-Zа-яА-Я.\\- ]{1,20}" + }, + { + "type": "button", + "title": "Сохранить", + "action": "ssdp?ssdp=[[ssdp]]", + "class": "btn btn-block btn-success" + }, + { + "type": "hr" + }, + { + "type": "h2", + "title": "Подключение к Wi-Fi роутеру" + }, + { + "type": "input", + "title":"Сеть", + "name":"ssid", + "state": "{{ssid}}" + }, + { + "type": "password", + "title": "Введите пароль", + "name":"ssidPass", + "state": "{{password}}", + "pattern": ".{8,20}" + }, + { + "type": "button", + "title": "Сохранить", + "class": "btn btn-block btn-success", + "action": "ssid?ssid=[[ssid]]&password=[[ssidPass]]" + }, + { + "type": "hr" + }, + { + "type": "h2", + "title": "Временная зона GMT" + }, + { + "type": "input", + "title": "{{LangSpace}}", + "name":"timeZone", + "state": "{{timezone}}", + "pattern": "[0-9-]{1,3}" + }, + { + "type": "button", + "module":"", + "title": "Сохранить", + "class": "btn btn-block btn-success", + "action": "timeZone?timeZone=[[timeZone]]" + }, + { + "type": "link", + "title": "Автоопределение зоны", + "action": "javascript:set_time_zone(this);", + "class": "btn btn-block btn-primary" + }, + { + "type": "time", + "name":"times1", + "title": "На устройстве сейчас", + "state":"{{time}}" + }, + { + "type": "button", + "response":"[[times1]]", + "title": "Синхронизировать", + "class": "btn btn-block btn-primary", + "action": "Time" + }, + { + "type": "hr" + }, + { + "type": "h2", + "title": "Точка доступа" + }, + { + "type": "text", + "title": "После того как устройство подключается к роутеру, его Wi-Fi исчезнет.", + "class": "alert alert-warning", + "style": "width:45%;float:right;" + }, + { + "type": "input", + "title": "Имя WI-FI сети", + "name":"ssidap", + "state": "{{ssidAP}}", + "style": "width:50%;display:inline", + "pattern": ".{1,20}" + }, + { + "type": "password", + "title": "Пароль", + "name":"ssidApPass", + "state": "{{passwordAP}}", + "style": "width:50%;display:inline", + "pattern": ".{8,20}" + }, + { + "type": "button", + "title": "Сохранить", + "action": "ssidap?ssidAP=[[ssidap]]&passwordAP=[[ssidApPass]]", + "class": "btn btn-block btn-success", + "style": "width:50%;display:inline" + }, + { + "type": "hr" + }, +{ + "type": "hr" + }, + { + "type": "link", + "title": "Перезагрузить устройство", + "action": "javascript:if(confirm(renameBlock(jsonResponse,'Перезагрузить?'))){send_request(this,'/restart?device=ok');}", + "class": "btn btn-block btn-warning" + } + ] +} diff --git a/data/soket.json b/data/soket.json new file mode 100644 index 00000000..92b61373 --- /dev/null +++ b/data/soket.json @@ -0,0 +1,57 @@ +{ + "configs": [ + + "/config.live.json", + "/config.option.json", + "/config.setup.json", + "/lang/lang.ru.json", + "socket {{ip}}:81/" + + ], + "title": "Главная", + "class":"col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", + "content": [ + { + "type": "h5", + "title": "{{SSDP}}", + "class":"alert-warning" + }, +{ + "type": "h4", + "title": "Module tank level:", + "style": "width:80%;float:left;" + }, +{ + "type": "h4", + "title": "{{module_tank_level_s}}", + "style": "width:20%;float:right;" + }, +{ + "type": "h4", + "title": "Module analog:", + "style": "width:80%;float:left;" + }, +{ + "type": "h4", + "title": "{{module_analog_s}}", + "style": "width:20%;float:right;" + }, +{ + "type": "h4", + "title": "Module ds18b20:", + "style": "width:80%;float:left;" + }, +{ + "type": "h4", + "title": "{{module_ds18b20_s}}", + "style": "width:20%;float:right;" + }, +{ + "type": "link", + "title": "Главная", + "action": "/page.htm?index", + "class": "btn btn-block btn-danger btn-sm", +"style": "width:100%;float:right;" + } + ] +} diff --git a/data/vigets/viget.alertbg.json b/data/vigets/viget.alertbg.json new file mode 100644 index 00000000..13cd1cc7 --- /dev/null +++ b/data/vigets/viget.alertbg.json @@ -0,0 +1,12 @@ +{ + "id" : "", + "page" : "", + "widget" : "anydata", + "class1": "col-xs-4 text-center", + "class2": "stable", + "style2": "font-size:12px;float:center;", + "class3":"stable", + "style3": "font-size:25px;float:center;font-weight:bold;", + "descr" : "", + "topic" : "" + } diff --git a/data/vigets/viget.alertsm.json b/data/vigets/viget.alertsm.json new file mode 100644 index 00000000..4ad91aa1 --- /dev/null +++ b/data/vigets/viget.alertsm.json @@ -0,0 +1,12 @@ +{ + "id" : "", + "page" : "", + "widget" : "anydata", + "class1" : "item col-xs-12 text-center", + "class2": "ballanced", + "style2": "font-size:20px;float:left;font-weight:bold;", + "class3":"ballanced", + "style3": "font-size:17px;float:right;", + "descr" : "", + "topic" : "" + } diff --git a/data/vigets/viget.button.json b/data/vigets/viget.button.json new file mode 100644 index 00000000..d94276c1 --- /dev/null +++ b/data/vigets/viget.button.json @@ -0,0 +1,18 @@ + { + "id": "", + "pageId":"", + "page": "", + "widget": "simple-btn", + "class1": "col-xs-4 text-center", + "class2": "ballanced", + "style2": "font-size:15px;float:left;font-weight:bold;", + "topic": "", + "class3": "button button-block", + "style3": "float:right;", + "widgetConfig": { + "fill": "#F5F5F5", + "fillPressed": "#4169E1", + "title": "-", + "delay":500 + } + } \ No newline at end of file diff --git a/data/vigets/viget.chart.json b/data/vigets/viget.chart.json new file mode 100644 index 00000000..bb0ae087 --- /dev/null +++ b/data/vigets/viget.chart.json @@ -0,0 +1,13 @@ +{ + "id" : "", + "pageId": "", + "widget" : "chart", + "topic" : "", + "widgetConfig": { + + "maxCount": 200, + "type": "line", + "height": 200 + + } +} \ No newline at end of file diff --git a/data/vigets/viget.fillgauge.json b/data/vigets/viget.fillgauge.json new file mode 100644 index 00000000..c434d0e1 --- /dev/null +++ b/data/vigets/viget.fillgauge.json @@ -0,0 +1,23 @@ + { + "id": "", + "page": "", + "pageId": "", + "widget": "fillgauge", + "descr": "", + "class2": "text-center ballanced", + "style2": "font-size:25px;font-weight:bold;padding-top:10px;padding-bottom:10px;", + "class3" : "text-center", + "style3": "padding-top:10px;padding-bottom:10px;", + "topic": "", + "width": "250px", + "height": "250px", + "widgetConfig": { + "circleColor": "#228B22", + "textColor": "#FFFFFF", + "waveTextColor": "#050000", + "waveColor": "#40E0D0", + "circleThickness": 0.05, + "textVertPosition": 0.5, + "waveAnimateTime": 500 + } + } \ No newline at end of file diff --git a/data/vigets/viget.gauge.json b/data/vigets/viget.gauge.json new file mode 100644 index 00000000..6c6c14e2 --- /dev/null +++ b/data/vigets/viget.gauge.json @@ -0,0 +1,18 @@ +{ + "id" : "", + "pageId": "", + "widget" : "gauge", + "topic" : "", + "class1" : "item no-border no-padding text-center", + "descr" : "", + "widgetConfig" : { + "type" : "full", + "cap" : "round", + "append" : "", + "size" : 300, + "thick" : 20, + "maximum": 1024, + "color" : "#11c1f3", + "backgroundColor": "rgba(0,0,0, 0.2)" + } +} \ No newline at end of file diff --git a/data/vigets/viget.led.json b/data/vigets/viget.led.json new file mode 100644 index 00000000..6b392086 --- /dev/null +++ b/data/vigets/viget.led.json @@ -0,0 +1,16 @@ + { + "id": "", + "pageId": "", + "descr": "", + "class1": "col-xs-3 text-center", + "page": "", + "widget": "steel", + "topic": "", + "widgetConfig": { + "width": 60, + "height": 60, + "type": "Led", + "blink": false, + "LedColor": "RED_LED" + } + } diff --git a/data/vigets/viget.range.json b/data/vigets/viget.range.json new file mode 100644 index 00000000..cf8a12a6 --- /dev/null +++ b/data/vigets/viget.range.json @@ -0,0 +1,13 @@ + { + "id": "", + "page": "", + "descr": "", + "widget": "range", + "class3": "ballanced", + "style3": "font-size:25px;float:left;font-weight:bold;", + "topic": "", + "widgetConfig": { + "maxValue": 1023, + "minValue": 0 + } + } diff --git a/data/vigets/viget.status.json b/data/vigets/viget.status.json new file mode 100644 index 00000000..618a05d2 --- /dev/null +++ b/data/vigets/viget.status.json @@ -0,0 +1,13 @@ +{ + "id" : "1", + "page" : "", + "pageId":"", + "widget" : "anydata", + "class1" : "item rounded text-center no-padding", + "class2": "ballanced", + "style2": "", + "class3":"ballanced", + "style3": "font-size:10px;float:right;", + "descr" : "", + "topic" : "" + } \ No newline at end of file diff --git a/data/vigets/viget.termometr.json b/data/vigets/viget.termometr.json new file mode 100644 index 00000000..0fed8f9d --- /dev/null +++ b/data/vigets/viget.termometr.json @@ -0,0 +1,15 @@ + { + "id": "", + "page": "", + "pageId": "", + "widget": "steel", + "topic": "/DS", + "widgetConfig": { + "width": "auto", + "height": 150, + "type": "Linear", + "titleString": "Спальня", + "unitString": "°C", + "threshold": 30 + } + } \ No newline at end of file diff --git a/data/vigets/viget.toggle.json b/data/vigets/viget.toggle.json new file mode 100644 index 00000000..cc554fb3 --- /dev/null +++ b/data/vigets/viget.toggle.json @@ -0,0 +1,11 @@ + { + "id": "", + "page": "", + "pageId": "", + "widget": "toggle", + "descrStyle": "font-size:20px;float:left;font-weight:bold;", + "descrStyleOff": "font-size:20px;float:left;", + "color": "#8997ff", + "descr": "", + "topic": "" + } \ No newline at end of file diff --git a/data/worker-html.js.gz b/data/worker-html.js.gz new file mode 100644 index 00000000..ec8aa87a Binary files /dev/null and b/data/worker-html.js.gz differ diff --git a/data_new/ace.js.gz b/data_new/ace.js.gz new file mode 100644 index 00000000..7b175c1c Binary files /dev/null and b/data_new/ace.js.gz differ diff --git a/data_new/chart.json.gz b/data_new/chart.json.gz new file mode 100644 index 00000000..c0df7c39 Binary files /dev/null and b/data_new/chart.json.gz differ diff --git a/data_new/config.all.json b/data_new/config.all.json new file mode 100644 index 00000000..b01644ad --- /dev/null +++ b/data_new/config.all.json @@ -0,0 +1,144 @@ +{ + "configs": [ + + "/config.live.json", + "/config.setup.json", + "/config.option.json" + ], + "class":"col-sm-offset-1 col-sm-10", + "content": [ + { + "type": "h5", + "title": "{{SSDP}}", + "class":"alert-warning" + }, +{ + "type": "h4", + "title": "Device ID: {{chipID}}" + }, +{ + "type": "h4", + "title": "IP address: {{ip}}" + }, + { + "type": "hr" + }, +{ + "type": "h2", + "title": "Конфигурация устройства" + }, + { + "type":"file", + "state":"config.all.txt", + "style":"width:100%;height:400px", + "title": "Сохранить", + "action": "/all_modules_init", + "class":"btn btn-block btn-success" + }, + { + "type": "link", + "title": "Инструкция", + "action": "https://github.com/DmitryBorisenko33/esp8266_iot-manager_modules_firmware/wiki/Instruction", + "class": "btn btn-block btn-primary" + }, +{ + "type": "h2", + "title": "Сценарии" + }, +{ +"type": "checkbox", +"name":"scenario", +"title": "Включить сценарии", +"action": "/scenario?status=[[scenario]]", +"state": "{{scenario}}" +}, +{ + "type": "h6", + "title": "" + }, +{ + "type":"file", + "state":"scenario.all.txt", + "style":"width:100%;height:400px", + "title": "Сохранить и включить", + "action": "/scenario?status=1", + "class":"btn btn-block btn-success" + }, +{ + "type": "h2", +"title": "Данные модулей" + }, +{ + "type": "hr" + }, +{ + "type": "h4", + "title": "Модуль уровня воды (level)", +"style": "width:100%" + }, + + { + "type": "h6", + "title": "Расстояние от датчика до воды: {{level_in}} см" + }, +{ + "type": "h6", + "title": " Заполнение бака: {{level}} %" + }, +{ + "type": "hr" + }, +{ + "type": "h4", + "title": "Модуль аналогового входа (analog)", +"style": "width:100%" + }, +{ + "type": "h6", + "title": "Прочитанное значение: {{analog_in}}" + }, +{ + "type": "h6", + "title": "Преобразованное значение: {{analog}}" + }, + { + "type": "hr" + }, +{ + "type": "h4", + "title": "Модуль температурного датчика (dallas)", +"style": "width:100%" + }, +{ + "type": "h6", + "title": "Текущее значение: {{dallas}} °C" + }, +{ + "type": "hr" + }, +{ + "type": "h4", + "title": "Модуль pH сенсора от df robot (ph)", +"style": "width:100%" + }, +{ + "type": "h6", + "title": "Текущее значение: {{ph}}" + }, +{ + "type": "hr" + }, + { + "type": "link", + "title": "Очистить все логи", + "action": "/cleanlog", + "class": "btn btn-block btn-success" + }, + { + "type": "link", + "title": "Главная", + "action": "/page.htm?index", + "class": "btn btn-block btn-danger btn-sm" + } + ] +} diff --git a/data_new/config.all.txt b/data_new/config.all.txt new file mode 100644 index 00000000..c66ef541 --- /dev/null +++ b/data_new/config.all.txt @@ -0,0 +1,19 @@ +button 1 na Включить#все Освещение 0 1 +button 2 13 Прихожая Освещение 0 2 +button 3 14 Кухня Освещение 0 3 +pwm 1 3 Яркость#коредор: Освещение 1023 4 +pwm 2 4 Яркость#ванная: Освещение 510 5 +analog Аналоговый#вход,#% Датчики text 1 1024 1 1024 6 +logging analog 1 144 график Датчики 7 +input value1 20.0 5 порог.#значение Датчики 8 +button 4 na Вкл#по#analog>20 Датчики 0 11 +//dallas 2 Водонагреватель,#t°C Датчики termometr 14 +//level Вода#в#баке,#% Датчики gauge 125 20 15 +//ph pH Датчики text 0 16 +input value2 8.0 1 период#сек Таймер 117 +button 5 na Вкл#обратный#таймер Таймер 0 20 +button 6 5 Включится#по#таймеру Таймер 0 21 +switch 1 0 20 +text 1 Квартира Двери 22 +button 7 scenario Сценарии Настройки 1 23 +button 8 line1,line2, 2строки#сценариев Освещение 1 24 \ No newline at end of file diff --git a/data_new/config.json b/data_new/config.json new file mode 100644 index 00000000..dfa5acfd --- /dev/null +++ b/data_new/config.json @@ -0,0 +1 @@ +{"SSDP":"MODULES","chipID":"12884479-1458415","ssidAP":"WiFi","passwordAP":"","ssid":"MGTS_GPON_1002","password":"TTNYJ4QJ","timezone":3,"mqttServer":"91.204.228.124","mqttPort":1883,"mqttUser":"rise","mqttPass":"23ri22se32","scenario":"1","timers":"0","pushingbox_id":"v670C4F8A2581A11"} \ No newline at end of file diff --git a/data_new/configclient.json b/data_new/configclient.json new file mode 100644 index 00000000..f9082e7c --- /dev/null +++ b/data_new/configclient.json @@ -0,0 +1 @@ +{"SSDP":"MODULES","ssidAP":"WiFi","passwordAP":"","ssid":"MGTS_GPON_10B0","password":"8ed76da8","timezone":3,"mqttServer":"","mqttPort":0,"mqttUser":"","mqttPass":"","chipID":"9139530-1458400","scenario":"1","timers":"1","pushHost":"api.pushbullet.com","pushPort":443,"pushAccessToken":"","module_push":"0","pushFingerprint":"fef1573c6feeef932eaed0228e91878e048e73a2"} diff --git a/data_new/configevery.json b/data_new/configevery.json new file mode 100644 index 00000000..8079a30f --- /dev/null +++ b/data_new/configevery.json @@ -0,0 +1 @@ +{"SSDP":"MODULES","ssidAP":"WiFi","passwordAP":"","ssid":"your_ssid","password":"your_password","timezone":3,"mqttServer":"","mqttPort":0,"mqttUser":"","mqttPass":"","chipID":"9139530-1458400","scenario":"1","timers":"1","pushHost":"api.pushbullet.com","pushPort":443,"pushAccessToken":"","module_push":"0","pushFingerprint":"fef1573c6feeef932eaed0228e91878e048e73a2"} diff --git a/data_new/css/build.css.gz b/data_new/css/build.css.gz new file mode 100644 index 00000000..469e6d32 Binary files /dev/null and b/data_new/css/build.css.gz differ diff --git a/data_new/donate.htm.gz b/data_new/donate.htm.gz new file mode 100644 index 00000000..d6af4a9e Binary files /dev/null and b/data_new/donate.htm.gz differ diff --git a/data_new/edit.htm.gz b/data_new/edit.htm.gz new file mode 100644 index 00000000..00861394 Binary files /dev/null and b/data_new/edit.htm.gz differ diff --git a/data_new/ext-searchbox.js.gz b/data_new/ext-searchbox.js.gz new file mode 100644 index 00000000..cf5b49f6 Binary files /dev/null and b/data_new/ext-searchbox.js.gz differ diff --git a/data_new/favicon.ico b/data_new/favicon.ico new file mode 100644 index 00000000..198474d2 Binary files /dev/null and b/data_new/favicon.ico differ diff --git a/data_new/img/swatches.png b/data_new/img/swatches.png new file mode 100644 index 00000000..b0648e11 Binary files /dev/null and b/data_new/img/swatches.png differ diff --git a/data_new/img/swatches1.png b/data_new/img/swatches1.png new file mode 100644 index 00000000..fedee0af Binary files /dev/null and b/data_new/img/swatches1.png differ diff --git a/data_new/index.htm b/data_new/index.htm new file mode 100644 index 00000000..e7d22ef5 --- /dev/null +++ b/data_new/index.htm @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + +
+
+ + +
+ + + + +
+ + diff --git a/data_new/index.htm.gz b/data_new/index.htm.gz new file mode 100644 index 00000000..a1caf8cf Binary files /dev/null and b/data_new/index.htm.gz differ diff --git a/data_new/index.json b/data_new/index.json new file mode 100644 index 00000000..567cc9c4 --- /dev/null +++ b/data_new/index.json @@ -0,0 +1,56 @@ +{ + "configs": [ + "/config.live.json", + "/config.setup.json" + ], + "title": "Главная", + "class": "col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", + "content": [ + { + "type": "h5", + "title": "{{SSDP}}", + "class": "alert-warning" + }, + { + "type": "h4", + "title": "Device ID: {{chipID}}" + }, + { + "type": "h4", + "title": "IP address: {{ip}}" + }, + { + "type": "link", + "title": "Конфигурация устройства", + "action": "/page.htm?config.all", + "class": "btn btn-block btn-primary" + }, + { + "type": "hr" + }, + { + "type": "link", + "title": "Конфигурация WIFI", + "action": "/page.htm?setup", + "class": "btn btn-block btn-success" + }, + { + "type": "link", + "title": "Конфигурация MQTT", + "action": "/page.htm?mqtt", + "class": "btn btn-block btn-success" + }, + { + "type": "link", + "title": "Конфигурация push", + "action": "/page.htm?pushingbox", + "class": "btn btn-block btn-success" + }, + { + "type": "link", + "title": "Скачать приложение IoT Manager", + "action": "https://github.com/DmitryBorisenko33/esp8266_iot-manager_modules_firmware/raw/master/iot_manager/IoT%20Manager%201.5.5.apk", + "class": "btn btn-block btn-success" + } + ] +} diff --git a/data_new/js/build.chart.js.gz b/data_new/js/build.chart.js.gz new file mode 100644 index 00000000..fface5cd Binary files /dev/null and b/data_new/js/build.chart.js.gz differ diff --git a/data_new/js/function.js.gz b/data_new/js/function.js.gz new file mode 100644 index 00000000..7079411b Binary files /dev/null and b/data_new/js/function.js.gz differ diff --git a/data_new/lang/lang.en.json.gz b/data_new/lang/lang.en.json.gz new file mode 100644 index 00000000..36a64bf8 Binary files /dev/null and b/data_new/lang/lang.en.json.gz differ diff --git a/data_new/lang/lang.lv.json.gz b/data_new/lang/lang.lv.json.gz new file mode 100644 index 00000000..75a2a524 Binary files /dev/null and b/data_new/lang/lang.lv.json.gz differ diff --git a/data_new/lang/lang.ru.json.gz b/data_new/lang/lang.ru.json.gz new file mode 100644 index 00000000..2ce395ac Binary files /dev/null and b/data_new/lang/lang.ru.json.gz differ diff --git a/data_new/lang/lang.ua.json.gz b/data_new/lang/lang.ua.json.gz new file mode 100644 index 00000000..8a7e31dc Binary files /dev/null and b/data_new/lang/lang.ua.json.gz differ diff --git a/data_new/mode-css.js.gz b/data_new/mode-css.js.gz new file mode 100644 index 00000000..ebd6fe94 Binary files /dev/null and b/data_new/mode-css.js.gz differ diff --git a/data_new/mode-html.js.gz b/data_new/mode-html.js.gz new file mode 100644 index 00000000..26b53532 Binary files /dev/null and b/data_new/mode-html.js.gz differ diff --git a/data_new/mode-javascript.js.gz b/data_new/mode-javascript.js.gz new file mode 100644 index 00000000..c0451c1c Binary files /dev/null and b/data_new/mode-javascript.js.gz differ diff --git a/data_new/mqtt.json b/data_new/mqtt.json new file mode 100644 index 00000000..cf7d98da --- /dev/null +++ b/data_new/mqtt.json @@ -0,0 +1,73 @@ +{ + "configs": [ +"/config.setup.json" + ], + "class":"col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", + "content": [ + { + "type": "h5", + "title": "{{SSDP}}", + "class":"alert-warning" + }, + { + "type": "h4", + "title": "Server name:" + }, +{ + "type": "input", + "title": "", + "name":"1", + "state": "{{mqttServer}}" + }, +{ + "type": "h4", + "title": "Port:" + }, +{ + "type": "input", + "title": "", + "name":"2", + "state": "{{mqttPort}}" + }, +{ + "type": "h4", + "title": "User name:" + }, +{ + "type": "input", + "title": "", + "name":"3", + "state": "{{mqttUser}}" + }, +{ + "type": "h4", + "title": "Password:" + }, +{ + "type": "input", + "title": "", + "name":"4", + "state": "{{mqttPass}}" + }, +{ + "type":"h3", + "name":"my-block", +"style":"position:fixed;top:30%;left:50%;width:400px;margin-left:-200px;text-align:center;", + "class":"hidden" + }, +{ + "type": "button", + "title":"Сохранить и проверить соединение", + "action": "mqttSave?mqttServer=[[1]]&mqttPort=[[2]]&mqttUser=[[3]]&mqttPass=[[4]]", + "response":"[[my-block]]", + "class": "btn btn-block btn-success", + "style": "width:100%;display:inline" + }, + { + "type": "link", + "title": "Главная", + "action": "/page.htm?index", + "class": "btn btn-block btn-danger btn-sm" + } + ] +} diff --git a/data_new/page.htm.gz b/data_new/page.htm.gz new file mode 100644 index 00000000..b9bb8db1 Binary files /dev/null and b/data_new/page.htm.gz differ diff --git a/data_new/push.json b/data_new/push.json new file mode 100644 index 00000000..5ae4af98 --- /dev/null +++ b/data_new/push.json @@ -0,0 +1,92 @@ +{ + "configs": [ +"/config.setup.json" + ], + "class":"col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", + "content": [ + { + "type": "h5", + "title": "{{SSDP}}", + "class":"alert-warning" + }, + { + "type": "h4", + "title": "Host name:" + }, +{ + "type": "input", + "title": "", + "name":"1", + "state": "{{pushHost}}" + }, +{ + "type": "h4", + "title": "Port:" + }, +{ + "type": "input", + "title": "", + "name":"2", + "state": "{{pushPort}}" + }, +{ + "type": "h4", + "title": "Fingerprint:" + }, +{ + "type": "input", + "title": "", + "name":"3", + "state": "{{pushFingerprint}}" + }, +{ + "type": "h4", + "title": "Access Token:" + }, +{ + "type": "input", + "title": "", + "name":"4", + "state": "{{pushAccessToken}}" + }, +{ + "type":"h3", + "name":"my-block", +"style":"position:fixed;top:30%;left:50%;width:400px;margin-left:-200px;text-align:center;", + "class":"hidden" + }, +{ + "type": "button", + "title":"Сохранить и проверить соединение", + "action": "pushDate?pushHost=[[1]]&pushPort=[[2]]&pushFingerprint=[[3]]&pushAccessToken=[[4]]", + "response":"[[my-block]]", + "class": "btn btn-block btn-success", + "style": "width:100%;display:inline" + }, +{ + "type": "hr" + }, +{ +"type": "checkbox", +"name":"start-push", +"title": "Отправлять push при включении устройства", +"action": "startPush?status=[[start-push]]", +"state": "{{startPush}}" +}, +{ + "type": "hr" + }, + { + "type": "link", + "title": "Перезагрузить устройство", + "action": "javascript:if(confirm(renameBlock(jsonResponse,'Перезагрузить?'))){send_request(this,'/restart?device=ok');}", + "class": "btn btn-block btn-warning" + }, + { + "type": "link", + "title": "Главная", + "action": "/page.htm?index", + "class": "btn btn-block btn-danger btn-sm" + } + ] +} diff --git a/data_new/pushingbox.json b/data_new/pushingbox.json new file mode 100644 index 00000000..0679489a --- /dev/null +++ b/data_new/pushingbox.json @@ -0,0 +1,46 @@ +{ + "configs": [ +"/config.setup.json" + ], + "class":"col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", + "content": [ + { + "type": "h5", + "title": "{{SSDP}}", + "class":"alert-warning" + }, + { + "type": "h4", + "title": "Device id:" + }, +{ + "type": "input", + "title": "", + "name":"1", + "state": "{{pushingbox_id}}" + }, + +{ + "type": "button", + "title":"Сохранить", + "action": "pushingboxDate?pushingbox_id=[[1]]", + "class": "btn btn-block btn-success", + "style": "width:100%;display:inline" + }, +{ + "type": "hr" + }, + { + "type": "link", + "title": "Перезагрузить устройство", + "action": "javascript:if(confirm(renameBlock(jsonResponse,'Перезагрузить?'))){send_request(this,'/restart?device=ok');}", + "class": "btn btn-block btn-warning" + }, + { + "type": "link", + "title": "Главная", + "action": "/page.htm?index", + "class": "btn btn-block btn-danger btn-sm" + } + ] +} diff --git a/data_new/scenario.all.txt b/data_new/scenario.all.txt new file mode 100644 index 00000000..54a790b1 --- /dev/null +++ b/data_new/scenario.all.txt @@ -0,0 +1,31 @@ +button1 = 1 +buttonSet 2 1 +buttonSet 3 1 +pwmSet 2 1024 +end +button1 = 0 +buttonSet 2 0 +buttonSet 3 0 +pwmSet 2 0 +end +analog > value1 +buttonSet 4 1 +end +button5 = 1 +timerStart 1 value2 sec +end +button5 = 0 +timerStart 2 value2 sec +end +timer1 = 0 +buttonSet 6 1 +end +timer2 = 0 +buttonSet 6 0 +end +switch1 = 1 +textSet 1 закрыто-time +end +switch1 = 0 +textSet 1 открыто-time +end \ No newline at end of file diff --git a/data_new/setup.json b/data_new/setup.json new file mode 100644 index 00000000..c6bb2fd4 --- /dev/null +++ b/data_new/setup.json @@ -0,0 +1,154 @@ +{ + "configs": [ + "/config.setup.json" + ], + "title": "Конфигурация", + "class":"col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", + "content": [ + { + "type": "h5", + "title": "{{SSDP}}", + "class":"alert-warning" + }, + { + "type": "link", + "title": "Главная", + "action": "/", + "class": "btn btn-block btn-danger" + }, + { + "type": "hr" + }, + { + "type": "h2", + "title": "Имя устройства" + }, + { + "type": "input", + "title": "Имя устройства", + "name":"ssdp", + "state": "{{SSDP}}", + "pattern": "[0-9a-zA-Zа-яА-Я.\\- ]{1,20}" + }, + { + "type": "button", + "title": "Сохранить", + "action": "ssdp?ssdp=[[ssdp]]", + "class": "btn btn-block btn-success" + }, + { + "type": "hr" + }, + { + "type": "h2", + "title": "Подключение к Wi-Fi роутеру" + }, + { + "type": "input", + "title":"Сеть", + "name":"ssid", + "state": "{{ssid}}" + }, + { + "type": "password", + "title": "Введите пароль", + "name":"ssidPass", + "state": "{{password}}", + "pattern": ".{8,20}" + }, + { + "type": "button", + "title": "Сохранить", + "class": "btn btn-block btn-success", + "action": "ssid?ssid=[[ssid]]&password=[[ssidPass]]" + }, + { + "type": "hr" + }, + { + "type": "h2", + "title": "Временная зона GMT" + }, + { + "type": "input", + "title": "{{LangSpace}}", + "name":"timeZone", + "state": "{{timezone}}", + "pattern": "[0-9-]{1,3}" + }, + { + "type": "button", + "module":"", + "title": "Сохранить", + "class": "btn btn-block btn-success", + "action": "timeZone?timeZone=[[timeZone]]" + }, + { + "type": "link", + "title": "Автоопределение зоны", + "action": "javascript:set_time_zone(this);", + "class": "btn btn-block btn-primary" + }, + { + "type": "time", + "name":"times1", + "title": "На устройстве сейчас", + "state":"{{time}}" + }, + { + "type": "button", + "response":"[[times1]]", + "title": "Синхронизировать", + "class": "btn btn-block btn-primary", + "action": "Time" + }, + { + "type": "hr" + }, + { + "type": "h2", + "title": "Точка доступа" + }, + { + "type": "text", + "title": "После того как устройство подключается к роутеру, его Wi-Fi исчезнет.", + "class": "alert alert-warning", + "style": "width:45%;float:right;" + }, + { + "type": "input", + "title": "Имя WI-FI сети", + "name":"ssidap", + "state": "{{ssidAP}}", + "style": "width:50%;display:inline", + "pattern": ".{1,20}" + }, + { + "type": "password", + "title": "Пароль", + "name":"ssidApPass", + "state": "{{passwordAP}}", + "style": "width:50%;display:inline", + "pattern": ".{8,20}" + }, + { + "type": "button", + "title": "Сохранить", + "action": "ssidap?ssidAP=[[ssidap]]&passwordAP=[[ssidApPass]]", + "class": "btn btn-block btn-success", + "style": "width:50%;display:inline" + }, + { + "type": "hr" + }, +{ + "type": "hr" + }, + { + "type": "link", + "title": "Перезагрузить устройство", + "action": "javascript:if(confirm(renameBlock(jsonResponse,'Перезагрузить?'))){send_request(this,'/restart?device=ok');}", + "class": "btn btn-block btn-warning" + } + ] +} diff --git a/data_new/soket.json b/data_new/soket.json new file mode 100644 index 00000000..92b61373 --- /dev/null +++ b/data_new/soket.json @@ -0,0 +1,57 @@ +{ + "configs": [ + + "/config.live.json", + "/config.option.json", + "/config.setup.json", + "/lang/lang.ru.json", + "socket {{ip}}:81/" + + ], + "title": "Главная", + "class":"col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", + "content": [ + { + "type": "h5", + "title": "{{SSDP}}", + "class":"alert-warning" + }, +{ + "type": "h4", + "title": "Module tank level:", + "style": "width:80%;float:left;" + }, +{ + "type": "h4", + "title": "{{module_tank_level_s}}", + "style": "width:20%;float:right;" + }, +{ + "type": "h4", + "title": "Module analog:", + "style": "width:80%;float:left;" + }, +{ + "type": "h4", + "title": "{{module_analog_s}}", + "style": "width:20%;float:right;" + }, +{ + "type": "h4", + "title": "Module ds18b20:", + "style": "width:80%;float:left;" + }, +{ + "type": "h4", + "title": "{{module_ds18b20_s}}", + "style": "width:20%;float:right;" + }, +{ + "type": "link", + "title": "Главная", + "action": "/page.htm?index", + "class": "btn btn-block btn-danger btn-sm", +"style": "width:100%;float:right;" + } + ] +} diff --git a/data_new/viget.alertbg.json b/data_new/viget.alertbg.json new file mode 100644 index 00000000..13cd1cc7 --- /dev/null +++ b/data_new/viget.alertbg.json @@ -0,0 +1,12 @@ +{ + "id" : "", + "page" : "", + "widget" : "anydata", + "class1": "col-xs-4 text-center", + "class2": "stable", + "style2": "font-size:12px;float:center;", + "class3":"stable", + "style3": "font-size:25px;float:center;font-weight:bold;", + "descr" : "", + "topic" : "" + } diff --git a/data_new/viget.alertsm.json b/data_new/viget.alertsm.json new file mode 100644 index 00000000..4ad91aa1 --- /dev/null +++ b/data_new/viget.alertsm.json @@ -0,0 +1,12 @@ +{ + "id" : "", + "page" : "", + "widget" : "anydata", + "class1" : "item col-xs-12 text-center", + "class2": "ballanced", + "style2": "font-size:20px;float:left;font-weight:bold;", + "class3":"ballanced", + "style3": "font-size:17px;float:right;", + "descr" : "", + "topic" : "" + } diff --git a/data_new/viget.button.json b/data_new/viget.button.json new file mode 100644 index 00000000..d94276c1 --- /dev/null +++ b/data_new/viget.button.json @@ -0,0 +1,18 @@ + { + "id": "", + "pageId":"", + "page": "", + "widget": "simple-btn", + "class1": "col-xs-4 text-center", + "class2": "ballanced", + "style2": "font-size:15px;float:left;font-weight:bold;", + "topic": "", + "class3": "button button-block", + "style3": "float:right;", + "widgetConfig": { + "fill": "#F5F5F5", + "fillPressed": "#4169E1", + "title": "-", + "delay":500 + } + } \ No newline at end of file diff --git a/data_new/viget.chart.json b/data_new/viget.chart.json new file mode 100644 index 00000000..bb0ae087 --- /dev/null +++ b/data_new/viget.chart.json @@ -0,0 +1,13 @@ +{ + "id" : "", + "pageId": "", + "widget" : "chart", + "topic" : "", + "widgetConfig": { + + "maxCount": 200, + "type": "line", + "height": 200 + + } +} \ No newline at end of file diff --git a/data_new/viget.fillgauge.json b/data_new/viget.fillgauge.json new file mode 100644 index 00000000..c434d0e1 --- /dev/null +++ b/data_new/viget.fillgauge.json @@ -0,0 +1,23 @@ + { + "id": "", + "page": "", + "pageId": "", + "widget": "fillgauge", + "descr": "", + "class2": "text-center ballanced", + "style2": "font-size:25px;font-weight:bold;padding-top:10px;padding-bottom:10px;", + "class3" : "text-center", + "style3": "padding-top:10px;padding-bottom:10px;", + "topic": "", + "width": "250px", + "height": "250px", + "widgetConfig": { + "circleColor": "#228B22", + "textColor": "#FFFFFF", + "waveTextColor": "#050000", + "waveColor": "#40E0D0", + "circleThickness": 0.05, + "textVertPosition": 0.5, + "waveAnimateTime": 500 + } + } \ No newline at end of file diff --git a/data_new/viget.gauge.json b/data_new/viget.gauge.json new file mode 100644 index 00000000..6c6c14e2 --- /dev/null +++ b/data_new/viget.gauge.json @@ -0,0 +1,18 @@ +{ + "id" : "", + "pageId": "", + "widget" : "gauge", + "topic" : "", + "class1" : "item no-border no-padding text-center", + "descr" : "", + "widgetConfig" : { + "type" : "full", + "cap" : "round", + "append" : "", + "size" : 300, + "thick" : 20, + "maximum": 1024, + "color" : "#11c1f3", + "backgroundColor": "rgba(0,0,0, 0.2)" + } +} \ No newline at end of file diff --git a/data_new/viget.led.json b/data_new/viget.led.json new file mode 100644 index 00000000..6b392086 --- /dev/null +++ b/data_new/viget.led.json @@ -0,0 +1,16 @@ + { + "id": "", + "pageId": "", + "descr": "", + "class1": "col-xs-3 text-center", + "page": "", + "widget": "steel", + "topic": "", + "widgetConfig": { + "width": 60, + "height": 60, + "type": "Led", + "blink": false, + "LedColor": "RED_LED" + } + } diff --git a/data_new/viget.range.json b/data_new/viget.range.json new file mode 100644 index 00000000..cf8a12a6 --- /dev/null +++ b/data_new/viget.range.json @@ -0,0 +1,13 @@ + { + "id": "", + "page": "", + "descr": "", + "widget": "range", + "class3": "ballanced", + "style3": "font-size:25px;float:left;font-weight:bold;", + "topic": "", + "widgetConfig": { + "maxValue": 1023, + "minValue": 0 + } + } diff --git a/data_new/viget.status.json b/data_new/viget.status.json new file mode 100644 index 00000000..618a05d2 --- /dev/null +++ b/data_new/viget.status.json @@ -0,0 +1,13 @@ +{ + "id" : "1", + "page" : "", + "pageId":"", + "widget" : "anydata", + "class1" : "item rounded text-center no-padding", + "class2": "ballanced", + "style2": "", + "class3":"ballanced", + "style3": "font-size:10px;float:right;", + "descr" : "", + "topic" : "" + } \ No newline at end of file diff --git a/data_new/viget.termometr.json b/data_new/viget.termometr.json new file mode 100644 index 00000000..0fed8f9d --- /dev/null +++ b/data_new/viget.termometr.json @@ -0,0 +1,15 @@ + { + "id": "", + "page": "", + "pageId": "", + "widget": "steel", + "topic": "/DS", + "widgetConfig": { + "width": "auto", + "height": 150, + "type": "Linear", + "titleString": "Спальня", + "unitString": "°C", + "threshold": 30 + } + } \ No newline at end of file diff --git a/data_new/viget.toggle.json b/data_new/viget.toggle.json new file mode 100644 index 00000000..cc554fb3 --- /dev/null +++ b/data_new/viget.toggle.json @@ -0,0 +1,11 @@ + { + "id": "", + "page": "", + "pageId": "", + "widget": "toggle", + "descrStyle": "font-size:20px;float:left;font-weight:bold;", + "descrStyleOff": "font-size:20px;float:left;", + "color": "#8997ff", + "descr": "", + "topic": "" + } \ No newline at end of file diff --git a/data_new/worker-html.js.gz b/data_new/worker-html.js.gz new file mode 100644 index 00000000..ec8aa87a Binary files /dev/null and b/data_new/worker-html.js.gz differ diff --git a/dependencies/WiFiClientSecure/WiFiClientSecure.cpp b/dependencies/WiFiClientSecure/WiFiClientSecure.cpp new file mode 100644 index 00000000..3b2c495b --- /dev/null +++ b/dependencies/WiFiClientSecure/WiFiClientSecure.cpp @@ -0,0 +1,197 @@ +/* + WiFiClientSecure.cpp - Client Secure class for ESP32 + Copyright (c) 2016 Hristo Gochkov All right reserved. + Additions Copyright (C) 2017 Evandro Luis Copercini. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "WiFiClientSecure.h" +#include +#include +#include + +#undef connect +#undef write +#undef read + + +WiFiClientSecure::WiFiClientSecure() +{ + _connected = false; + + sslclient = new sslclient_context; + ssl_init(sslclient); + sslclient->socket = -1; + + _CA_cert = NULL; + _cert = NULL; + _private_key = NULL; + next = NULL; +} + + +WiFiClientSecure::WiFiClientSecure(int sock) +{ + _connected = false; + + sslclient = new sslclient_context; + ssl_init(sslclient); + sslclient->socket = sock; + + if (sock >= 0) { + _connected = true; + } + + _CA_cert = NULL; + _cert = NULL; + _private_key = NULL; + next = NULL; +} + +WiFiClientSecure::~WiFiClientSecure() +{ + stop(); +} + +WiFiClientSecure &WiFiClientSecure::operator=(const WiFiClientSecure &other) +{ + stop(); + sslclient->socket = other.sslclient->socket; + _connected = other._connected; + return *this; +} + +void WiFiClientSecure::stop() +{ + if (sslclient->socket >= 0) { + close(sslclient->socket); + sslclient->socket = -1; + _connected = false; + } + stop_ssl_socket(sslclient, _CA_cert, _cert, _private_key); +} + +int WiFiClientSecure::connect(IPAddress ip, uint16_t port) +{ + return connect(ip, port, _CA_cert, _cert, _private_key); +} + +int WiFiClientSecure::connect(const char *host, uint16_t port) +{ + return connect(host, port, _CA_cert, _cert, _private_key); +} + +int WiFiClientSecure::connect(IPAddress ip, uint16_t port, const char *_CA_cert, const char *_cert, const char *_private_key) +{ + int ret = start_ssl_client(sslclient, ip, port, _CA_cert, _cert, _private_key); + if (ret < 0) { + log_e("lwip_connect_r: %d", errno); + stop(); + return 0; + } + _connected = true; + return 1; +} + +int WiFiClientSecure::connect(const char *host, uint16_t port, const char *_CA_cert, const char *_cert, const char *_private_key) +{ + struct hostent *server; + server = gethostbyname(host); + if (server == NULL) { + return 0; + } + IPAddress srv((const uint8_t *)(server->h_addr)); + return connect(srv, port, _CA_cert, _cert, _private_key); +} + + +size_t WiFiClientSecure::write(uint8_t data) +{ + return write(&data, 1); +} + +int WiFiClientSecure::read() +{ + uint8_t data = 0; + int res = read(&data, 1); + if (res < 0) { + return res; + } + return data; +} + +size_t WiFiClientSecure::write(const uint8_t *buf, size_t size) +{ + if (!_connected) { + return 0; + } + int res = send_ssl_data(sslclient, buf, size); + if (res < 0) { + + stop(); + res = 0; + } + return res; +} + +int WiFiClientSecure::read(uint8_t *buf, size_t size) +{ + if (!available()) { + return -1; + } + int res = get_ssl_receive(sslclient, buf, size); + if (res < 0) { + + stop(); + } + return res; +} + +int WiFiClientSecure::available() +{ + if (!_connected) { + return 0; + } + int res = data_to_read(sslclient); + if (res < 0 ) { + stop(); + } + return res; +} + +uint8_t WiFiClientSecure::connected() +{ + uint8_t dummy = 0; + read(&dummy, 0); + + return _connected; +} + +void WiFiClientSecure::setCACert (const char *rootCA) +{ + _CA_cert = rootCA; +} + +void WiFiClientSecure::setCertificate (const char *client_ca) +{ + _cert = client_ca; +} + +void WiFiClientSecure::setPrivateKey (const char *private_key) +{ + _private_key = private_key; +} + diff --git a/dependencies/WiFiClientSecure/WiFiClientSecure.h b/dependencies/WiFiClientSecure/WiFiClientSecure.h new file mode 100644 index 00000000..5ffc3ae0 --- /dev/null +++ b/dependencies/WiFiClientSecure/WiFiClientSecure.h @@ -0,0 +1,92 @@ +/* + WiFiClientSecure.h - Base class that provides Client SSL to ESP32 + Copyright (c) 2011 Adrian McEwen. All right reserved. + Additions Copyright (C) 2017 Evandro Luis Copercini. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WiFiClientSecure_h +#define WiFiClientSecure_h +#include "Arduino.h" +#include "IPAddress.h" +#include +#include "ssl_client.h" + +class WiFiClientSecure : public Client +{ +protected: + bool _connected; + sslclient_context *sslclient; + + const char *_CA_cert; + const char *_cert; + const char *_private_key; + +public: + WiFiClientSecure *next; + WiFiClientSecure(); + WiFiClientSecure(int socket); + ~WiFiClientSecure(); + int connect(IPAddress ip, uint16_t port); + int connect(const char *host, uint16_t port); + int connect(IPAddress ip, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key); + int connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key); + size_t write(uint8_t data); + size_t write(const uint8_t *buf, size_t size); + int available(); + int read(); + int read(uint8_t *buf, size_t size); + int peek() + { + return 0; + } + void flush() {} + void stop(); + uint8_t connected(); + + void setCACert(const char *rootCA); + void setCertificate(const char *client_ca); + void setPrivateKey (const char *private_key); + + operator bool() + { + return connected(); + } + WiFiClientSecure &operator=(const WiFiClientSecure &other); + bool operator==(const bool value) + { + return bool() == value; + } + bool operator!=(const bool value) + { + return bool() != value; + } + bool operator==(const WiFiClientSecure &); + bool operator!=(const WiFiClientSecure &rhs) + { + return !this->operator==(rhs); + }; + + int socket() + { + return sslclient->socket = -1; + } + + //friend class WiFiServer; + using Print::write; +}; + +#endif /* _WIFICLIENT_H_ */ diff --git a/dependencies/WiFiClientSecure/ssl_client.cpp b/dependencies/WiFiClientSecure/ssl_client.cpp new file mode 100644 index 00000000..15c2cb81 --- /dev/null +++ b/dependencies/WiFiClientSecure/ssl_client.cpp @@ -0,0 +1,261 @@ +/* Provide SSL/TLS functions to ESP32 with Arduino IDE +* +* Adapted from the ssl_client1 example of mbedtls. +* +* Original Copyright (C) 2006-2015, ARM Limited, All Rights Reserved, Apache 2.0 License. +* Additions Copyright (C) 2017 Evandro Luis Copercini, Apache 2.0 License. +*/ + +#include "Arduino.h" +#include +#include +#include +#include +#include +#include +#include "ssl_client.h" + +const char *pers = "esp32-tls"; + +static int handle_error(int err) +{ +#ifdef MBEDTLS_ERROR_C + char error_buf[100]; + mbedtls_strerror(err, error_buf, 100); + log_e("%s", error_buf); +#endif + log_e("MbedTLS message code: %d", err); + return err; +} + + +void ssl_init(sslclient_context *ssl_client) +{ + mbedtls_ssl_init(&ssl_client->ssl_ctx); + mbedtls_ssl_config_init(&ssl_client->ssl_conf); + mbedtls_ctr_drbg_init(&ssl_client->drbg_ctx); +} + + +int start_ssl_client(sslclient_context *ssl_client, uint32_t ipAddress, uint32_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key) +{ + char buf[512]; + int ret, flags, timeout; + int enable = 1; + log_i("Free heap before TLS %u", xPortGetFreeHeapSize()); + + log_i("Starting socket"); + ssl_client->socket = -1; + + ssl_client->socket = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (ssl_client->socket < 0) { + log_e("ERROR opening socket"); + return ssl_client->socket; + } + + struct sockaddr_in serv_addr; + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = ipAddress; + serv_addr.sin_port = htons(port); + + if (lwip_connect(ssl_client->socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0) { + timeout = 30000; + lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); + lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable)); + lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)); + } else { + log_e("Connect to Server failed!"); + return -1; + } + + fcntl( ssl_client->socket, F_SETFL, fcntl( ssl_client->socket, F_GETFL, 0 ) | O_NONBLOCK ); + + log_i("Seeding the random number generator"); + mbedtls_entropy_init(&ssl_client->entropy_ctx); + + ret = mbedtls_ctr_drbg_seed(&ssl_client->drbg_ctx, mbedtls_entropy_func, + &ssl_client->entropy_ctx, (const unsigned char *) pers, strlen(pers)); + if (ret < 0) { + return handle_error(ret); + } + + log_i("Setting up the SSL/TLS structure..."); + + if ((ret = mbedtls_ssl_config_defaults(&ssl_client->ssl_conf, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { + return handle_error(ret); + } + + /* MBEDTLS_SSL_VERIFY_REQUIRED if a CA certificate is defined on Arduino IDE and + MBEDTLS_SSL_VERIFY_NONE if not. + */ + if (rootCABuff != NULL) { + log_i("Loading CA cert"); + mbedtls_x509_crt_init(&ssl_client->ca_cert); + mbedtls_ssl_conf_authmode(&ssl_client->ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED); + ret = mbedtls_x509_crt_parse(&ssl_client->ca_cert, (const unsigned char *)rootCABuff, strlen(rootCABuff) + 1); + mbedtls_ssl_conf_ca_chain(&ssl_client->ssl_conf, &ssl_client->ca_cert, NULL); + //mbedtls_ssl_conf_verify(&ssl_client->ssl_ctx, my_verify, NULL ); + if (ret < 0) { + return handle_error(ret); + } + } else { + mbedtls_ssl_conf_authmode(&ssl_client->ssl_conf, MBEDTLS_SSL_VERIFY_NONE); + log_i("WARNING: Use certificates for a more secure communication!"); + } + + if (cli_cert != NULL && cli_key != NULL) { + mbedtls_x509_crt_init(&ssl_client->client_cert); + mbedtls_pk_init(&ssl_client->client_key); + + log_i("Loading CRT cert"); + + ret = mbedtls_x509_crt_parse(&ssl_client->client_cert, (const unsigned char *)cli_cert, strlen(cli_cert) + 1); + if (ret < 0) { + return handle_error(ret); + } + + log_i("Loading private key"); + ret = mbedtls_pk_parse_key(&ssl_client->client_key, (const unsigned char *)cli_key, strlen(cli_key) + 1, NULL, 0); + + if (ret != 0) { + return handle_error(ret); + } + + mbedtls_ssl_conf_own_cert(&ssl_client->ssl_conf, &ssl_client->client_cert, &ssl_client->client_key); + } + + /* + // TODO: implement match CN verification + + log_i("Setting hostname for TLS session..."); + + // Hostname set here should match CN in server certificate + if((ret = mbedtls_ssl_set_hostname(&ssl_client->ssl_ctx, host)) != 0) + { + return handle_error(ret); + + } + */ + + mbedtls_ssl_conf_rng(&ssl_client->ssl_conf, mbedtls_ctr_drbg_random, &ssl_client->drbg_ctx); + + if ((ret = mbedtls_ssl_setup(&ssl_client->ssl_ctx, &ssl_client->ssl_conf)) != 0) { + return handle_error(ret); + } + + mbedtls_ssl_set_bio(&ssl_client->ssl_ctx, &ssl_client->socket, mbedtls_net_send, mbedtls_net_recv, NULL ); + + log_i("Performing the SSL/TLS handshake..."); + + while ((ret = mbedtls_ssl_handshake(&ssl_client->ssl_ctx)) != 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret != -76) { //workaround for bug: https://github.com/espressif/esp-idf/issues/434 + return handle_error(ret); + } + delay(10); + vPortYield(); + } + + + if (cli_cert != NULL && cli_key != NULL) { + log_i("Protocol is %s Ciphersuite is %s", mbedtls_ssl_get_version(&ssl_client->ssl_ctx), mbedtls_ssl_get_ciphersuite(&ssl_client->ssl_ctx)); + if ((ret = mbedtls_ssl_get_record_expansion(&ssl_client->ssl_ctx)) >= 0) { + log_i("Record expansion is %d", ret); + } else { + log_i("Record expansion is unknown (compression)"); + } + } + + log_i("Verifying peer X.509 certificate..."); + + if ((flags = mbedtls_ssl_get_verify_result(&ssl_client->ssl_ctx)) != 0) { + log_e("Failed to verify peer certificate!"); + bzero(buf, sizeof(buf)); + mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags); + log_e("verification info: %s", buf); + stop_ssl_socket(ssl_client, rootCABuff, cli_cert, cli_key); //It's not safe continue. + return handle_error(ret); + } else { + log_i("Certificate verified."); + } + + log_i("Free heap after TLS %u", xPortGetFreeHeapSize()); + + return ssl_client->socket; +} + + +void stop_ssl_socket(sslclient_context *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key) +{ + log_i("Cleaning SSL connection."); + + if (ssl_client->socket >= 0) { + close(ssl_client->socket); + ssl_client->socket = -1; + } + + mbedtls_ssl_free(&ssl_client->ssl_ctx); + mbedtls_ssl_config_free(&ssl_client->ssl_conf); + mbedtls_ctr_drbg_free(&ssl_client->drbg_ctx); + mbedtls_entropy_free(&ssl_client->entropy_ctx); + + if (rootCABuff != NULL) { + mbedtls_x509_crt_free(&ssl_client->ca_cert); + } + + if (cli_cert != NULL) { + mbedtls_x509_crt_free(&ssl_client->client_cert); + } + + if (cli_key != NULL) { + mbedtls_pk_free(&ssl_client->client_key); + } +} + + +int data_to_read(sslclient_context *ssl_client) +{ + int ret, res; + ret = mbedtls_ssl_read(&ssl_client->ssl_ctx, NULL, 0); + //log_e("RET: %i",ret); //for low level debug + res = mbedtls_ssl_get_bytes_avail(&ssl_client->ssl_ctx); + //log_e("RES: %i",res); + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret < 0 && ret != -76) { + return handle_error(ret); + } + + return res; +} + + +int send_ssl_data(sslclient_context *ssl_client, const uint8_t *data, uint16_t len) +{ + //log_i("Writing HTTP request..."); //for low level debug + int ret = -1; + + while ((ret = mbedtls_ssl_write(&ssl_client->ssl_ctx, data, len)) <= 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret != -76) { + return handle_error(ret); + } + } + + len = ret; + //log_i("%d bytes written", len); //for low level debug + return ret; +} + + +int get_ssl_receive(sslclient_context *ssl_client, uint8_t *data, int length) +{ + //log_i( "Reading HTTP response..."); //for low level debug + int ret = -1; + + ret = mbedtls_ssl_read(&ssl_client->ssl_ctx, data, length); + + //log_i( "%d bytes readed", ret); //for low level debug + return ret; +} diff --git a/dependencies/WiFiClientSecure/ssl_client.h b/dependencies/WiFiClientSecure/ssl_client.h new file mode 100644 index 00000000..5fc98ad7 --- /dev/null +++ b/dependencies/WiFiClientSecure/ssl_client.h @@ -0,0 +1,37 @@ +/* Provide SSL/TLS functions to ESP32 with Arduino IDE + * by Evandro Copercini - 2017 - Apache 2.0 License + */ + +#ifndef ARD_SSL_H +#define ARD_SSL_H +#include "mbedtls/platform.h" +#include "mbedtls/net.h" +#include "mbedtls/debug.h" +#include "mbedtls/ssl.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/error.h" + +typedef struct sslclient_context { + int socket; + mbedtls_net_context net_ctx; + mbedtls_ssl_context ssl_ctx; + mbedtls_ssl_config ssl_conf; + + mbedtls_ctr_drbg_context drbg_ctx; + mbedtls_entropy_context entropy_ctx; + + mbedtls_x509_crt ca_cert; + mbedtls_x509_crt client_cert; + mbedtls_pk_context client_key; +} sslclient_context; + + +void ssl_init(sslclient_context *ssl_client); +int start_ssl_client(sslclient_context *ssl_client, uint32_t ipAddress, uint32_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key); +void stop_ssl_socket(sslclient_context *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key); +int data_to_read(sslclient_context *ssl_client); +int send_ssl_data(sslclient_context *ssl_client, const uint8_t *data, uint16_t len); +int get_ssl_receive(sslclient_context *ssl_client, uint8_t *data, int length); + +#endif diff --git a/esp32_iot-manager_modules_firmware.ino b/esp32_iot-manager_modules_firmware.ino new file mode 100644 index 00000000..74ee69bb --- /dev/null +++ b/esp32_iot-manager_modules_firmware.ino @@ -0,0 +1,78 @@ +#include "set.h" + +void setup() { + + Serial.begin(115200); + Serial.setDebugOutput(true); + Serial.println("--------------started----------------"); + + //-------------------------------------------------------------- + SPIFFS.begin(); + configSetup = readFile("config.json", 4096); + Serial.println(configSetup); + jsonWrite(configJson, "SSDP", jsonRead(configSetup, "SSDP")); + jsonWrite(configJson, "lang", jsonRead(configSetup, "lang")); + Serial.println("SPIFFS_init"); + +#ifdef ESP32 + uint32_t chipID_u = ESP.getEfuseMac(); + chipID = String(chipID_u); + jsonWrite(configSetup, "chipID", chipID); +#endif + +#ifdef ESP8266 + chipID = String( ESP.getChipId() ) + "-" + String( ESP.getFlashChipId()); + jsonWrite(configSetup, "chipID", chipID); +#endif + + prex = prefix + "/" + chipID; + Serial.println(chipID); + //-------------------------------------------------------------- + CMD_init(); + Serial.println("[V] CMD_init"); + //-------------------------------------------------------------- + All_init(); + Serial.println("[V] All_init"); + //-------------------------------------------------------------- + WIFI_init(); + Serial.println("[V] WIFI_init"); + //-------------------------------------------------------------- + Web_server_init(); + Serial.println("[V] Web_server_init"); + //-------------------------------------------------------------- + Time_Init(); + Serial.println("[V] Time_Init"); + //-------------------------------------------------------------- + MQTT_init(); + Serial.println("[V] MQTT_init"); + //-------------------------------------------------------------- + + getMemoryLoad("[i] After loading"); + + + ts.add(TEST, 1000, [&](void*) { + + //getMemoryLoad("[i] Periodic check"); + + }, nullptr, true); + +} + +void loop() { + +#ifdef OTA_enable + ArduinoOTA.handle(); +#endif + +#ifdef WS_enable + ws.cleanupClients(); +#endif + + handleMQTT(); + + handleCMD_loop(); + handleButton(); + handleScenario(); + + ts.update(); +} diff --git a/main.ino b/main.ino new file mode 100644 index 00000000..53147f35 --- /dev/null +++ b/main.ino @@ -0,0 +1,279 @@ +//=============================================JSON=========================================================== +// ------------- Чтение значения json +String jsonRead(String &json, String name) { + DynamicJsonBuffer jsonBuffer; + JsonObject& root = jsonBuffer.parseObject(json); + return root[name].as(); +} + +// ------------- Чтение значения json +int jsonReadtoInt(String &json, String name) { + DynamicJsonBuffer jsonBuffer; + JsonObject& root = jsonBuffer.parseObject(json); + return root[name]; +} + +// ------------- Запись значения json String +String jsonWrite(String &json, String name, String volume) { + DynamicJsonBuffer jsonBuffer; + JsonObject& root = jsonBuffer.parseObject(json); + root[name] = volume; + json = ""; + root.printTo(json); + return json; +} + +// ------------- Запись значения json int +String jsonWrite(String &json, String name, int volume) { + DynamicJsonBuffer jsonBuffer; + JsonObject& root = jsonBuffer.parseObject(json); + root[name] = volume; + json = ""; + root.printTo(json); + return json; +} + +// ------------- Запись значения json float +String jsonWrite(String &json, String name, float volume) { + DynamicJsonBuffer jsonBuffer; + JsonObject& root = jsonBuffer.parseObject(json); + root[name] = volume; + json = ""; + root.printTo(json); + return json; +} +//=============================================CONFIG=========================================================== +void saveConfig () { + writeFile("config.json", configSetup); +} +//=============================================ТЕКСТ============================================================ +// --------Выделяем строку от конца строки до маркера----------------------------------------------------------- +String selectToMarkerLast (String str, String found) { + int p = str.lastIndexOf(found); + return str.substring(p + found.length()); +} + +// --------Выделяем строку до маркера--------------------------------------------------------------------------- +String selectToMarker (String str, String found) { + int p = str.indexOf(found); + return str.substring(0, p); +} +// --------Удаляем все после символа разделителя (вместе с символом разделителя)-------------------------------- +String deleteAfterDelimiter (String str, String found) { + int p = str.indexOf(found); + return str.substring(0, p); +} + +//---------Удаляем все до символа разделителя (вместе с символом разделителя)----------------------------------- +String deleteBeforeDelimiter(String str, String found) { + int p = str.indexOf(found) + found.length(); + return str.substring(p); +} +//----------------------Удаляем все до символа разделителя (без символа разделителя)---------------------------- +String deleteBeforeDelimiterTo(String str, String found) { + int p = str.indexOf(found); + return str.substring(p); +} + +// -------------------Выделяем строку от конца строки до маркера ------------------------------------------------ +String deleteToMarkerLast (String str, String found) { + int p = str.lastIndexOf(found); + return str.substring(0, p); +} +String selectToMarkerPlus (String str, String found, int plus) { + int p = str.indexOf(found); + return str.substring(0, p + plus); +} +//--------------------Выделяем строку от маркера до маркера +String selectFromMarkerToMarker(String str, String found, int number) { + if (str.indexOf(found) == -1) return "not found"; // если строки поиск нет сразу выход + str += found; // добавим для корректного поиска + uint8_t i = 0; // Индекс перебора + do { + if (i == number) return selectToMarker(str, found); // если индекс совпал с позицией законцим вернем резултат + str = deleteBeforeDelimiter(str, found); // отбросим проверенный блок до разделителя + i++; // увеличим индекс + } while (str.length() != 0); // повторим пока строка не пустая + return "not found"; // Достигли пустой строки и ничего не нашли +} +//--------------------Посчитать +int count(String str, String found) { + if (str.indexOf(found) == -1) return 0; // если строки поиск нет сразу выход + str += found; // добавим для корректного поиска + uint8_t i = 0; // Индекс перебора + while (str.length() != 0) { + str = deleteBeforeDelimiter(str, found); // отбросим проверенный блок до разделителя + i++; // увеличим индекс + } + return i; // Достигли пустой строки и ничего не нашли +} + +boolean isDigitStr (String str) { + if (str.length() == 1) { + return Digit (str); + } + if (str.length() > 1) { + for (int i = 0; i < str.length(); i++) { + if (!Digit (String(str.charAt(i)))) return false; + } + return true; + } +} + +boolean Digit (String str) { + if (str == "0" || str == "1" || str == "2" || str == "3" || str == "4" || str == "5" || str == "6" || str == "7" || str == "8" || str == "9") { + return true; + } else { + return false; + } +} +//============================================URL=================================================================== +// ----------------------Запрос на удаленный URL +String getURL(String urls) { + String answer = ""; + HTTPClient http; + http.begin(urls); //HTTP + int httpCode = http.GET(); + if (httpCode == HTTP_CODE_OK) { + answer = http.getString(); + } + else + { + answer = "error"; + } + http.end(); + return answer; +} + +//===========================================FILES=================================================================== + +String safeDataToFile(String data, String Folder) +{ + //String fileName = GetDate(); + String fileName; + fileName.toLowerCase(); + fileName = deleteBeforeDelimiter(fileName, " "); + fileName.replace(" ", "."); + fileName.replace("..", "."); + fileName = Folder + "/" + fileName + ".txt"; + + // addFile(fileName, GetTime() + "/" + data); + + Serial.println(fileName); + jsonWrite(configJson, "test", fileName); +} +// ------------- Чтение файла в строку +String readFile(String fileName, size_t len ) { + File configFile = SPIFFS.open("/" + fileName, "r"); + if (!configFile) { + return "Failed"; + } + size_t size = configFile.size(); + if (size > len) { + configFile.close(); + return "Large"; + } + String temp = configFile.readString(); + configFile.close(); + return temp; +} + +String sizeFile(String fileName) { + File configFile = SPIFFS.open("/" + fileName, "r"); + if (!configFile) { + return "Failed"; + } + size_t size = configFile.size(); + configFile.close(); + return String(size); +} + +// ------------- Запись строки в файл +String writeFile(String fileName, String strings ) { + File configFile = SPIFFS.open("/" + fileName, "w"); + if (!configFile) { + return "Failed to open config file"; + } + configFile.print(strings); + //strings.printTo(configFile); + configFile.close(); + return "Write sucsses"; +} + +// ------------- Добовление строки в файл +String addFile(String fileName, String strings ) { + File configFile = SPIFFS.open("/" + fileName, "a"); + if (!configFile) { + return "Failed to open config file"; + } + configFile.println(strings); + configFile.close(); + return "Write sucsses"; +} + +// ------------- Чтение строки из файла +String readFileString(String fileName, String found) +{ + File configFile = SPIFFS.open("/" + fileName, "r"); + if (!configFile) { + return "Failed"; + } + if (configFile.find(found.c_str())) { + return configFile.readStringUntil('\r\n'); //'\r' + } + //return "|-|-|"; + configFile.close(); +} + +//=======================================УПРАВЛЕНИЕ ВИДЖЕТАМИ MQTT====================================================================== + + +void sendCONFIG(String topik, String widgetConfig, String key, String date) { + yield(); + topik = prefix + "/" + chipID + "/" + topik + "/status"; + String outer = "{\"widgetConfig\":"; + String inner = "{\""; + inner = inner + key; + inner = inner + "\":\""; + inner = inner + date; + inner = inner + "\""; + inner = inner + "}}"; + String t = outer + inner; + //Serial.println(t); + //client.publish(MQTT::Publish(topik, t).set_qos(1)); + yield(); +} +//============================================================================================================= +#ifdef led_status +void led_blink(int pin, int fq, String blink_satus) { + + pinMode(pin, OUTPUT); + + if (blink_satus == "on") tone(pin, fq); + if (blink_satus == "off") { + + noTone(pin); + digitalWrite(pin, HIGH); + + } +} +#endif + +void getMemoryLoad(String text) { + #ifdef ESP8266 + int all_memory = 53312; + #endif + #ifdef ESP32 + int all_memory = 362868; + #endif + int memory_remain = ESP.getFreeHeap(); + int memory_used = all_memory - memory_remain; + int memory_load = memory_used * 100 / all_memory; + if (memory_load > 65) Serial.print("Attention!!! too match memory used!!!"); + Serial.print(text + " memory used:"); + Serial.println(String(memory_load) + "%"); + +} + +//esp32 full memory = 362868 +//esp8266 full memory = 53312 diff --git a/mqtt.ino b/mqtt.ino new file mode 100644 index 00000000..a202bcaf --- /dev/null +++ b/mqtt.ino @@ -0,0 +1,370 @@ +//===============================================ИНИЦИАЛИЗАЦИЯ================================================ +void MQTT_init() { + + server.on("/mqttSave", HTTP_GET, [](AsyncWebServerRequest * request) { + + if (request->hasArg("mqttServer")) { + jsonWrite(configSetup, "mqttServer", request->getParam("mqttServer")->value()); + } + if (request->hasArg("mqttPort")) { + int port = (request->getParam("mqttPort")->value()).toInt(); + jsonWrite(configSetup, "mqttPort", port); + } + if (request->hasArg("mqttUser")) { + jsonWrite(configSetup, "mqttUser", request->getParam("mqttUser")->value()); + } + if (request->hasArg("mqttPass")) { + jsonWrite(configSetup, "mqttPass", request->getParam("mqttPass")->value()); + } + + saveConfig(); + + client.disconnect(); + MQTT_Connecting(false); + + String tmp = "{}"; + jsonWrite(tmp, "title", "" + stateMQTT()); + jsonWrite(tmp, "class", "pop-up"); + + request->send(200, "text/text", tmp); // отправляем ответ о выполнении + }); + + + + //проверка подключения к серверу + ts.add(WIFI_MQTT_CONNECTION_CHECK, wifi_mqtt_reconnecting, [&](void*) { + if (WiFi.status() == WL_CONNECTED) { + Serial.println("[V] WiFi-ok"); + if (client.connected()) { + Serial.println("[V] MQTT-ok"); + } else { + MQTT_Connecting(true); + } + } else { + Serial.println("[E] Lost WiFi connection"); + ts.remove(WIFI_MQTT_CONNECTION_CHECK); + StartAPMode(); + } + }, nullptr, true); +} + +//================================================ОБНОВЛЕНИЕ==================================================== + +void handleMQTT() { + if (WiFi.status() == WL_CONNECTED) { + if (client.connected()) { + client.loop(); + } + } +} +//===============================================ПОДКЛЮЧЕНИЕ======================================================== +void MQTT_Connecting(boolean out_date_send) { + + String mqtt_server = jsonRead(configSetup, "mqttServer"); + + if ((mqtt_server != "")) { + + static boolean first = true; + if (!first) Serial.println("[E] Lost MQTT connection, start reconnecting"); + first = false; + + //ssl//espClient.setCACert(local_root_ca1); + + client.setServer(mqtt_server.c_str(), jsonReadtoInt(configSetup, "mqttPort")); + // подключаемся к MQTT серверу + if (WiFi.status() == WL_CONNECTED) { + if (!client.connected()) { + Serial.println("[V] Connecting to MQTT server commenced"); + //busy = true; + if (client.connect(chipID.c_str(), jsonRead(configSetup, "mqttUser").c_str(), jsonRead(configSetup, "mqttPass").c_str())) { + Serial.println("[V] MQTT connected"); + + client.setCallback(callback); + + client.subscribe(prefix.c_str()); // Для приема получения HELLOW и подтверждения связи + client.subscribe((prefix + "/" + chipID + "/+/control").c_str()); // Подписываемся на топики control + client.subscribe((prefix + "/" + chipID + "/order").c_str()); // Подписываемся на топики order + //client.subscribe((prefix + "/" + chipID + "/test").c_str()); //Для приема получения work и подтверждения связи (для приложения mqtt IOT MQTT Panel) + /* String tmp_line = id_of_other_device; + + while (tmp_line.length() != 0) { + + String id = selectToMarker(tmp_line, ","); //2058631-1589487 1 + id = selectFromMarkerToMarker(id, " ", 0); + client.subscribe((prefix + "/" + id + "/+/status").c_str(), 0); + Serial.println("->subscribed to device, id: " + id); + + tmp_line = deleteBeforeDelimiter(tmp_line, ","); + }*/ + + client.subscribe((prefix + "/ids").c_str()); // Подписываемся на топики ids + sendMQTT("test", "work"); + Serial.println("[V] Callback set, subscribe done"); + //busy = false; + if (out_date_send) outcoming_date(); //отправляем данные в виджеты + } else { + //Serial.println(stateMQTT()); + Serial.println("[E] try again in " + String(wifi_mqtt_reconnecting / 1000) + " sec"); + } + } + } + } else { + Serial.println("[E] No date for MQTT connection"); + } +} + +//=====================================================ВХОДЯЩИЕ ДАННЫЕ======================================================== + +void callback(char* topic, byte* payload, unsigned int length) { + Serial.print("[MQTT] "); + Serial.print(topic); + String topic_str = String(topic); + + String str; + for (int i = 0; i < length; i++) { + str += (char)payload[i]; + } + Serial.println(" => " + str); + + if (str == "HELLO") outcoming_date(); + //if (str == "work") outcoming_date(); //Для приема получения work и подтверждения связи (для приложения mqtt IOT MQTT Panel) + //превращает название топика в команду, а значение в параметр команды + + if (topic_str.indexOf("control") > 0) { //IoTmanager/800324-1458415/RelaySet1/control 1 /IoTmanager/9139530-1458400/RelaySet1/control -> 1 + //Serial.println(topic_str); + String topic = selectFromMarkerToMarker(topic_str, "/", 3); //RelaySet1 + String number = selectToMarkerLast(topic, "Set"); //1 + topic.replace(number, ""); //RelaySet + String final_line = topic + " " + number + " " + str; //RelaySet 1 1 + //Serial.println(final_line); + order_loop += final_line + ","; + + } + if (topic_str.indexOf("order") > 0) { + str.replace("_", " "); + //Serial.println(str); + order_loop += str + ","; + } +} + +//данные которые отправляем при подключении или отбновлении страницы +void outcoming_date() { + + //busy = true; + + sendAllWigets(); + sendAllData(); + + if (flagLoggingAnalog) sendLogData("log.analog.txt", "loganalog"); + if (flagLoggingPh) sendLogData("log.ph.txt", "logph"); + if (flagLoggingDallas) sendLogData("log.dallas.txt", "logdallas"); + if (flagLoggingLevel) sendLogData("log.level.txt", "loglevel"); + + Serial.println("[V] Sending all date to iot manager completed"); + + //busy = false; + +} +//======================================CONFIG================================================== +///IoTmanager/2058631-1589487/config {----viget----} +///sendMQTT("config", data); +boolean sendMQTT(String end_of_topik, String data) { + String topik = prefix + "/" + chipID + "/" + end_of_topik; + boolean send_status = client.beginPublish(topik.c_str(), data.length(), false); + client.print(data); + client.endPublish(); + return send_status; +} +//======================================STATUS================================================== +///IoTmanager/2058631-1589487/rel1/status {"status":"1"} +///sendSTATUS(topic, state) +void sendSTATUS(String topik, String state) { + topik = prefix + "/" + chipID + "/" + topik + "/" + "status"; + String json_ = "{}"; + jsonWrite(json_, "status", state); + + //long st_time = millis(); + int send_status = client.publish (topik.c_str(), json_.c_str(), false); + //long end_time = millis(); + //Serial.println("send status = " + String(send_status) + ", timeout = " + String(end_time - st_time)); +} +/*void sendSTATUS(String topik, String state, String type, String param) { + topik = prefix + "/" + chipID + "/" + topik + "/" + "status"; + String json_ = "{}"; + jsonWrite(json_, "status", state); + jsonWrite(json_, type, param); + + //long st_time = millis(); + int send_status = client.publish (topik.c_str(), json_.c_str(), false); + //long end_time = millis(); + //Serial.println("send status = " + String(send_status) + ", timeout = " + String(end_time - st_time)); + }*/ +//======================================CONTROL================================================== +///IoTmanager/2058631-1589487/rel1/control 1 +void sendCONTROL(String id, String topik, String state) { + String all_line = prefix + "/" + id + "/" + topik + "/control"; + + //long st_time = millis(); + int send_status = client.publish (all_line.c_str(), state.c_str(), false); + //long end_time = millis(); + //Serial.println("send control = " + String(send_status) + ", timeout = " + String(end_time - st_time)); +} + +//=====================================================ОТПРАВЛЯЕМ ВИДЖЕТЫ======================================================== +void sendAllWigets() { + if (all_vigets != "") { + int counter = 0; + String line; + int psn_1 = 0; + int psn_2; + + do { + + psn_2 = all_vigets.indexOf("\r\n", psn_1); + line = all_vigets.substring(psn_1, psn_2); + jsonWrite(line, "id", String(counter)); + counter++; + sendMQTT("config", line); + Serial.println("[V] " + line); + psn_1 = psn_2 + 1; + + } while (psn_2 + 2 < all_vigets.length()); + + getMemoryLoad("[i] after send all vigets"); + } +} +//=====================================================ОТПРАВЛЯЕМ ДАННЫЕ В ВИДЖЕТЫ ПРИ ОБНОВЛЕНИИ СТРАНИЦЫ======================================================== + +void sendAllData() { //берет строку json и ключи превращает в топики а значения колючей в них посылает + + String current_config = configJson; //{"SSDP":"MODULES","lang":"","ip":"192.168.43.60","DS":"34.00","rel1":"1","rel2":"1"} + getMemoryLoad("[i] after send all date"); + current_config.replace("{", ""); + current_config.replace("}", ""); //"SSDP":"MODULES","lang":"","ip":"192.168.43.60","DS":"34.00","rel1":"1","rel2":"1" + current_config += ","; //"SSDP":"MODULES","lang":"","ip":"192.168.43.60","DS":"34.00","rel1":"1","rel2":"1", + + while (current_config.length() != 0) { + + String tmp = selectToMarker (current_config, ","); + String topic = selectToMarker (tmp, ":"); + topic.replace("\"", ""); + String state = selectToMarkerLast (tmp, ":"); + state.replace("\"", ""); + if (topic != ssdpS && topic != "lang" && topic != "ip" && topic.indexOf("_in") < 0) { + sendSTATUS(topic, state); + //Serial.println("-->" + topic + " " + state); + } + current_config = deleteBeforeDelimiter(current_config, ","); + } +} + +void sendLogData(String file, String topic) { + + String log_date = readFile(file, 5000) + "\r\n"; + getMemoryLoad("[i] after send log date"); + + log_date.replace("\r\n", "\n"); + log_date.replace("\r", "\n"); + + while (log_date.length() != 0) { + String tmp = selectToMarker (log_date, "\n"); + + //sendSTATUS(topic, selectFromMarkerToMarker(tmp, " ", 2)); + if (tmp != "") sendSTATUS(topic, tmp); + + log_date = deleteBeforeDelimiter(log_date, "\n"); + } +} + +String stateMQTT() { + + int state = client.state(); + + switch (state) { + case -4: return "the server didn't respond within the keepalive time"; + break; + case -3: return "the network connection was broken"; + break; + case -2: return "the network connection failed"; + break; + case -1: return "the client is disconnected cleanly"; + break; + case 0: return "the client is connected"; + break; + case 1: return "the server doesn't support the requested version of MQTT"; + break; + case 2: return "the server rejected the client identifier"; + break; + case 3: return "the server was unable to accept the connection"; + break; + case 4: return "the username/password were rejected"; + break; + case 5: return "the client was not authorized to connect"; + break; + } +} +/*void scenario_devices_topiks_subscribe() { + + //SCENARIO ANALOG > 5 800324-1458415 rel1 0 + if (jsonRead(configSetup, "scenario") == "1") { + //String all_text = readFile("scenario.all.txt", 1024) + "\r\n"; + String all_text = scenario + "\r\n"; + all_text.replace("\r\n", "\n"); + all_text.replace("\r", "\n"); + while (all_text.length() != 0) { + String line_ = selectToMarker (all_text, "\n"); + String id = selectFromMarkerToMarker(line_, " ", 4); + if (id != "not found") { + client.subscribe((prefix + "/" + id + "/+/status").c_str(), 0); + Serial.println("subscribed to device, id: " + id); + } + all_text = deleteBeforeDelimiter(all_text, "\n"); + } + } + } +*/ +/*void scenario_devices_test_msg_send() { + + if (jsonRead(configSetup, "scenario") == "1") { + + String all_text = scenario + "\r\n"; + all_text.replace("\r\n", "\n"); + all_text.replace("\r", "\n"); + while (all_text.length() != 0) { + String line_ = selectToMarker (all_text, "\n"); + String id = selectFromMarkerToMarker(line_, " ", 4); + if (id != "not found") { + //Serial.println(); + Serial.println(client.publish ((prefix + "/" + id).c_str(), "CHECK", true)); + + } + all_text = deleteBeforeDelimiter(all_text, "\n"); + } + } + }*/ + +/* + //----------------------------------------------------------------------------------------------------------------------------------------------- + //jsonWrite(tmp, "status", "1"); + + String current_config = configJson; //{"SSDP":"MODULES","lang":"","ip":"192.168.43.60","DS":"34.00","rel1":"1","rel2":"1"} + current_config.replace("{", ""); + current_config.replace("}", ""); //"SSDP":"MODULES","lang":"","ip":"192.168.43.60","DS":"34.00","rel1":"1","rel2":"1" + current_config += ","; //"SSDP":"MODULES","lang":"","ip":"192.168.43.60","DS":"34.00","rel1":"1","rel2":"1", + + while (current_config.length() != 0) { + + String tmp = selectToMarker (current_config, ","); //"rel1":"1" + String topic = selectToMarker (tmp, ":"); //"rel1" + topic.replace("\"", ""); //rel1 + Serial.println(topic); + String state = selectToMarkerLast (tmp, ":"); //"1" + state.replace("\"", ""); //1 + + //if (viget.lastIndexOf(topic) > 0) { + jsonWrite(tmp, "status", state); + //} + current_config = deleteBeforeDelimiter(current_config, ","); + } + //------------------------------------------------------------------------------------------------------------------------------------------------- +*/ diff --git a/set.h b/set.h new file mode 100644 index 00000000..b378a4b8 --- /dev/null +++ b/set.h @@ -0,0 +1,118 @@ +//==библиотеки и объекты для ESP8266==// +#ifdef ESP8266 +#include +#include +#include +#include +#endif + +//==библиотеки и объекты для ESP32==// +#ifdef ESP32 +#include +#include +#ifdef MDNS_enable +#include +#endif +#include +#include +#include +HTTPClient http; +#endif + +//==общие библиотеки и объекты==// +#ifdef OTA_enable +#include +#endif +#include +#include +#include +#include +AsyncWebServer server(80); +#ifdef WS_enable +AsyncWebSocket ws("/ws"); +#endif +AsyncEventSource events("/events"); +#include "time.h" +#include +TickerScheduler ts(30); +enum { ROUTER_SEARCHING, WIFI_MQTT_CONNECTION_CHECK, LEVEL, ANALOG_, PH, DALLAS, ANALOG_LOG, LEVEL_LOG, DALLAS_LOG, PH_LOG, CMD , TIMER_COUNTDOWN, TIMERS, TEST}; + +//ssl//#include "dependencies/WiFiClientSecure/WiFiClientSecure.h" //using older WiFiClientSecure +#include +WiFiClient espClient; +//ssl//WiFiClientSecure espClient; +PubSubClient client(espClient); +//--------------------------------------------------------------- +#include +StringCommand sCmd; +//--------------------------------------------------------------- +#include +#define NUM_BUTTONS 6 +boolean but[NUM_BUTTONS]; +Bounce * buttons = new Bounce[NUM_BUTTONS]; +//---------------------------------------------------------------- +#include "GyverFilters.h" //настраивается в GyverHacks.h - MEDIAN_FILTER_SIZE +GMedian medianFilter; +//---------------------------------------------------------------- +#include +#include +OneWire *oneWire; +DallasTemperature sensors; + + +//----------------------------------------------------------------- +//#define OTA_enable +//----------------------------------------------------------------- +//#define MDNS_enable +//----------------------------------------------------------------- +//#define WS_enable +//----------------------------------------------------------------- + + + +#define wifi_mqtt_reconnecting 60000 +//----------------------------------------------------------------- +#define analog_update_int 5000 +//----------------------------------------------------------------- +#define ph_shooting_interval 500 //интервал выстрела датчика +#define ph_times_to_send 10 //после скольки выстрелов делать отправку данных +//----------------------------------------------------------------- +#define temp_update_int 5000 +//----------------------------------------------------------------- +#define tank_level_shooting_interval 500 //интервал выстрела датчика +#define tank_level_times_to_send 20 //после скольки выстрелов делать отправку данных +//----------------------------------------------------------------- + + +const char* hostName = "esp-async"; +const char* http_username = "admin"; +const char* http_password = "admin"; + +String configSetup = "{}"; +String configJson = "{}"; +String optionJson = "{}"; + +String chipID = ""; +String prefix = "/IoTmanager"; +String prex; +String ids; +//boolean busy; +String all_vigets = ""; +String scenario; + +String order_loop; + +boolean flagLoggingAnalog = false; +boolean flagLoggingLevel = false; +boolean flagLoggingDallas = false; +boolean flagLoggingPh = false; + +const char* ntpServer = "pool.ntp.org"; +const long gmtOffset_sec = 3600; +const int daylightOffset_sec = 3600; + +const String scenarioFileNameS = "scenario.all.txt"; +const String ssdpS = "SSDP"; +String current_time; + +int scenario_line_status [] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};