diff --git a/.vscode/settings.json b/.vscode/settings.json
index 03d0d454..cc4865fe 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,66 +1,7 @@
{
- "terminal.integrated.env.windows": {
- "PATH": "C:\\Users\\ytrikoz\\.platformio\\penv\\Scripts;C:\\Users\\ytrikoz\\.platformio\\penv;C:\\Program Files (x86)\\Borland\\Delphi7\\Bin;C:\\Program Files (x86)\\Borland\\Delphi7\\Projects\\Bpl\\;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C:\\WINDOWS\\System32\\OpenSSH\\;C:\\Program Files\\Git\\cmd\\;c:\\android-studio\\jre\\jre\\bin\\;C:\\Program Files (x86)\\Microsoft SQL Server\\150\\DTS\\Binn\\;C:\\Front\\Shared\\;C:\\Program Files (x86)\\Plantronics\\Spokes3G\\;C:\\Program Files\\Microsoft SQL Server\\130\\Tools\\Binn\\;C:\\Program Files\\Microsoft SQL Server\\Client SDK\\ODBC\\170\\Tools\\Binn\\;C:\\Program Files\\nodejs\\;C:\\ProgramData\\chocolatey\\bin;C:\\Program Files\\dotnet\\;C:\\Users\\ytrikoz\\AppData\\Local\\Microsoft\\WindowsApps;C:\\Users\\ytrikoz\\AppData\\Local\\Programs\\Microsoft VS Code\\bin;C:\\Users\\ytrikoz\\AppData\\Roaming\\npm;C:\\MinGW\\bin;;C:\\Program Files (x86)\\West Wind Html Help Builder;C:\\Program Files (x86)\\Borland\\Delphi7\\Bin;C:\\Program Files (x86)\\Borland\\Delphi7\\Projects\\Bpl\\;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C:\\WINDOWS\\System32\\OpenSSH\\;C:\\Program Files\\Git\\cmd\\;c:\\android-studio\\jre\\jre\\bin\\;C:\\Program Files (x86)\\Microsoft SQL Server\\150\\DTS\\Binn\\;C:\\Front\\Shared\\;C:\\Program Files (x86)\\Plantronics\\Spokes3G\\;C:\\Program Files\\Microsoft SQL Server\\130\\Tools\\Binn\\;C:\\Program Files\\Microsoft SQL Server\\Client SDK\\ODBC\\170\\Tools\\Binn\\;C:\\Program Files\\nodejs\\;C:\\ProgramData\\chocolatey\\bin;C:\\Program Files\\dotnet\\;C:\\Users\\ytrikoz\\AppData\\Local\\Microsoft\\WindowsApps;C:\\Users\\ytrikoz\\AppData\\Local\\Programs\\Microsoft VS Code\\bin;C:\\Users\\ytrikoz\\AppData\\Roaming\\npm;C:\\MinGW\\bin;;C:\\Program Files (x86)\\West Wind Html Help Builder",
- "PLATFORMIO_CALLER": "vscode"
- },
"files.associations": {
- "*.cpp": "cpp",
"functional": "cpp",
- "*.tcc": "cpp",
- "optional": "cpp",
- "ratio": "cpp",
- "system_error": "cpp",
- "array": "cpp",
- "regex": "cpp",
- "tuple": "cpp",
- "type_traits": "cpp",
- "utility": "cpp",
"bitset": "cpp",
- "chrono": "cpp",
- "algorithm": "cpp",
- "random": "cpp",
- "atomic": "cpp",
- "cctype": "cpp",
- "cerrno": "cpp",
- "cfloat": "cpp",
- "climits": "cpp",
- "clocale": "cpp",
- "cmath": "cpp",
- "cstdarg": "cpp",
- "cstddef": "cpp",
- "cstdint": "cpp",
- "cstdio": "cpp",
- "cstdlib": "cpp",
- "ctime": "cpp",
- "cwchar": "cpp",
- "cwctype": "cpp",
- "deque": "cpp",
- "list": "cpp",
- "map": "cpp",
- "set": "cpp",
- "string": "cpp",
- "unordered_map": "cpp",
- "vector": "cpp",
- "exception": "cpp",
- "iterator": "cpp",
- "memory": "cpp",
- "numeric": "cpp",
- "fstream": "cpp",
- "initializer_list": "cpp",
- "ios": "cpp",
- "iosfwd": "cpp",
- "istream": "cpp",
- "limits": "cpp",
- "locale": "cpp",
- "new": "cpp",
- "ostream": "cpp",
- "queue": "cpp",
- "sstream": "cpp",
- "stack": "cpp",
- "stdexcept": "cpp",
- "streambuf": "cpp",
- "cinttypes": "cpp",
- "cstdbool": "cpp",
- "typeinfo": "cpp"
+ "algorithm": "cpp"
}
}
\ No newline at end of file
diff --git a/data/config.json b/data/config.json
index 34c25c56..7cd5e871 100644
--- a/data/config.json
+++ b/data/config.json
@@ -3,8 +3,8 @@
"chipID": "",
"apssid": "IoTmanager",
"appass": "",
- "routerssid": "rise",
- "routerpass": "hostel3333",
+ "routerssid": "home",
+ "routerpass": "kisa3333",
"timezone": 2,
"ntp": "pool.ntp.org",
"mqttServer": "91.204.228.124",
@@ -17,6 +17,6 @@
"weblogin": "admin",
"webpass": "admin",
"udponoff": "1",
- "blink": "1",
+ "blink": "0",
"oneWirePin": "2"
}
\ No newline at end of file
diff --git a/data/css/build.css.gz b/data/css/build.css.gz
index 4bf6e060..b62ceaf0 100644
Binary files a/data/css/build.css.gz and b/data/css/build.css.gz differ
diff --git a/data/dev_conf.txt b/data/dev_conf.txt
deleted file mode 100644
index 2c5bb9ae..00000000
--- a/data/dev_conf.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-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 adc 0 Аналоговый#вход Датчики fillgauge 1 1023 1 1023 6
-logging adc 1 100 Аналоговый#вход Датчики 7
-
-//Это демо конфигурация. В ней показано как связать кнопки c помощью сценариев
-//Кнопка номер 1 связана с кнопкой 2, 3 и с pwm 2
-//Так же продемонстрированна система логгирования данных строкой logging
-//1 - это интервал между точками в минутах, 100 это количество точек
diff --git a/data/dev_scen.txt b/data/dev_scen.txt
deleted file mode 100644
index 4927ac1e..00000000
--- a/data/dev_scen.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-button1 = 1
-buttonSet 2 1
-buttonSet 3 1
-pwmSet 2 1024
-end
-button1 = 0
-buttonSet 2 0
-buttonSet 3 0
-pwmSet 2 0
-end
-adc > 50
-buttonSet 2 1
-end
\ No newline at end of file
diff --git a/data/edit.htm b/data/edit.htm
new file mode 100644
index 00000000..1ebb989d
--- /dev/null
+++ b/data/edit.htm
@@ -0,0 +1,658 @@
+
+
+
+
+
+ FS Editor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/data/index.htm.gz b/data/index.htm.gz
index 139f0040..073ff4ab 100644
Binary files a/data/index.htm.gz and b/data/index.htm.gz differ
diff --git a/data/index.json b/data/index.json
index 1b6413ad..0f12c670 100644
--- a/data/index.json
+++ b/data/index.json
@@ -23,12 +23,6 @@
"action": "/?set.device",
"class": "btn btn-block btn-default"
},
- {
- "type": "link",
- "title": "Список других устройств в сети",
- "action": "/?set.udp",
- "class": "btn btn-block btn-default"
- },
{
"type": "link",
"title": "Конфигурация WIFI",
diff --git a/data/items/analog-adc.txt b/data/items/analog-adc.txt
new file mode 100644
index 00000000..8bc0e914
--- /dev/null
+++ b/data/items/analog-adc.txt
@@ -0,0 +1 @@
+0;analog-adc;id;fillgauge;Сенсоры;Аналоговый;order;gol;map[0,1024,0,100];c[1]
\ No newline at end of file
diff --git a/data/items/bme280-hum.txt b/data/items/bme280-hum.txt
new file mode 100644
index 00000000..c8afd255
--- /dev/null
+++ b/data/items/bme280-hum.txt
@@ -0,0 +1 @@
+0;bme280-hum;id;anydataHum;Сенсоры;Влажность;order;addr[0x76];c[1]
\ No newline at end of file
diff --git a/data/items/bme280-press.txt b/data/items/bme280-press.txt
new file mode 100644
index 00000000..f79973e2
--- /dev/null
+++ b/data/items/bme280-press.txt
@@ -0,0 +1 @@
+0;bme280-press;id;anydataPress;Сенсоры;Давление;order;addr[0x76];c[1]
\ No newline at end of file
diff --git a/data/items/bme280-temp.txt b/data/items/bme280-temp.txt
new file mode 100644
index 00000000..6e5e9003
--- /dev/null
+++ b/data/items/bme280-temp.txt
@@ -0,0 +1 @@
+0;bme280-temp;id;anydataTemp;Сенсоры;Температура;order;addr[0x76];c[1]
\ No newline at end of file
diff --git a/data/items/bmp280-press.txt b/data/items/bmp280-press.txt
new file mode 100644
index 00000000..44b9e8c9
--- /dev/null
+++ b/data/items/bmp280-press.txt
@@ -0,0 +1 @@
+0;bmp280-press;id;anydataPress;Сенсоры;Давление;order;addr[0x76];c[1]
\ No newline at end of file
diff --git a/data/items/bmp280-temp.txt b/data/items/bmp280-temp.txt
new file mode 100644
index 00000000..c3cb42eb
--- /dev/null
+++ b/data/items/bmp280-temp.txt
@@ -0,0 +1 @@
+0;bmp280-temp;id;anydataTemp;Сенсоры;Температура;order;addr[0x76];c[1]
\ No newline at end of file
diff --git a/data/items/button-in.txt b/data/items/button-in.txt
new file mode 100644
index 00000000..79d79ec9
--- /dev/null
+++ b/data/items/button-in.txt
@@ -0,0 +1 @@
+0;button-in;id;toggle;Кнопки;Освещение;order;pin;db[20]
\ No newline at end of file
diff --git a/data/items/button-out.inv.txt b/data/items/button-out.inv.txt
new file mode 100644
index 00000000..fd3bdead
--- /dev/null
+++ b/data/items/button-out.inv.txt
@@ -0,0 +1 @@
+0;button-out;id;toggle;Кнопки;Освещение;order;pin;inv[1];st[1]
\ No newline at end of file
diff --git a/data/items/button-out.npin.txt b/data/items/button-out.npin.txt
new file mode 100644
index 00000000..380b815f
--- /dev/null
+++ b/data/items/button-out.npin.txt
@@ -0,0 +1 @@
+0;button-out;id;toggleSunMoon;Кнопки;Освещение;order;st[0]
\ No newline at end of file
diff --git a/data/items/button-out.pin.txt b/data/items/button-out.pin.txt
new file mode 100644
index 00000000..81310f4e
--- /dev/null
+++ b/data/items/button-out.pin.txt
@@ -0,0 +1 @@
+0;button-out;id;toggle;Кнопки;Освещение;order;pin;st[0]
\ No newline at end of file
diff --git a/data/items/dallas-temp.txt b/data/items/dallas-temp.txt
new file mode 100644
index 00000000..a6b87c28
--- /dev/null
+++ b/data/items/dallas-temp.txt
@@ -0,0 +1 @@
+0;dallas-temp;id;anydataTemp;Сенсоры;Температура;order;sal;c[1]
\ No newline at end of file
diff --git a/data/items/dht11-hum.txt b/data/items/dht11-hum.txt
new file mode 100644
index 00000000..b7d9a820
--- /dev/null
+++ b/data/items/dht11-hum.txt
@@ -0,0 +1 @@
+0;dht-hum;id;anydataHum;Сенсоры;Влажность;order;thd;type[dht11];c[1]
\ No newline at end of file
diff --git a/data/items/dht11-temp.txt b/data/items/dht11-temp.txt
new file mode 100644
index 00000000..39c5e949
--- /dev/null
+++ b/data/items/dht11-temp.txt
@@ -0,0 +1 @@
+0;dht-temp;id;anydataTemp;Сенсоры;Температура;order;thd;type[dht11];c[1]
\ No newline at end of file
diff --git a/data/items/dht22-hum.txt b/data/items/dht22-hum.txt
new file mode 100644
index 00000000..ab69cf97
--- /dev/null
+++ b/data/items/dht22-hum.txt
@@ -0,0 +1 @@
+0;dht-hum;id;anydataHum;Сенсоры;Влажность;order;thd;type[dht22];c[1]
\ No newline at end of file
diff --git a/data/items/dht22-temp.txt b/data/items/dht22-temp.txt
new file mode 100644
index 00000000..d14a434d
--- /dev/null
+++ b/data/items/dht22-temp.txt
@@ -0,0 +1 @@
+0;dht-temp;id;anydataTemp;Сенсоры;Температура;order;thd;type[dht22];c[1]
\ No newline at end of file
diff --git a/data/items/input-digit.txt b/data/items/input-digit.txt
new file mode 100644
index 00000000..bfb99882
--- /dev/null
+++ b/data/items/input-digit.txt
@@ -0,0 +1 @@
+0;input-digit;id;inputDigit;Ввод;Введите#цифру;order;st[60]
\ No newline at end of file
diff --git a/data/items/input-time.txt b/data/items/input-time.txt
new file mode 100644
index 00000000..46e49666
--- /dev/null
+++ b/data/items/input-time.txt
@@ -0,0 +1 @@
+0;input-time;id;inputTime;Ввод;Введите#время;order;st[10-00-00]
\ No newline at end of file
diff --git a/data/items/modbus.txt b/data/items/modbus.txt
new file mode 100644
index 00000000..a782395a
--- /dev/null
+++ b/data/items/modbus.txt
@@ -0,0 +1 @@
+0;modbus;id;anydata;Modbus;Регистр;order;addr[1];reg[0];c[1]
\ No newline at end of file
diff --git a/data/items/output-text.txt b/data/items/output-text.txt
new file mode 100644
index 00000000..f96c2e26
--- /dev/null
+++ b/data/items/output-text.txt
@@ -0,0 +1 @@
+0;output-text;id;anydata;Вывод;Сигнализация;order;st[Обнаружено#движение]
\ No newline at end of file
diff --git a/data/items/pwm-out.txt b/data/items/pwm-out.txt
new file mode 100644
index 00000000..39a42037
--- /dev/null
+++ b/data/items/pwm-out.txt
@@ -0,0 +1 @@
+0;pwm-out;id;range;Ползунки;Яркость;order;pin;st[500]
\ No newline at end of file
diff --git a/data/items/ultrasonic-cm.txt b/data/items/ultrasonic-cm.txt
new file mode 100644
index 00000000..cca50890
--- /dev/null
+++ b/data/items/ultrasonic-cm.txt
@@ -0,0 +1 @@
+0;ultrasonic-cm;id;anydata;Сенсоры;Расстояние;order;cin;map[0,500,0,100];c[1]
\ No newline at end of file
diff --git a/data/js/build.chart.js.gz b/data/js/build.chart.js.gz
index ac021668..654707fd 100644
Binary files a/data/js/build.chart.js.gz and b/data/js/build.chart.js.gz differ
diff --git a/data/js/function.js.gz b/data/js/function.js.gz
index 443fbca2..10c9953a 100644
Binary files a/data/js/function.js.gz and b/data/js/function.js.gz differ
diff --git a/data/s.conf.csv b/data/s.conf.csv
new file mode 100644
index 00000000..2d2f8d1d
--- /dev/null
+++ b/data/s.conf.csv
@@ -0,0 +1 @@
+Тип элемента;Id;Виджет;Имя вкладки;Имя виджета;Позиция виджета
\ No newline at end of file
diff --git a/data/s.scen.txt b/data/s.scen.txt
new file mode 100644
index 00000000..ab0c0141
--- /dev/null
+++ b/data/s.scen.txt
@@ -0,0 +1 @@
+//
\ No newline at end of file
diff --git a/data/set.device.json b/data/set.device.json
index f890fa5e..ef80ac85 100644
--- a/data/set.device.json
+++ b/data/set.device.json
@@ -1,142 +1,171 @@
{
- "configs": [
- "/config.setup.json",
- "/config.option.json",
- "/config.live.json",
- "/lang/lang.ru.json"
- ],
- "class": "col-sm-offset-1 col-sm-10",
- "content": [
- {
- "type": "h5",
- "title": "{{name}}",
- "class": "alert-default"
- },
- {
- "type": "link",
- "title": "{{ButMainPage}}",
- "action": "/",
- "class": "btn btn-block btn-default"
- },
- {
- "type": "hr"
- },
- {
- "type": "h4",
- "title": "Device ID: {{chipID}}"
- },
- {
- "type": "h4",
- "title": "IP address: {{ip}}"
- },
- {
- "type": "h4",
- "title": "Time: {{time}}"
- },
- {
- "type": "h4",
- "title": "Uptime: {{uptime}}"
- },
- {
- "type": "h4",
- "title": "Build version: {{firmware_version}}"
- },
- {
- "type": "h4",
- "title": "LittleFS version: 2.3.5"
- },
- {
- "type": "hr"
- },
- {
- "type": "dropdown",
- "name": "help-url",
- "class": "btn btn-default",
- "style": "display:inline",
- "title": {
- "#": "{{SetDevPreset}}",
- "/set?preset=001": "1.Вкл. выкл. локального реле",
- "/set?preset=002": "2.Вкл. выкл. локального реле в определенное время",
- "/set?preset=003": "3.Вкл. выкл. локального реле на определенный период времени",
- "/set?preset=004": "4.Вкл. выкл. нескольких локальных реле кнопкой в приложении",
- "/set?preset=005": "5.Вкл. выкл. локального реле физической кнопкой и кнопкой в приложении параллельно (для выключателя света)",
- "/set?preset=006": "6.Вкл. выкл. нескольких удаленных реле кнопкой в приложении (нужно указать Device ID)",
- "/set?preset=007": "7.Вкл. выкл. нескольких удаленных реле физической кнопкой (нужно указать Device ID)",
- "/set?preset=008": "8.Широтно импульсная модуляция",
- "/set?preset=009": "9.Сенсор DHT11 (темп, влажность) и логгирование",
- "/set?preset=010": "10.Сенсор DHT22, DHT33, DHT44, AM2302, RHT03 (темп, влажность) и логгирование",
- "/set?preset=011": "11.Аналоговый сенсор и логгирование",
- "/set?preset=012": "12.Cенсор bmp280 (темп, давление) и логгирование",
- "/set?preset=013": "13.Cенсор bme280 (темп, давление, влажность, высота) и логгирование",
- "/set?preset=014": "14.Сенсор DS18B20 (темп) и логгирование",
- "/set?preset=015": "15.Термостат на DS18B20 с переключением в ручной режим и логгированием",
- "/set?preset=016": "16.Котроль уровня в баке (датчик расстояния) на сенсорах: JSN-SR04T, HC-SR04, HY-SRF05 и логгирование",
- "/set?preset=017": "17.Датчик движения включающий свет",
- "/set?preset=018": "18.Охранный датчик движения",
- "/set?preset=019": "19.Система управления шаговыми двигателями на основе драйвера A4988 (открытие закрытие штор)",
- "/set?preset=020": "20.Система управления сервоприводами",
- "/set?preset=021": "21.Модуль uart (serial). Двухстороняя связь с устройством через uart. Получение данных и отправка команд",
- "/set?preset=100": "22.Настройки по умолчанию"
- }
- },
- {
- "type": "h2",
- "title": "{{SetDevConf}}"
- },
- {
- "type": "file",
- "state": "dev_conf.txt",
- "style": "width:100%;height:350px",
- "title": "Сохранить",
- "action": "/set?devinit",
- "class": "btn btn-block btn-default"
- },
- {
- "type": "h2",
- "title": "Сценарии"
- },
- {
- "type": "checkbox",
- "name": "scen",
- "title": "Включить сценарии",
- "action": "/set?scen=[[scen]]",
- "state": "{{scen}}"
- },
- {
- "type": "file",
- "state": "dev_scen.txt",
- "style": "width:100%;height:350px",
- "title": "Сохранить",
- "action": "/set?sceninit",
- "class": "btn btn-block btn-default"
- },
- {
- "type": "link",
- "title": "Инструкция к системе автоматизации",
- "action": "https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/wiki/Instruction",
- "class": "btn btn-block btn-default"
- },
- {
- "type": "link",
- "title": "Очистить логи сенсоров",
- "action": "/set?cleanlog",
- "class": "btn btn-block btn-default"
- },
- {
- "type": "hr"
- },
- {
- "type": "h3",
- "name": "my-block",
- "style": "position:fixed;top:50%;left:50%;width:400px;margin-left:-200px;text-align:center;",
- "class": "hidden"
- },
- {
- "type": "button",
- "title": "Обновить прошивку устройства",
- "action": "/check",
- "response": "[[my-block]]",
- "class": "btn btn-block btn-default"
- }
- ]
+ "configs": [
+ "/config.setup.json",
+ "/config.option.json",
+ "/config.live.json",
+ "/lang/lang.ru.json"
+ ],
+ "class": "col-sm-offset-1 col-sm-10",
+ "content": [
+ {
+ "type": "h5",
+ "title": "{{name}}",
+ "class": "alert-default"
+ },
+ {
+ "type": "link",
+ "title": "{{ButMainPage}}",
+ "action": "/",
+ "class": "btn btn-block btn-default"
+ },
+ {
+ "type": "hr"
+ },
+ {
+ "type": "h4",
+ "title": "Device ID: {{chipID}}"
+ },
+ {
+ "type": "h4",
+ "title": "IP address: {{ip}}"
+ },
+ {
+ "type": "h4",
+ "title": "Time: {{time}}"
+ },
+ {
+ "type": "h4",
+ "title": "Uptime: {{uptime}}"
+ },
+ {
+ "type": "h4",
+ "title": "Build version: {{firmware_version}}"
+ },
+ {
+ "type": "h4",
+ "title": "LittleFS version: 257"
+ },
+ {
+ "type": "hr"
+ },
+ {
+ "type": "dropdown",
+ "name": "help-url",
+ "class": "btn btn-default",
+ "style": "display:inline",
+ "title": {
+ "#": "Выберите элемент из списка",
+ "/set?addItem=button-out.pin": "1.Кнопка управляющая пином",
+ "/set?addItem=button-out.npin": "2.Кнопка виртуальная",
+ "/set?addItem=button-in": "4.Кнопка физическая",
+ "/set?addItem=pwm-out": "3.Широтно импульсная модуляция pwm",
+ "/set?addItem=input-digit": "5.Окно ввода цифровых значений",
+ "/set?addItem=input-time": "6.Окно ввода времени",
+ "/set?addItem=output-text": "7.Окно вывода любого текста, предупреждения, цифры",
+ "/set?addItem=analog-adc": "8.Датчик аналоговый, чтение аналогового входа",
+ "/set?addItem=dallas-temp": "9.Датчик температуры ds18b20",
+ "/set?addItem=ultrasonic-cm": "10.Датчик расстояния ультрозвуковой JSN-SR04T, HC-SR04, HY-SRF05",
+ "/set?addItem=dht11-temp": "11.Датчик температуры DHT11",
+ "/set?addItem=dht11-hum": "12.Датчик влажности DHT11",
+ "/set?addItem=dht22-temp": "13.Датчик температуры DHT22, DHT33, DHT44, AM2302, RHT03",
+ "/set?addItem=dht22-hum": "14.Датчик влажности DHT22, DHT33, DHT44, AM2302, RHT03",
+ "/set?addItem=bme280-temp": "15.Датчик температуры bme280",
+ "/set?addItem=bme280-hum": "16.Датчик влажности bme280",
+ "/set?addItem=bme280-press": "17.Датчик давления bme280",
+ "/set?addItem=bmp280-temp": "18.Датчик температуры bmp280",
+ "/set?addItem=bmp280-press": "19.Датчик давления bmp280",
+ "/set?addItem=modbus": "20.Прочитать регистр modbus устройства"
+ }
+ },
+ {
+ "type": "hr"
+ },
+ {
+ "type": "csv",
+ "title": [
+ "checkbox",
+ "html",
+ "text",
+ "text",
+ "text",
+ "text",
+ "text"
+ ],
+ "state": "s.conf.csv",
+ "style": "width:100%;",
+ "action": "/set?saveItems",
+ "class": "btn btn-block btn-default"
+ },
+ {
+ "type": "hr"
+ },
+ {
+ "type": "link",
+ "title": "Удалить выбранные элементы",
+ "action": "javascript:{send_request(this,'/set?delChoosingItems');setTimeout(function(){location.href='/?set.device' ; }, 1000);}",
+ "class": "btn btn-block btn-default"
+ },
+ {
+ "type": "link",
+ "title": "Удалить все",
+ "action": "/set?delAllItems",
+ "class": "btn btn-block btn-default"
+ },
+ {
+ "type": "h2",
+ "title": "Сценарии"
+ },
+ {
+ "type": "checkbox",
+ "name": "scen",
+ "title": "Включить сценарии",
+ "action": "/set?scen=[[scen]]",
+ "state": "{{scen}}"
+ },
+ {
+ "type": "file",
+ "state": "s.scen.txt",
+ "style": "width:100%;height:350px",
+ "title": "Сохранить",
+ "action": "/set?sceninit",
+ "class": "btn btn-block btn-default"
+ },
+ {
+ "type": "hr"
+ },
+ {
+ "type": "link",
+ "title": "Ручная настройка",
+ "action": "/?set.manual",
+ "class": "btn btn-block btn-default"
+ },
+ {
+ "type": "link",
+ "title": "Инструкция к системе автоматизации",
+ "action": "https://github.com/IoTManagerProject/IoTManager/wiki",
+ "class": "btn btn-block btn-default"
+ },
+ {
+ "type": "link",
+ "title": "Очистить логи сенсоров",
+ "action": "/set?cleanlog",
+ "class": "btn btn-block btn-default"
+ },
+ {
+ "type": "hr"
+ },
+ {
+ "type": "h3",
+ "name": "my-block",
+ "style": "position:fixed;top:50%;left:50%;width:400px;margin-left:-200px;text-align:center;",
+ "class": "hidden"
+ },
+ {
+ "type": "button",
+ "title": "Обновить прошивку устройства",
+ "action": "/check",
+ "response": "[[my-block]]",
+ "class": "btn btn-block btn-default"
+ }
+ ]
}
\ No newline at end of file
diff --git a/data/set.manual.json b/data/set.manual.json
new file mode 100644
index 00000000..bd3b7ba0
--- /dev/null
+++ b/data/set.manual.json
@@ -0,0 +1,38 @@
+{
+ "configs": [
+ "/config.setup.json",
+ "/config.option.json",
+ "/config.live.json",
+ "/lang/lang.ru.json"
+ ],
+ "class": "col-sm-offset-1 col-sm-10",
+ "content": [
+ {
+ "type": "h5",
+ "title": "{{name}}",
+ "class": "alert-default"
+ },
+ {
+ "type": "link",
+ "title": "{{ButMainPage}}",
+ "action": "/",
+ "class": "btn btn-block btn-default"
+ },
+ {
+ "type": "file",
+ "state": "s.conf.csv",
+ "style": "width:100%;height:350px",
+ "title": "Сохранить",
+ "action": "/set?saveItems",
+ "class": "btn btn-block btn-default"
+ },
+ {
+ "type": "file",
+ "state": "s.scen.txt",
+ "style": "width:100%;height:350px",
+ "title": "Сохранить",
+ "action": "/set?sceninit",
+ "class": "btn btn-block btn-default"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/data/widgets/alarm.json b/data/widgets/alarm.json
new file mode 100644
index 00000000..e0e636c3
--- /dev/null
+++ b/data/widgets/alarm.json
@@ -0,0 +1,6 @@
+{
+ "widget": "anydata",
+ "icon": "body",
+ "color": "red",
+ "descrColor": "red"
+}
\ No newline at end of file
diff --git a/data/widgets/anydataHum.json b/data/widgets/anydataHum.json
new file mode 100644
index 00000000..ebc5b5af
--- /dev/null
+++ b/data/widgets/anydataHum.json
@@ -0,0 +1,5 @@
+{
+ "widget": "anydata",
+ "after": "%",
+ "icon": "water"
+}
\ No newline at end of file
diff --git a/data/widgets/anydataPress.json b/data/widgets/anydataPress.json
new file mode 100644
index 00000000..e67af2c8
--- /dev/null
+++ b/data/widgets/anydataPress.json
@@ -0,0 +1,5 @@
+{
+ "widget": "anydata",
+ "after": "mm",
+ "icon": "speedometer"
+}
\ No newline at end of file
diff --git a/data/widgets/anydataTemp.json b/data/widgets/anydataTemp.json
new file mode 100644
index 00000000..112da222
--- /dev/null
+++ b/data/widgets/anydataTemp.json
@@ -0,0 +1,5 @@
+{
+ "widget": "anydata",
+ "after": "°С",
+ "icon": "thermometer"
+}
\ No newline at end of file
diff --git a/data/widgets/toggleSunMoon.json b/data/widgets/toggleSunMoon.json
new file mode 100644
index 00000000..5501aa75
--- /dev/null
+++ b/data/widgets/toggleSunMoon.json
@@ -0,0 +1,5 @@
+{
+ "widget": "toggle",
+ "icon": "sunny",
+ "iconOff": "moon"
+}
\ No newline at end of file
diff --git a/doc/1.txt b/doc/1.txt
new file mode 100644
index 00000000..d08be432
--- /dev/null
+++ b/doc/1.txt
@@ -0,0 +1,566 @@
+***
+
+
+## Возможности
+
+ - Объединение различных по типу и назначению устройств: управление, получение данных, и настройка параметров - всё в одном приложении
+
+ - Взаимодействие с устройствами осуществляется через "облачный" сервис с использованием протокола mqtt, позволит контролировать их из любой точки Мира (при наличии доступа в Интернет)
+
+ - Поддержка нескольких профилей и их переключение "на лету", дает возможность объединить устройства в группы
+
+
+Настройка (после "прошивки") производится через веб-интерфейс, чтобы получить к нему доступ необходимо соединиться с WiFi AP устройства и набрать в адресной строке браузера http://192.168.4.1.
+Далее выбрать типовой шаблон автоматизации, произвести настройку под свои требования и задачи.
+Основные разделы интерфейса: конфигурация и сценарии.
+В окне конфигурации задаются "объекты", "элементы управления" устройства (dashboard) - им устройство будет представлено в приложении компаньоне проекта. В окне сценариев задаются реакции на события и изменения в параметрах работы системы.
+
+***
+
+
+## Команды, назначение и применение
+
+Команды служат для настройки и управления устройством и его взаимодействия
+
+**`buttonSet 1 1`** Изменит состояние "кнопки" №1, установит его в значение 1
+
+**`pinSet 13 0`** Установит GPIO 13 состояние 0
+
+**`pinChange 13`** Состояние GPIO 13 будет изменено на противоположное
+
+**`pwmSet 1 500`** Настройка pwm №1 будет использовано значение 500
+
+**`timeSet 1 08-00-00`** Установит для элемента ввода времени - inputTime значение 08:00:00
+
+**`digitSet 1 56`** Элемент №1 (для цифровых параметров) отобразит число 56
+
+**`stepperSet 1 100 1`** Шаговый двигатель №1 - вращение 100 "шагов" по часовой стрелке (для движения в обратную сторону используются отрицательные значения параметра)
+
+**`servoSet 1 180`** Сервопривод №1 принять положение 180°
+
+**`timerStart 1 60 sec`** Установить для таймера №1 обратный отсчёт в 60 секунд
+
+**`timerStop 1`** Остановить таймер №1
+
+**`textSet 1 Привет`** Установить для элемента текстовое поле №1 - "привет"
+
+**`push Внимание Протечка`** Отправить push-уведомление с темой "внимание" и содержанием "протечка"
+
+**`firmwareUpdate`** Обновить прошивку устройства "по воздуху"
+
+**`firmwareVersion Версия прошивки Системные 1`** Узнать версию прошивки устройстве
+
+## Сценарии
+
+Элементарный блок в сценарии состоит из набора команд и триггера - условия для их выполнения
+
+**temp > 60**
+digitSet 1 60
+stepperSet 1 100 1
+textSet 1 Перегрев
+**end**
+
+Условие: когда температура превысит 60°
+Запустит: команда шаговому двигателю, в приложение отправить сообщение и цифровое значение температуры.
+
+В сценарии может быть несколько блоков, при необходимости из приложения есть возможность "выключать" часть из них.
+Неактивные блоки сценария будут проигнорированы.
+
+Для взаимодействия устройств между собой предусмотрены команды mqtt и http
+
+**temp > 60**
+mqtt 154348-134 digitSet_1_56
+mqtt 154348-136 stepperSet _1_100_1
+http 192.168.1.10 textSet_1_Перегрев
+**end**
+
+***
+
+## 1.1 Объект "кнопка"
+
+(эти строки мы пишем в "конфигурации устройства")
+
+### a) кнопка управляющая выходом (пином). Пины нумеруются по системе нумирации gpio для esp контроллеров.
+
+`button 1 13 кухня освещение 0 1`
+
+**"button"** это объект создающий кнопку в приложении
+**"1"** это номер этой кнопки (необходимый для ее аутентификации)
+**"13"** это номер пина которым будет управлять данная кнопка
+**"кухня"** это название кнопки в приложении
+**"освещение"** это название вкладки в приложении на которой появится данная кнопка
+**"0"** это начальное состояние кнопки при старте модуля (выкд 0, вкл 1)
+**"1"** это уникальный номер и номер сортировки данной кнопки. Этот номер должен быть уникален для каждого объекта
+
+
+### б) виртуальная кнопка - кнопка реакцию на которую можно задать в сценариях:
+
+`button 1 na запустить таймеры 0 1`
+
+**"button"** это объект создающий кнопку в приложении
+**"1"** это номер этой кнопки (необходимый для ее аутентификации)
+**"na"** абривиатура not available означающая что эта кнопка виртуальная и что пин не установлен
+**"запустить"** это название кнопки в приложении
+**"таймеры"** это название вкладки в приложении на которой появится данная кнопка
+**"0"** это начальное состояние кнопки при старте модуля (выкд 0, вкл 1)
+**"1"** это уникальный номер и номер сортировки данной кнопки. Этот номер должен быть уникален для каждого объекта
+
+### в) кнопка включающая и выключающая все сценарии:
+
+`button 1 scenario запустить таймеры 0 1`
+
+**"button"** это объект создающий кнопку в приложении
+**"1"** это номер этой кнопки (необходимый для ее аутентификации)
+**"scenario"** слово означающее что эта кнопка для управления сценариями
+**"запустить"** это название кнопки в приложении
+**"таймеры"** это название вкладки в приложении на которой появится данная кнопка
+**"0"** это начальное состояние кнопки при старте модуля (выкд 0, вкл 1)
+**"1"** это уникальный номер и номер сортировки данной кнопки. Этот номер должен быть уникален для каждого объекта
+
+
+### г) кнопка включающая выключающая определенные блоки сценариев:
+
+`button 1 line1,line3, Включить#отправку#push Оповещение 0 1`
+
+**"button"** это объект создающий кнопку в приложении
+**"1"** это номер этой кнопки (необходимый для ее аутентификации)
+**"line1,line3,"** это блоки сценариев нумирация сверху вниз. Блоком считается выражение от начала до слова end
+**"Включить#отправку#push"** это название кнопки в приложении
+**"Оповещение"** это название вкладки в приложении на которой появится данная кнопка
+**"0"** это начальное состояние кнопки при старте модуля (выкд 0, вкл 1)
+**"1"** это уникальный номер и номер сортировки данной кнопки. Этот номер должен быть уникален для каждого объекта
+
+## 1.2 Команды управления объектом "кнопка"
+
+(эти строки мы пишем в "сценариях")
+
+ ### а) Команда включения выключения кнопки по ее номеру
+
+`buttonSet 1 1`
+
+**"buttonSet"** команда управления объектом button
+**"1"** номер кнопки которой будем управлять
+**"1"** состояние включено, 0 - выключено
+
+### б) Команда изменения состояния кнопки на противоположное
+
+`buttonChange 1`
+
+**"buttonChange"** команда управления объектом button
+**"1"** номер кнопки которой будем управлять
+
+## 1.3 Вызов событий объектом "кнопока"
+
+(эти строки мы пишем в "сценариях")
+
+объект button может быть равен либо 0 либо 1
+
+`button1 = 1`
+`button2 = 0`
+
+Пример использования:
+
+`button1 = 1`
+`buttonSet 2 1`
+`buttonSet 3 0`
+`end`
+
+
+***
+
+## 2.1 Объект "физическая кнопка"
+
+`switch 1 0 10`
+
+**switch** это объект создающий физическую кнопку
+**1** номер кнопки
+**0** пин кнопки (при подключении необходим подтягивающий резистор)
+**10** задержка для избавления от дребезга с мили секундах
+
+## 2.2 Вызов событий объектом "физическая кнопка"
+
+`switch1` может быть равна нулю или единицы, ноль - событие отбрасывания кнопки, единица - событие нажатия
+
+`switch1 = 1`
+`buttonChange 1`
+`end`
+
+
+***
+
+## 3.1 Объект "широтноимпульсная модуляция"
+
+`pwm 1 12 яркость освещение 1023 1`
+
+**"pwm"** это объект создающий управление шим в приложении в виде ползунка
+**"1"** это номер этого объекта
+**"12"** это номер пина на котором будет генерироваться шим заданной в приложении величены
+**"Яркость"** это название кнопки в приложении
+**"Оповещение"** это название вкладки в приложении на которой появится данная кнопка
+**"1023"** это начальное значение шим сигнала и ползунка (изменяется от 0 до 1023)
+**"1"** это уникальный номер и номер сортировки данной кнопки. Этот номер должен быть уникален для каждого объекта
+
+## 3.2 Команда управления объектом "широтноимпульсная модуляция"
+
+`pwmSet 1 500`
+
+**"pwmSet"** команда управления объектом
+**"1"** номер объекта, которым будем управлять
+**"500"** значение которое установится после выполнения команды (от 0 до 1023)
+
+***
+
+## 4.1 Объект "окно ввода времени"
+
+`inputTime time1 Во#сколько#включить? Таймеры 20-30-00 1`
+
+**inputTime** это объект создающий окно ввода в приложении
+**time1** переменная в которую будет записано время введенное в окно
+**Во#сколько#включить?** это название окна в приложении
+**Таймеры** это название вкладки в приложении
+**20-30-00** начальное значение времени после загрузки устройства
+**1** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта
+
+## 4.2 Управление объектом "окно ввода времени"
+
+`timeSet 1 08-00-00`
+
+**"timeSet"** команда управления объектом
+**"1"** номер объекта, которым будем управлять в данном случае окном ввода с `time1`
+**"08-00-00"** время которое хотим установить
+
+В окно ввода можно вводить время в приложении но если необходимо изменить время автоматически
+по какому нибудь событию то можно использовать команду выше - **timeSet**.
+
+## 4.3 Вызов событий объектом "окно ввода времени"
+
+`timenow = time1`
+`buttonSet 1 1`
+`end`
+
+`timenow` всегда хранит в себе текущее время, и поэтому исходя из данного сценария кнопка номер 1 включится в то время которое будет введено в окно ввода `time1`
+
+***
+
+## 5.1 Объект "окно ввода цифры"
+
+`inputDigit digit1 Через#сколько#секунд#выключить? Таймеры 5 2`
+
+**inputDigit** это объект создающий окно ввода в приложении
+**digit1** переменная в которую будет записана цифра, введенная в окно
+**Через#сколько#секунд#выключить?** это название окна в приложении
+**Таймеры** это название вкладки в приложении
+**5** цифра по умолчанию, после загрузки модуля
+**2** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта
+
+## 5.2 Управление объектом "окно ввода цифры":
+
+`digitSet 1 56`
+
+**"digitSet"** команда управления объектом
+**"1"** номер объекта, которым будем управлять в данном случае окном ввода с `digit1`
+**"56"** цифра которую хотим установить
+
+В окно ввода можно вводить цифры в приложении, но если необходимо изменить цифру автоматически
+по какому нибудь событию, то можно использовать команду выше - **digitSet**.
+
+## 5.3 Вызов событий объектом "окно ввода цифры"
+
+`dallas > digit1`
+`buttonSet 1 0`
+`end`
+
+`button1 = 1`
+`timerStart 1 digit1 sec`
+`end`
+
+***
+
+## 6.1 Объект "dallas" (сенсор температуры ds18b20)
+
+`dallas temp1 2 123456 Водонагреватель,#t°C Термостат any-data 1`
+
+**dallas** это объект чтения датчика температуры
+**2** пин датчика температуры
+**Водонагреватель,#t°C** это название виджета в приложении
+**Датчики** название вкладки в приложении
+**any-data** или **progress-round** или **progress-line** три разных варианта виджета отображения
+**1** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта
+
+## 6.2 Вызов событий объектом "dallas"
+
+В сценариях dallas можно сравнивать с переменной окна ввода `digit1` (>,<,>=,<=,=):
+
+`dallas > digit1`
+`buttonSet 1 0`
+`end`
+
+Или можно сравнивать с постоянной цифрой (>,<,>=,<=,=):
+
+`dallas > 60`
+`buttonSet 1 0`
+`end`
+
+
+***
+
+## 7.1 Объект "analog" (аналоговый вход контроллера)
+
+`analog adc 0 Аналоговый#вход,#% Датчики progress-round 310 620 1 100 1`
+
+**analog** это объект чтения аналогового входа
+**adc** это переменная
+**0** пин аналогового входа (для esp8266 всегда 0, для esp32 пока что не доделал читаться будет всегда пин 34)
+**Аналоговый#вход,#%** это название виджета в приложении
+**Датчики** название вкладки в приложении
+**any-data** или **progress-round** или **progress-line** три разных варианта виджета отображения
+**310** начальная величина читаемого диапазона
+**620** конечная величина читаемого диапазона
+**1** начальная величина выводимого диапазона
+**100** конечная величина выводимого диапазона
+**1** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта
+
+## 7.2 Вызов событий объектом "analog"
+
+В сценариях analog можно сравнивать с переменной окна ввода `digit1` (>,<,>=,<=,=):
+
+`analog > digit1`
+`buttonSet 1 0`
+`end`
+
+Или можно сравнивать с постоянной цифрой (>,<,>=,<=,=):
+
+`analog > 50`
+`buttonSet 1 0`
+`end`
+
+
+***
+
+## 8.1 Объект "level" (ультразвуковой дальномер JSN-SR04T, HC-SR04, HY-SRF05)
+
+`level Вода#в#баке,#% Датчики any-data 125 20 1`
+
+**level** это объект чтения датчика расстояния
+**Вода#в#баке** это название виджета в приложении
+**Датчики** название вкладки в приложении
+**any-data** или **progress-round** или **progress-line** три разных варианта отображения виджета
+**125** расстояние от датчика до дна бака в сантиметрах
+**20** расстояние от датчика до поверхности воды, когда бак полный, в сантиметрах
+**1** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта
+
+Подключать дальномер нужно:
+
+| | trig | echo |
+| :-: | :-: | :-: |
+| wemos | D5 | D6 |
+| esp | 14 | 12 |
+
+## 8.2 Вызов событий объектом "level"
+
+В сценариях level можно сравнивать с переменной окна ввода `digit1` (>,<,>=,<=,=):
+
+`level > digit1`
+`buttonSet 1 0`
+`end`
+
+Или можно сравнивать с постоянной цифрой (>,<,>=,<=,=):
+
+`level > 95`
+`buttonSet 1 0`
+`end`
+
+
+
+***
+
+## 9.1 Объект "dht" (Сенсоры DHT11, DHT22, DHT33, DHT44, AM2302, RHT03)
+
+dhtT DHT11 2 Температура#DHT,#t°C Датчики any-data 1
+dhtH DHT11 2 Влажность#DHT,#% Датчики any-data 2
+dhtComfort Степень#комфорта: Датчики 3
+dhtPerception Восприятие: Датчики 4
+dhtDewpoint Точка#росы: Датчики 5
+
+**dhtT** или **dhtH** температура или влажность
+**DHT11** или **DHT22** чтение DHT11 или DHT22, DHT33, DHT44, AM2302, RHT03 соответственно
+**2** пин датчика
+**Температура#DHT,#t°C** это название виджета в приложении
+**Датчики** название вкладки в приложении
+**any-data** или **progress-round** или **progress-line** три разных варианта отображения виджета
+**1** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта
+
+## 9.2 Вызов событий объектом "dhtT" или "dhtH"
+
+В сценариях "dhtT" или "dhtH" можно сравнивать с переменной окна ввода `digit1` (>,<,>=,<=,=):
+
+`dhtT > digit1`
+`buttonSet 1 0`
+`end`
+
+`dhtH > digit1`
+`buttonSet 1 0`
+`end`
+
+Или можно сравнивать с постоянной цифрой (>,<,>=,<=,=):
+
+`dhtT > 50`
+`buttonSet 1 0`
+`end`
+
+`dhtH < 40`
+`buttonSet 1 0`
+`end`
+
+
+***
+
+## 10.1 Объект "stepper" (Драйвер шагового двигателя A4988)
+
+stepper 1 12 4
+stepper 2 13 5
+
+**stepper** объект создающий шаговый двигатель
+**1** номер шаговика
+**12** номер пина количества шагов
+**4** номер пина направления
+
+## 10.2 управление объектом "stepper"
+
+`stepperSet 1 200 1`
+
+**stepperSet** команда управления шаговым двигателем
+**1** номер шагового двигателя (их может быть не более двух)
+**200** количество шагов (обратное направление отрицательное значение параметра)
+**1** интервал между шагами (мс)
+
+`button1 = 1`
+`stepperSet 1 200 1`
+`end`
+`button1 = 0`
+`stepperSet 1 -200 1`
+`end`
+
+***
+
+## 11.1 Объект "обратный таймер"
+
+Прежде чем читать этот раздел запустите пресет №3 на устройстве.
+Нажав на кнопку "Выберите во что вы хотите превратить esp"
+
+Можно использовать цифры из окон ввода:
+
+`timerStart 1 digit1 sec`
+
+Можно писать цифры прям в объект:
+
+`timerStart 1 10 sec`
+
+Можно установить часы минуты или секунды:
+
+`timerStart 1 10 sec`
+`timerStart 1 10 min`
+`timerStart 1 10 hours`
+
+Используем это объект в сценариях вот так:
+
+`button1 = 1`
+`timerStart 1 digit1 sec`
+`end`
+
+Смысл в том что при нажатии на кнопку один запуститься обратный отчет, на величину digit1 секунд. Если напишем например:
+
+`dallas < 60`
+`timerStart 1 digit1 sec`
+`end`
+
+то такой же отчет запустится когда значение температуры вырастит больше 60 градусов. Таким образом обратный отчет можно запустить реакцией на любое событие. Итак теперь обратный отчет запущен, обратный таймер уменьшается, и нам надо назначить действие на тот момент когда он обнулится. Для этого я придумал выражение: `timer1 = 0`
+
+Используем его и в общем получаем вот такой сценарий:
+
+`button1 = 1`
+`timerStart 1 digit1 sec`
+`end`
+`timer1 = 0`
+`buttonSet 1 0`
+`end`
+
+Когда таймер закончит отсчёт, кнопка станет "неактивной". Используйте преет №3, как пример подобного сценария
+Например:
+
+`dallas < 60`
+`buttonSet 1 0`
+`buttonSet 2 0`
+`pwmSet 1 1023`
+`mqtt 2653450020 buttonChange_1`
+`mqtt 2653450020 pinSet_13_1`
+`http 192.168.1.32 pinSet_14_1`
+`end`
+
+Вот что может произойти на разных устройствах по одному событию повышения температуры...
+
+
+***
+
+## 12 Журнал (лог) данных
+
+
+`logging analog 1 100 slow Аналоговый#вход Датчики 7`
+
+**logging** объект для логирования
+**analog** или **dhtT** или **dhtH** какой сенсор будем логировать, можно указать любой
+**1** период между точками в минутах
+**100** количество точек (старые точки будут удаляться по мере добавления новых)
+**slow** или **fast** метод выгрузки графика в приложение, slow - выгружает график по одной точке (меньше расходуется оперативка, лучше использовать для esp8266), fast - выгрузка графика сразу (больше расход оперативки, подходит для esp32)
+**Аналоговый#вход** название графика в приложении
+**Датчики** название вкладки в приложении
+**7** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта
+
+***
+
+## 13 Взаимодействие устройств между собой
+
+Устройства могут между собой обмениваться командами. Команды можно отправлять по http или по mqtt.
+По событию на одном устройстве можно вызвать действие на другом. Например на esp01 стоит датчик температуры, реле стоит на esp02.
+
+Настройки esp01:
+
+`dhtT temp 2 dht11 Температура#DHT,#t°C Датчики any-data 1`
+
+`temp < 40`
+`http 192.168.10.25 buttonSet_1_1`
+`end`
+
+Настройки esp02:
+
+`button 1 13 Включить#реле Реле 0 1`
+
+И теперь когда температура датчика на esp01 станет меньше 40 градусов то на esp02 будет отправлена команда на включение кнопки: buttonSet_1_1
+
+Если вы хотите отправить команду через mqtt то сценарий будет выглядеть следующим образом:
+
+`temp < 40`
+`mqtt 12343442-12413131 buttonSet_1_1`
+`end`
+
+где `12343442-12413131` id esp02 той на которую отправляем команду. Id можно взять в веб интерфейсе на странице конфигурация устройства. Или в списке устройств в сети.
+
+Теперь рассмотрим вариант внешнего управления esp с помощью get запросов.
+
+`http://192.168.88.239/cmd?command=buttonSet%201%201`
+
+Разберем эту строку. Сама команда в ней выглядит вот так: buttonSet%201%201. `%20` заменяют пробел.
+
+То есть что бы составить get запрос на изменение например pwm нужно:
+
+Взять команду `pwmSet 1 500`
+Заменить в ней пробелы на `%20` получится так: `pwmSet%201%20500`
+И добавить ее в конец строки `http://192.168.88.239/cmd?command=` где указывается ip адрес устройства
+
+В итоге получится http://192.168.88.239/cmd?command=pwmSet%201%20500
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/2.txt b/doc/2.txt
new file mode 100644
index 00000000..529f22bb
--- /dev/null
+++ b/doc/2.txt
@@ -0,0 +1,85 @@
+# В этой инструкции будет описано как с esp отправлять email и push
+
+# Часть 1. Привязать email и pushbullet к сайту pushingbox
+
+### 1. Необходимо перейти на сайт: [pushingbox](https://www.pushingbox.com/)
+### 2. Войти с помощью google
+
+### 3. Перейти в мои сервисы и добавить новый сервис
+
+### 4. Нас интересуют два сервиса email и pushbullet
+
+### 5. Выбираем сначало сервис для отправки email. В окно `Name of your email configuration` - вводим слово "email". В окно `Email address` - вводим ваш email адрес. жмем submit
+
+manager_modules_firmware/blob/master/push_instruction/Screenshot_6.png)
+### 6.1 Привязываем pushbullet. Переходим на сайт [pushbullet.com](https://www.pushbullet.com/)
+### 6.2 Входим с гуглом или фейсбуком
+### 6.3 Идем в настройки
+
+### 6.4 Создаем токен
+
+### 6.5 Идем опять в сервисы и теперь выбираем сервис pushbullet [pushingbox.com/services](https://www.pushingbox.com/services.php) нажимаем add service
+### Берем токен, и вставляем его в окно Access token.
+### Окно Device token (optional) оставляем пустым.
+### В окно Name of your Pushbullet configuration пишем слово "push".
+
+
+### 7. Теперь наш email и pushbullet привязаны к pushingbox. Далее можно скачать приложение pushbullet на телефон и войти с гуглом или фейсбуком сответственно с пунктом 6.3 этой инструкции
+
+
+# Часть 2. Создание сценариев отправки email
+
+### 8.1. Сценарий для отправки email. Заходим в My Scenarios:
+
+
+### 8.2 Пишем слово email (это имя сценария отправки email) жмем add:
+
+### 8.3 Нажимаем add an action
+
+### 8.4 Выбираем наш email который мы зарегестрировали ранее и нажимаем Add an action with this service
+
+### 8.5 Делаем все как на скриншоте и жмем submit
+
+### 8.6 Возвращаемся на мои сценарии
+
+### 8.7 Вставляем токен в веб интерфейс esp
+
+
+# Часть 3. Создание сценариев отправки push
+
+### 9.1. Сценарий для отправки push. Заходим в My Scenarios:
+
+
+### 9.2 Пишем слово push (это имя сценария отправки email) жмем add:
+
+### 9.3 Нажимаем add an action
+
+### 9.4 Выбираем наш pushbullet который мы зарегестрировали ранее и нажимаем Add an action with this service
+
+### 9.5 Делаем все как на скриншоте и жмем submit
+
+### 9.6 Возвращаемся на мои сценарии
+
+### 9.7 Вставляем токен в веб интерфейс esp
+
+
+# Часть 4. Итог
+
+При создании такой конфигурации как на картинке:
+
+`button 1 na Отправить#push Push 0 1`
+
+
+`button1 = 1`
+`push внимание кнопка#нажата`
+`end`
+
+
+
+Если мы введем токен для email то будут приходить email
+
+
+Если для push то будут приходить push в pushbullet
+
+
+Способ описанный в данной инструкции более сложный в настройке но зато очень надежный.
\ No newline at end of file
diff --git a/doc/3.txt b/doc/3.txt
new file mode 100644
index 00000000..31226847
--- /dev/null
+++ b/doc/3.txt
@@ -0,0 +1,32 @@
+***
+
+
+### 1. Скачать архив из [релизов](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/releases) или из закрепленного сообщения группы телеграм с последней версией прошивки
+
+***
+
+
+
+### 2. Для ESP8266 c 4 и больше мб памяти (все сделать как на скриншотах)
+
+
+
+
+
+***
+
+
+### 2. Для ESP8266 c 1 мб памяти (все сделать как на скриншотах)
+
+
+
+
+
+***
+
+
+### 2. Для ESP32 (все сделать как на скриншотах)
+
+
+
+
\ No newline at end of file
diff --git a/data/conf/c001.txt b/doc/conf/c001.txt
similarity index 100%
rename from data/conf/c001.txt
rename to doc/conf/c001.txt
diff --git a/data/conf/c002.txt b/doc/conf/c002.txt
similarity index 100%
rename from data/conf/c002.txt
rename to doc/conf/c002.txt
diff --git a/data/conf/c003.txt b/doc/conf/c003.txt
similarity index 100%
rename from data/conf/c003.txt
rename to doc/conf/c003.txt
diff --git a/data/conf/c004.txt b/doc/conf/c004.txt
similarity index 100%
rename from data/conf/c004.txt
rename to doc/conf/c004.txt
diff --git a/data/conf/c005.txt b/doc/conf/c005.txt
similarity index 100%
rename from data/conf/c005.txt
rename to doc/conf/c005.txt
diff --git a/data/conf/c006.txt b/doc/conf/c006.txt
similarity index 100%
rename from data/conf/c006.txt
rename to doc/conf/c006.txt
diff --git a/data/conf/c007.txt b/doc/conf/c007.txt
similarity index 100%
rename from data/conf/c007.txt
rename to doc/conf/c007.txt
diff --git a/data/conf/c008.txt b/doc/conf/c008.txt
similarity index 100%
rename from data/conf/c008.txt
rename to doc/conf/c008.txt
diff --git a/data/conf/c009.txt b/doc/conf/c009.txt
similarity index 100%
rename from data/conf/c009.txt
rename to doc/conf/c009.txt
diff --git a/data/conf/c010.txt b/doc/conf/c010.txt
similarity index 100%
rename from data/conf/c010.txt
rename to doc/conf/c010.txt
diff --git a/data/conf/c011.txt b/doc/conf/c011.txt
similarity index 100%
rename from data/conf/c011.txt
rename to doc/conf/c011.txt
diff --git a/data/conf/c012.txt b/doc/conf/c012.txt
similarity index 100%
rename from data/conf/c012.txt
rename to doc/conf/c012.txt
diff --git a/data/conf/c013.txt b/doc/conf/c013.txt
similarity index 100%
rename from data/conf/c013.txt
rename to doc/conf/c013.txt
diff --git a/data/conf/c014.txt b/doc/conf/c014.txt
similarity index 100%
rename from data/conf/c014.txt
rename to doc/conf/c014.txt
diff --git a/data/conf/c015.txt b/doc/conf/c015.txt
similarity index 100%
rename from data/conf/c015.txt
rename to doc/conf/c015.txt
diff --git a/data/conf/c016.txt b/doc/conf/c016.txt
similarity index 100%
rename from data/conf/c016.txt
rename to doc/conf/c016.txt
diff --git a/data/conf/c017.txt b/doc/conf/c017.txt
similarity index 100%
rename from data/conf/c017.txt
rename to doc/conf/c017.txt
diff --git a/data/conf/c018.txt b/doc/conf/c018.txt
similarity index 100%
rename from data/conf/c018.txt
rename to doc/conf/c018.txt
diff --git a/data/conf/c019.txt b/doc/conf/c019.txt
similarity index 100%
rename from data/conf/c019.txt
rename to doc/conf/c019.txt
diff --git a/data/conf/c020.txt b/doc/conf/c020.txt
similarity index 100%
rename from data/conf/c020.txt
rename to doc/conf/c020.txt
diff --git a/data/conf/c021.txt b/doc/conf/c021.txt
similarity index 100%
rename from data/conf/c021.txt
rename to doc/conf/c021.txt
diff --git a/data/conf/c100.txt b/doc/conf/c100.txt
similarity index 100%
rename from data/conf/c100.txt
rename to doc/conf/c100.txt
diff --git a/data/conf/s001.txt b/doc/conf/s001.txt
similarity index 100%
rename from data/conf/s001.txt
rename to doc/conf/s001.txt
diff --git a/data/conf/s002.txt b/doc/conf/s002.txt
similarity index 100%
rename from data/conf/s002.txt
rename to doc/conf/s002.txt
diff --git a/data/conf/s003.txt b/doc/conf/s003.txt
similarity index 100%
rename from data/conf/s003.txt
rename to doc/conf/s003.txt
diff --git a/data/conf/s004.txt b/doc/conf/s004.txt
similarity index 100%
rename from data/conf/s004.txt
rename to doc/conf/s004.txt
diff --git a/data/conf/s005.txt b/doc/conf/s005.txt
similarity index 100%
rename from data/conf/s005.txt
rename to doc/conf/s005.txt
diff --git a/data/conf/s006.txt b/doc/conf/s006.txt
similarity index 100%
rename from data/conf/s006.txt
rename to doc/conf/s006.txt
diff --git a/data/conf/s007.txt b/doc/conf/s007.txt
similarity index 100%
rename from data/conf/s007.txt
rename to doc/conf/s007.txt
diff --git a/data/conf/s008.txt b/doc/conf/s008.txt
similarity index 100%
rename from data/conf/s008.txt
rename to doc/conf/s008.txt
diff --git a/data/conf/s009.txt b/doc/conf/s009.txt
similarity index 100%
rename from data/conf/s009.txt
rename to doc/conf/s009.txt
diff --git a/data/conf/s010.txt b/doc/conf/s010.txt
similarity index 100%
rename from data/conf/s010.txt
rename to doc/conf/s010.txt
diff --git a/data/conf/s011.txt b/doc/conf/s011.txt
similarity index 100%
rename from data/conf/s011.txt
rename to doc/conf/s011.txt
diff --git a/data/conf/s012.txt b/doc/conf/s012.txt
similarity index 100%
rename from data/conf/s012.txt
rename to doc/conf/s012.txt
diff --git a/data/conf/s013.txt b/doc/conf/s013.txt
similarity index 100%
rename from data/conf/s013.txt
rename to doc/conf/s013.txt
diff --git a/data/conf/s014.txt b/doc/conf/s014.txt
similarity index 100%
rename from data/conf/s014.txt
rename to doc/conf/s014.txt
diff --git a/data/conf/s015.txt b/doc/conf/s015.txt
similarity index 100%
rename from data/conf/s015.txt
rename to doc/conf/s015.txt
diff --git a/data/conf/s016.txt b/doc/conf/s016.txt
similarity index 100%
rename from data/conf/s016.txt
rename to doc/conf/s016.txt
diff --git a/data/conf/s017.txt b/doc/conf/s017.txt
similarity index 100%
rename from data/conf/s017.txt
rename to doc/conf/s017.txt
diff --git a/data/conf/s018.txt b/doc/conf/s018.txt
similarity index 100%
rename from data/conf/s018.txt
rename to doc/conf/s018.txt
diff --git a/data/conf/s019.txt b/doc/conf/s019.txt
similarity index 100%
rename from data/conf/s019.txt
rename to doc/conf/s019.txt
diff --git a/data/conf/s020.txt b/doc/conf/s020.txt
similarity index 100%
rename from data/conf/s020.txt
rename to doc/conf/s020.txt
diff --git a/data/conf/s021.txt b/doc/conf/s021.txt
similarity index 100%
rename from data/conf/s021.txt
rename to doc/conf/s021.txt
diff --git a/data/conf/s100.txt b/doc/conf/s100.txt
similarity index 100%
rename from data/conf/s100.txt
rename to doc/conf/s100.txt
diff --git a/doc/orders.xlsm b/doc/orders.xlsm
new file mode 100644
index 00000000..d86f040e
Binary files /dev/null and b/doc/orders.xlsm differ
diff --git a/doc/pictures/001 iot manager.jpeg b/doc/pictures/001 iot manager.jpeg
new file mode 100644
index 00000000..39914774
Binary files /dev/null and b/doc/pictures/001 iot manager.jpeg differ
diff --git a/doc/pictures/002 iot manager.jpeg b/doc/pictures/002 iot manager.jpeg
new file mode 100644
index 00000000..80b9d67c
Binary files /dev/null and b/doc/pictures/002 iot manager.jpeg differ
diff --git a/doc/pictures/003 iot manager.jpeg b/doc/pictures/003 iot manager.jpeg
new file mode 100644
index 00000000..3f23d111
Binary files /dev/null and b/doc/pictures/003 iot manager.jpeg differ
diff --git a/doc/pictures/007 iot manager.jpg b/doc/pictures/007 iot manager.jpg
new file mode 100644
index 00000000..2178d634
Binary files /dev/null and b/doc/pictures/007 iot manager.jpg differ
diff --git a/doc/pictures/pic1.png b/doc/pictures/pic1.png
deleted file mode 100644
index 4cbed577..00000000
Binary files a/doc/pictures/pic1.png and /dev/null differ
diff --git a/include/BufferExecute.h b/include/BufferExecute.h
new file mode 100644
index 00000000..85252a36
--- /dev/null
+++ b/include/BufferExecute.h
@@ -0,0 +1,8 @@
+#pragma once
+#include
+
+extern void loopCmdAdd(const String &cmdStr);
+extern void fileCmdExecute(const String &filename);
+extern void csvCmdExecute(String &cmdStr);
+extern void spaceCmdExecute(String &cmdStr);
+extern void loopCmdExecute();
\ No newline at end of file
diff --git a/include/Bus.h b/include/Bus.h
new file mode 100644
index 00000000..11edd50b
--- /dev/null
+++ b/include/Bus.h
@@ -0,0 +1,4 @@
+#pragma once
+#include
+void busInit();
+String i2c_scan();
\ No newline at end of file
diff --git a/include/Bus/BusScanner.h b/include/Bus/BusScanner.h
deleted file mode 100644
index 659aa501..00000000
--- a/include/Bus/BusScanner.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#pragma once
-
-#include
-
-class BusScanner {
- public:
- BusScanner(const char* tag, String& out, size_t tries) : _found{0},
- _tries{tries},
- _out{&out} {
- _tag = new char(strlen(tag) + 1);
- strcpy(_tag, tag);
- }
-
- void scan() {
- init();
- bool res;
- do {
- res = syncScan();
- } while (!res && --_tries);
-
- if (!_found) {
- addResult("не найдено");
- }
- }
-
- const char* tag() {
- return _tag;
- }
-
- protected:
- virtual void init(){};
-
- virtual boolean syncScan() = 0;
-
- protected:
- void addResult(const String& str) {
- _out->concat(str);
- }
-
- void addResult(uint8_t addr, boolean last = true) {
- _found++;
- String str = "0x";
- if (addr < 16) {
- str += "0";
- }
- str += String(addr, HEX);
- str += !last ? ", " : ", ";
- addResult(str);
- };
-
- private:
- char* _tag;
- size_t _found;
- size_t _tries;
- String* _out;
-};
diff --git a/include/Bus/BusScannerFactory.h b/include/Bus/BusScannerFactory.h
deleted file mode 100644
index 867cf860..00000000
--- a/include/Bus/BusScannerFactory.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#pragma once
-
-#include "Bus/BusScanner.h"
-#include "Bus/I2CScanner.h"
-#include "Consts.h"
-#include "Utils/JsonUtils.h"
-
-class BusScannerFactory {
- public:
- static BusScanner* get(String& config, BusScanner_t type, String& str) {
- switch (type) {
- case BS_I2C:
- return new I2CScanner(str);
- default:
- return nullptr;
- }
- }
-};
diff --git a/include/Bus/I2CScanner.h b/include/Bus/I2CScanner.h
deleted file mode 100644
index 9678d089..00000000
--- a/include/Bus/I2CScanner.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#pragma once
-
-#include "Bus/BusScanner.h"
-
-class I2CScanner : public BusScanner {
- public:
- I2CScanner(String& out);
-
- protected:
- virtual void init() override;
- virtual boolean syncScan() override;
-};
\ No newline at end of file
diff --git a/include/Class/CallBackTest.h b/include/Class/CallBackTest.h
new file mode 100644
index 00000000..6632bfe0
--- /dev/null
+++ b/include/Class/CallBackTest.h
@@ -0,0 +1,26 @@
+#pragma once
+#include
+#include
+#include
+
+// Декларируем тип - сигнатуру метода , который мы готовы принять в данном случае это
+// должен быть метод без результата и без параметров.
+// Новый тип мы называем AsynсActionCb - хотя можешь назвать вообще как нравиться а что значит callBack
+
+typedef std::function AsyncActionCb; //метод без результата и параметров
+typedef std::function AsyncParamActionCb; //метод без результата и параметров
+
+class CallBackTest {
+ private:
+ long count;
+ AsyncActionCb _cb;
+ AsyncParamActionCb _pcb;
+
+
+ public:
+ CallBackTest();
+ void loop();
+ void setCallback(AsyncActionCb cb);
+ void setCallback(AsyncParamActionCb pcb);
+};
+//extern CallBackTest* CB;
\ No newline at end of file
diff --git a/include/Class/LineParsing.h b/include/Class/LineParsing.h
index 884510b9..f6e3d858 100644
--- a/include/Class/LineParsing.h
+++ b/include/Class/LineParsing.h
@@ -3,6 +3,7 @@
#include
#include "Global.h"
+#include "Utils/JsonUtils.h"
class LineParsing {
protected:
@@ -13,12 +14,14 @@ class LineParsing {
String _order;
String _addr;
+ String _reg;
String _pin;
String _map;
String _c;
String _inv;
String _state;
String _db;
+ String _type;
public:
LineParsing() :
@@ -29,18 +32,20 @@ class LineParsing {
_descr{""},
_order{""},
_addr{""},
+ _reg{""},
_pin{""},
_map{""},
_c{""},
_inv{""},
_state{""},
- _db{""}
+ _db{""},
+ _type{""}
{};
void update() {
//String order = sCmd.order();
- //pm.info("create '" + order + "'");
+ //SerialPrint("I","module","create '" + order + "'");
for (int i = 1; i < 12; i++) {
if (i == 1) _key = sCmd.next();
if (i == 2) _file = sCmd.next();
@@ -49,7 +54,7 @@ class LineParsing {
if (i == 5) _order = sCmd.next();
}
- for (int i = 1; i < 6; i++) {
+ for (int i = 1; i < 10; i++) {
String arg = sCmd.next();
if (arg != "") {
if (arg.indexOf("pin[") != -1) {
@@ -64,15 +69,33 @@ class LineParsing {
if (arg.indexOf("db[") != -1) {
_db = extractInner(arg);
}
+ if (arg.indexOf("map[") != -1) {
+ _map = extractInner(arg);
+ }
+ if (arg.indexOf("c[") != -1) {
+ _c = extractInner(arg);
+ }
+ if (arg.indexOf("type[") != -1) {
+ _type = extractInner(arg);
+ }
+ if (arg.indexOf("addr[") != -1) {
+ _addr = extractInner(arg);
+ }
+ if (arg.indexOf("reg[") != -1) {
+ _reg = extractInner(arg);
+ }
}
}
+
_page.replace("#", " ");
+
_descr.replace("#", " ");
- _page.replace(".", " ");
- _descr.replace(".", " ");
+
createWidgetClass(_descr, _page, _order, _file, _key);
}
+ //jsonWriteStr(configOptionJson, _key + "_pin", _pin);
+
String gkey() {
return _key;
}
@@ -89,14 +112,29 @@ class LineParsing {
return _order;
}
String gpin() {
- return _pin;
+ return _pin; //
}
String ginv() {
- return _inv;
+ return _inv; //
}
String gstate() {
return _state;
}
+ String gmap() {
+ return _map;
+ }
+ String gc() {
+ return _c;
+ }
+ String gtype() {
+ return _type;
+ }
+ String gaddr() {
+ return _addr;
+ }
+ String gregaddr() {
+ return _reg;
+ }
void clear() {
_key = "";
@@ -105,12 +143,14 @@ class LineParsing {
_descr = "";
_order = "";
_addr = "";
+ _reg = "";
_pin = "";
_map = "";
_c = "";
_inv = "";
_state = "";
_db = "";
+ _type = "";
}
String extractInnerDigit(String str) {
@@ -120,30 +160,30 @@ class LineParsing {
}
void createWidgetClass(String descr, String page, String order, String filename, String topic) {
- String buf = "{}";
- if (!loadWidgetClass(filename, buf)) {
- return;
- }
- descr.replace("#", " ");
- page.replace("#", " ");
+ if (filename != "na") {
+ String buf = "{}";
+ if (!loadWidgetClass(filename, buf)) {
+ return;
+ }
- jsonWriteStr(buf, "page", page);
- jsonWriteStr(buf, "order", order);
- jsonWriteStr(buf, "descr", descr);
- jsonWriteStr(buf, "topic", prex + "/" + topic);
+ jsonWriteStr(buf, "page", page);
+ jsonWriteStr(buf, "order", order);
+ jsonWriteStr(buf, "descr", descr);
+ jsonWriteStr(buf, "topic", prex + "/" + topic);
#ifdef LAYOUT_IN_RAM
- all_widgets += widget + "\r\n";
+ all_widgets += widget + "\r\n";
#else
- addFile("layout.txt", buf);
+ addFileLn("layout.txt", buf);
#endif
+ }
}
bool loadWidgetClass(const String& filename, String& buf) {
buf = readFile(getWidgetFileClass(filename), 2048);
bool res = !(buf == "Failed" || buf == "Large");
if (!res) {
- //pm.error("on load" + filename);
+ //SerialPrint("[E]","module","on load" + filename);
}
return res;
}
@@ -151,4 +191,13 @@ class LineParsing {
const String getWidgetFileClass(const String& name) {
return "/widgets/" + name + ".json";
}
+
+ //String jsonWriteStr1(String& json, String name, String value) {
+ // DynamicJsonBuffer jsonBuffer;
+ // JsonObject& root = jsonBuffer.parseObject(json);
+ // root[name] = value;
+ // json = "";
+ // root.printTo(json);
+ // return json;
+ //}
};
diff --git a/include/Class/NotAsinc.h b/include/Class/NotAsinc.h
new file mode 100644
index 00000000..73d45196
--- /dev/null
+++ b/include/Class/NotAsinc.h
@@ -0,0 +1,31 @@
+#pragma once
+#include
+#include
+
+#include
+
+typedef std::function NotAsincCb;
+
+struct NotAsincItem {
+ bool test;
+ NotAsincCb cb;
+ void * cb_arg;
+ volatile bool is_used = false;
+};
+
+class NotAsinc {
+ private:
+ uint8_t size;
+ uint8_t task = 0;
+ NotAsincItem* items = NULL;
+ void handle(NotAsincCb f, void* arg);
+
+ public:
+ NotAsinc(uint8_t size);
+ ~NotAsinc();
+
+ void add(uint8_t i, NotAsincCb, void* arg);
+ void make(uint8_t task);
+ void loop();
+};
+extern NotAsinc* myNotAsincActions;
\ No newline at end of file
diff --git a/include/Class/ScenarioClass.h b/include/Class/ScenarioClass.h
new file mode 100644
index 00000000..3a241112
--- /dev/null
+++ b/include/Class/ScenarioClass.h
@@ -0,0 +1,113 @@
+#pragma once
+#include
+#include "Cmd.h"
+#include "Global.h"
+
+class Scenario {
+ protected:
+ String _scenarioTmp;
+ String _condition;
+ String _conditionParam;
+ String _conditionSign;
+ String _conditionValue;
+ String _scenBlok;
+ String _event;
+ String _eventParam;
+ String _eventValue;
+
+ public:
+ Scenario() : _scenarioTmp{""},
+ _condition{""},
+ _conditionParam{""},
+ _conditionSign{""},
+ _conditionValue{""},
+ _scenBlok{""},
+ _event{""},
+ _eventParam{""},
+ _eventValue{""} {};
+
+ void load() {
+ _scenarioTmp = scenario;
+ }
+
+ void calculate1() {
+ _scenBlok = selectToMarker(_scenarioTmp, "end\n");
+ _condition = selectToMarker(_scenBlok, "\n");
+ _eventParam = selectToMarker(eventBuf, ",");
+ }
+
+ bool isIncommingEventInScenario() {
+ bool ret = false;
+ if (_condition.indexOf(_eventParam) != -1) {
+ ret = true;
+ }
+ return ret;
+ }
+
+ void calculate2() {
+ _scenarioTmp += "\n";
+ _scenarioTmp.replace("\r\n", "\n");
+ _scenarioTmp.replace("\r", "\n");
+
+ _conditionParam = selectFromMarkerToMarker(_condition, " ", 0);
+ _conditionSign = selectFromMarkerToMarker(_condition, " ", 1);
+ _conditionValue = selectFromMarkerToMarker(_condition, " ", 2);
+ if (!isDigitStr(_conditionValue)) _conditionValue = jsonReadStr(configLiveJson, _conditionValue);
+ _eventValue = jsonReadStr(configLiveJson, _conditionParam);
+ }
+
+ void delOneScenBlock() {
+ _scenarioTmp = deleteBeforeDelimiter(_scenarioTmp, "end\n");
+ }
+
+ void delOneEvent() {
+ eventBuf = deleteBeforeDelimiter(eventBuf, ",");
+ }
+
+ bool isConditionSatisfied() {
+ boolean flag = false;
+
+ if (_conditionSign == "=") {
+ flag = _eventValue == _conditionValue;
+ } else if (_conditionSign == "!=") {
+ flag = _eventValue != _conditionValue;
+ } else if (_conditionSign == "<") {
+ flag = _eventValue.toInt() < _conditionValue.toInt();
+ } else if (_conditionSign == ">") {
+ flag = _eventValue.toInt() > _conditionValue.toInt();
+ } else if (_conditionSign == ">=") {
+ flag = _eventValue.toInt() >= _conditionValue.toInt();
+ } else if (_conditionSign == "<=") {
+ flag = _eventValue.toInt() <= _conditionValue.toInt();
+ }
+
+ if (flag) Serial.println("I Scenario event: " + _condition);
+
+ return flag;
+ }
+
+ void loop() {
+ if (!this->isScenarioEnabled()) {
+ return;
+ }
+ this->load(); //после этого мы получили все сценарии
+ while (_scenarioTmp.length() > 1) {
+ this->calculate1(); //расчет необходимый для ответа на следующий вопрос
+ if (this->isIncommingEventInScenario()) { //если вошедшее событие есть в сценарии
+ this->calculate2();
+ if (this->isConditionSatisfied()) { //если вошедшее событие выполняет условие сценария
+ _scenBlok = deleteBeforeDelimiter(_scenBlok, "\n");
+ //Serial.println(" [>] Making: " + _scenBlok);
+ spaceCmdExecute(_scenBlok);
+ }
+ }
+ this->delOneScenBlock(); //удалим использованный блок
+ }
+ this->delOneEvent();
+ }
+
+ bool isScenarioEnabled() {
+ return jsonReadBool(configSetupJson, "scen") && eventBuf != "";
+ }
+};
+extern Scenario* myScenario;
\ No newline at end of file
diff --git a/include/Class/button.h b/include/Class/button.h
deleted file mode 100644
index 87b4a805..00000000
--- a/include/Class/button.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#pragma once
-
-#include
-#include "Class/LineParsing.h"
-#include "Global.h"
-
-class Button : public LineParsing {
- public:
- Button() : LineParsing(){};
-
- void pinModeSet() {
- if (_pin != "") {
- pinMode(_pin.toInt(), OUTPUT);
- }
- }
-
- void pinStateSetDefault() {
- if (_inv == "" && _state != "") {
- pinChange(_key, _pin, _state, true);
- }
- }
-
- void pinStateSetInvDefault() {
- if (_inv != "" && _state != "") {
- pinChange(_key, _pin, _state, false);
- }
- }
-
- void pinChange(String key, String pin, String state, bool rev) {
- int pinInt = pin.toInt();
- int stateInt;
- if (rev) {
- digitalWrite(pinInt, state.toInt());
- } else {
- digitalWrite(pinInt, !state.toInt());
- }
- eventGen(key, "");
- jsonWriteInt(configLiveJson, key, state.toInt());
- MqttClient::publishStatus(key, state);
- }
-};
-
-extern Button* myButton;
\ No newline at end of file
diff --git a/include/Clock.h b/include/Clock.h
index 743a61cc..eaddafde 100644
--- a/include/Clock.h
+++ b/include/Clock.h
@@ -2,13 +2,15 @@
#include "Utils/TimeUtils.h"
#include "Utils/PrintMessage.h"
+#include "Global.h"
+#include "Clock.h"
#ifdef ESP8266
#include "sntp.h"
#endif
class Clock {
- const char* MODULE = "Clock";
+
private:
Time_t _time_local;
@@ -69,7 +71,7 @@ class Clock {
void startSync() {
if (!_configured) {
- pm.info("sync to: " + _ntp + " timezone: " + String(_timezone));
+ //SerialPrint("I","module","sync to: " + _ntp + " timezone: " + String(_timezone));
setupSntp();
_configured = true;
// лучше не ждать, проверим в следующий раз
@@ -77,9 +79,9 @@ class Clock {
}
_hasSynced = hasTimeSynced();
if (_hasSynced) {
- pm.info("synced " + getDateDotFormated() + " " + getTime());
+ //SerialPrint("I","module","synced " + getDateDotFormated() + " " + getTime());
} else {
- pm.error("failed to obtain");
+ //SerialPrint("[E]","module","failed to obtain");
}
}
diff --git a/include/Cmd.h b/include/Cmd.h
index a536a0e5..eb27380d 100644
--- a/include/Cmd.h
+++ b/include/Cmd.h
@@ -4,23 +4,43 @@
extern void cmd_init();
-extern void buttonOut();
-extern void buttonOutSet();
+extern void sensorsInit();
-extern void pwmOut();
-extern void pwmOutSet();
+//extern void levelPr();
+//extern void ultrasonicCm();
+//extern void ultrasonic_reading();
-extern void buttonIn();
-extern void buttonInSet();
+extern void analog_reading1();
+extern void analog_reading2();
+extern void dallas_reading();
+extern void dhtT_reading();
-extern void inputDigit();
-extern void inputDigitSet();
+//extern void dallas();
-extern void inputTime();
-extern void inputTimeSet();
+extern void bmp280T();
+extern void bmp280P();
+extern void bmp280T_reading();
+extern void bmp280P_reading();
-extern void text();
-extern void textSet();
+extern void bme280T();
+extern void bme280P();
+extern void bme280H();
+extern void bme280A();
+
+extern void bme280T_reading();
+extern void bme280P_reading();
+extern void bme280H_reading();
+extern void bme280A_reading();
+
+//extern void dhtT();
+//extern void dhtH();
+//extern void dhtP();
+//extern void dhtC();
+//extern void dhtD();
+//extern void dhtH_reading();
+//extern void dhtP_reading();
+//extern void dhtC_reading();
+//extern void dhtD_reading();
extern void handle_time_init();
extern void stepper();
@@ -31,7 +51,6 @@ extern void serialBegin();
extern void serialWrite();
extern void logging();
-
extern void button();
extern void timeSet();
@@ -41,5 +60,6 @@ extern void firmwareVersion();
extern void firmwareUpdate();
extern void loadScenario();
-extern void fileExecute(const String& filename);
-extern void stringExecute(String& cmdStr);
\ No newline at end of file
+extern void fileCmdExecute(const String& filename);
+extern void csvCmdExecute(String& cmdStr);
+extern void spaceCmdExecute(String& cmdStr);
\ No newline at end of file
diff --git a/include/Consts.h b/include/Consts.h
index ea94ed68..e023921c 100644
--- a/include/Consts.h
+++ b/include/Consts.h
@@ -1,36 +1,33 @@
#pragma once
-/*
-* Main consts
-*/
-#define FIRMWARE_VERSION "2.3.5"
+
+//=================Firmeare=================
+#define FIRMWARE_NAME "esp8266-iotm"
+#define FIRMWARE_VERSION 257
+#define FLASH_4MB true
+
+//=================System===================
#define NUM_BUTTONS 6
#define LED_PIN 2
-#define FLASH_4MB true
+
+//=================MQTT=====================
#define MQTT_RECONNECT_INTERVAL 20000
-#define TELEMETRY_UPDATE_INTERVAL 7200000
+//===============Telemetry==================
+#define TELEMETRY_UPDATE_INTERVAL_MIN 60
-#define DEVICE_CONFIG_FILE "dev_conf.txt"
-#define DEVICE_SCENARIO_FILE "dev_scen.txt"
-#define DEFAULT_PRESET 100
-#define DEFAULT_SCENARIO 100
+//=============Configuration================
+#define DEVICE_CONFIG_FILE "s.conf.csv"
+#define DEVICE_SCENARIO_FILE "s.scen.txt"
-#define TAG_ONE_WIRE "oneWire"
-#define TAG_I2C "i2c"
-#define TAG_ONE_WIRE_PIN "oneWirePin"
-
-/*
-* Optional
-*/
+//=============System parts=================
//#define OTA_UPDATES_ENABLED
//#define MDNS_ENABLED
//#define WEBSOCKET_ENABLED
//#define LAYOUT_IN_RAM
-#define UDP_ENABLED
+//#define UDP_ENABLED
+//#define SSDP_EN
-/*
-* Sensor
-*/
+//=========Sensors enable/disable===========
#define TANK_LEVEL_SAMPLES 10
#define LEVEL_ENABLED
#define ANALOG_ENABLED
@@ -39,19 +36,16 @@
#define BMP_ENABLED
#define BME_ENABLED
-/*
-* Gears
-*/
+//=========Gears enable/disable===========
#define STEPPER_ENABLED
#define SERVO_ENABLED
-/*
-* Other
-*/
+//=========Other enable/disable===========
#define LOGGING_ENABLED
#define SERIAL_ENABLED
#define PUSH_ENABLED
+
struct Time_t {
uint8_t second;
uint8_t minute;
@@ -79,11 +73,25 @@ enum TimerTask_t { WIFI_SCAN,
TIME,
TIME_SYNC,
STATISTICS,
+ STATISTICS_WORK,
UPTIME,
UDP,
UDP_DB,
TEST };
+enum notAsincActions {
+ do_ZERO,
+ do_UPGRADE,
+ do_GETLASTVERSION,
+ do_UDPDATAPARSE,
+ do_MQTTUDP,
+ do_BUSSCAN,
+ do_MQTTPARAMSCHANGED,
+ do_deviceInit,
+ do_delChoosingItems,
+ do_LAST,
+};
+
enum ErrorType_t {
ET_NONE,
ET_FUNCTION,
@@ -108,9 +116,4 @@ enum LedStatus_t {
enum ConfigType_t {
CT_CONFIG,
CT_SCENARIO
-};
-
-enum BusScanner_t {
- BS_I2C,
- BS_ONE_WIRE
-};
+};
\ No newline at end of file
diff --git a/include/FSEditor.h b/include/FSEditor.h
new file mode 100644
index 00000000..394fb0e2
--- /dev/null
+++ b/include/FSEditor.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include
+#include
+
+#ifdef ESP8266
+#include
+#endif
+
+class FSEditor : public AsyncWebHandler {
+ private:
+ fs::FS _fs;
+ String _username;
+ String _password;
+ bool _authenticated;
+ uint32_t _startTime;
+
+ public:
+#ifdef ESP32
+ FSEditor(const fs::FS& fs, const String& username = String(), const String& password = String());
+#else
+ FSEditor(const String& username = String(), const String& password = String(), const fs::FS& fs = LittleFS);
+#endif
+ virtual bool canHandle(AsyncWebServerRequest* request) override final;
+ virtual void handleRequest(AsyncWebServerRequest* request) override final;
+ virtual void handleUpload(AsyncWebServerRequest* request, const String& filename, size_t index, uint8_t* data, size_t len, bool final) override final;
+ virtual bool isRequestHandlerTrivial() override final { return false; }
+};
\ No newline at end of file
diff --git a/include/Global.h b/include/Global.h
index d8fee323..d08aeab3 100644
--- a/include/Global.h
+++ b/include/Global.h
@@ -1,14 +1,11 @@
#pragma once
-
-/*
-* Libraries
-*/
+//===================Libraries===================================================================================================================================================
#include
#include
#include "ESP32.h"
#include "ESP8266.h"
-//
+
#include "Consts.h"
#include "Errors.h"
#include "GyverFilters.h"
@@ -22,8 +19,7 @@
#include "Utils\SysUtils.h"
#include "Utils\PrintMessage.h"
#include "Utils\WiFiUtils.h"
-
-//=========ПОДКЛЮЧЕНИЕ ОБЩИХ БИБЛИОТЕК===============
+#include "Utils\SerialPrint.h"
#include
#include
@@ -38,100 +34,55 @@
#include
#include
+
+
#ifdef WEBSOCKET_ENABLED
extern AsyncWebSocket ws;
//extern AsyncEventSource events;
#endif
extern Clock* timeNow;
-
extern TickerScheduler ts;
-
extern WiFiClient espClient;
-
extern PubSubClient mqtt;
-
extern StringCommand sCmd;
-
extern AsyncWebServer server;
-
extern DallasTemperature sensors;
-
extern OneWire *oneWire;
-
extern boolean but[NUM_BUTTONS];
-
extern Bounce* buttons;
-/*
-* Global vars
-*/
+//Global vars
extern boolean just_load;
+// Json
extern String configSetupJson; //все настройки
extern String configLiveJson; //все данные с датчиков (связан с mqtt)
extern String configOptionJson; //для трансфера
+// Mqtt
extern String chipId;
extern String prex;
extern String all_widgets;
extern String scenario;
-extern String order_loop;
-extern String analog_value_names_list;
-extern int enter_to_analog_counter;
+//orders and events
+extern String orderBuf;
+extern String eventBuf;
+extern String itemsFile;
+extern String itemsLine;
-extern String dallas_value_name;
-extern int enter_to_dallas_counter;
-
-extern String levelPr_value_name;
-extern String ultrasonicCm_value_name;
-
-extern String dhtT_value_name;
-extern String dhtH_value_name;
-
-extern String bmp280T_value_name;
-extern String bmp280P_value_name;
-
-extern String bme280T_value_name;
-extern String bme280P_value_name;
-extern String bme280H_value_name;
-extern String bme280A_value_name;
+// Sensors
+extern String sensorReadingMap;
+extern int8_t dallasEnterCounter;
extern String logging_value_names_list;
extern int enter_to_logging_counter;
-
extern int scenario_line_status[40];
+extern int lastVersion;
-extern String lastVersion;
-
-extern boolean checkUpdatesFlag;
-extern boolean updateFlag;
-extern boolean mqttParamsChanged;
-extern boolean udp_data_parse;
-extern boolean mqtt_send_settings_to_udp;
-
-/*
-* Запрос на скарнирование шины
-*/
-extern boolean busScanFlag;
-/*
-* Запрос на сканирование шины, указание какую
-*/
-extern BusScanner_t busToScan;
-
-extern boolean fsCheckFlag;
-
-extern int sensors_reading_map[15];
-
-/*
-* Global functions
-*/
-
-
-
-
+//Global functions
// Logging
extern void logging();
extern void deleteOldDate(String filename, size_t max_lines, String date_to_add);
@@ -145,7 +96,7 @@ extern void setConfigParam(const char* param, const String& value);
extern String getURL(const String& urls);
extern void do_fscheck();
-extern void do_scan_bus();
+extern void doBusScan();
extern void servo_();
extern void clock_init();
@@ -155,45 +106,7 @@ extern void setLedStatus(LedStatus_t);
extern void eventGen(String event_name, String number);
extern String add_set(String param_name);
-//Sensors
-extern void sensors_init();
-extern void levelPr();
-extern void ultrasonicCm();
-extern void ultrasonic_reading();
-
-extern void analog();
-extern void analog_reading1();
-extern void analog_reading2();
-extern void dallas_reading();
-extern void dhtT_reading();
-
-extern void dallas();
-
-extern void bmp280T();
-extern void bmp280P();
-extern void bmp280T_reading();
-extern void bmp280P_reading();
-
-extern void bme280T();
-extern void bme280P();
-extern void bme280H();
-extern void bme280A();
-
-extern void bme280T_reading();
-extern void bme280P_reading();
-extern void bme280H_reading();
-extern void bme280A_reading();
-
-extern void dhtT();
-extern void dhtH();
-extern void dhtP();
-extern void dhtC();
-extern void dhtD();
-extern void dhtH_reading();
-extern void dhtP_reading();
-extern void dhtC_reading();
-extern void dhtD_reading();
//Timers
extern void Timer_countdown_init();
@@ -203,7 +116,7 @@ extern void timerStop_();
extern void delTimer(String number);
extern int readTimer(int number);
-extern void initUpdater();
+extern void upgradeInit();
// widget
extern void createWidgetByType(String widget_name, String page_name, String page_number, String file, String topic);
@@ -215,15 +128,11 @@ extern void createChart(String widget_name, String page_name, String page_number
extern void pushControl();
// UDP
-extern void udp_init();
-extern void do_udp_data_parse();
-extern void do_mqtt_send_settings_to_udp();
+//extern void udpInit();
+//extern void do_udp_data_parse();
+//extern void do_mqtt_send_settings_to_udp();
+
-extern void addCommandLoop(const String& cmdStr);
-extern void loopSerial();
-extern void loopCmd();
-extern void loopScenario();
-extern void loopUdp();
extern void do_update();
@@ -232,4 +141,4 @@ extern void uptime_init();
// Web
extern void web_init();
-extern void telemetry_init();
+
diff --git a/include/Init.h b/include/Init.h
index 6b4c744e..bb2b2ca7 100644
--- a/include/Init.h
+++ b/include/Init.h
@@ -8,4 +8,3 @@ extern void Device_init();
extern void prsets_init();
extern void handle_uptime();
extern void handle_statistics();
-extern void telemetry_init();
\ No newline at end of file
diff --git a/include/ItemsCmd.h b/include/ItemsCmd.h
new file mode 100644
index 00000000..d949a0f8
--- /dev/null
+++ b/include/ItemsCmd.h
@@ -0,0 +1,48 @@
+#pragma once
+
+extern void buttonOut();
+extern void buttonOutSet();
+
+extern void pwmOut();
+extern void pwmOutSet();
+
+extern void buttonIn();
+extern void buttonInSet();
+
+extern void inputDigit();
+extern void inputDigitSet();
+
+extern void inputTime();
+extern void inputTimeSet();
+
+extern void textOut();
+extern void textOutSet();
+
+extern void analogAdc();
+extern void analogReading();
+
+extern void ultrasonicCm();
+extern void ultrasonicReading();
+
+extern void dallasTemp();
+extern void dallasReading();
+
+extern void dhtTemp();
+extern void dhtReadingTemp();
+extern void dhtHum();
+extern void dhtReadingHum();
+
+extern void bme280Temp();
+extern void bme280ReadingTemp();
+extern void bme280Hum();
+extern void bme280ReadingHum();
+extern void bme280Press();
+extern void bme280ReadingPress();
+
+extern void bmp280Temp();
+extern void bmp280ReadingTemp();
+extern void bmp280Press();
+extern void bmp280ReadingPress();
+
+//extern void modbus();
+//extern void modbusReading();
diff --git a/include/ItemsList.h b/include/ItemsList.h
new file mode 100644
index 00000000..940db0b5
--- /dev/null
+++ b/include/ItemsList.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include
+#include "Global.h"
+
+extern void itemsListInit();
+extern void addItem(String name);
+extern void delChoosingItems();
+extern void delAllItems();
+extern uint8_t getNewElementNumber(String file);
+extern uint8_t getFreePinAll();
+extern uint8_t getFreePinAnalog();
diff --git a/include/Module/Runner.h b/include/Module/Runner.h
index 3d15c421..45ca7403 100644
--- a/include/Module/Runner.h
+++ b/include/Module/Runner.h
@@ -12,6 +12,6 @@ class CmdRunner : public Runner {
public:
void run(const char* cmd, Print* out) override {
String cmdStr{cmd};
- stringExecute(cmdStr);
+ csvCmdExecute(cmdStr);
}
};
\ No newline at end of file
diff --git a/include/MqttClient.h b/include/MqttClient.h
index 74977ef6..7656ced5 100644
--- a/include/MqttClient.h
+++ b/include/MqttClient.h
@@ -2,14 +2,12 @@
#include
-namespace MqttClient {
-void init();
-boolean connect();
-void reconnect();
-void loop();
-
-void subscribe();
+void mqttInit();
+boolean mqttConnect();
+void mqttReconnect();
+void mqttLoop();
+void mqttSubscribe();
boolean publish(const String& topic, const String& data);
boolean publishData(const String& topic, const String& data);
@@ -21,7 +19,5 @@ boolean publishStatus(const String& topic, const String& data);
void publishWidgets();
void publishState();
-void handleSubscribedUpdates(char* topic, uint8_t* payload, size_t length);
+void mqttCallback(char* topic, uint8_t* payload, size_t length);
const String getStateStr();
-
-} // namespace MqttClient
diff --git a/include/RemoteOrdersUdp.h b/include/RemoteOrdersUdp.h
new file mode 100644
index 00000000..5aff5be4
--- /dev/null
+++ b/include/RemoteOrdersUdp.h
@@ -0,0 +1,7 @@
+//#pragma once
+//#include "ESPAsyncUDP.h"
+//extern AsyncUDP asyncUdp;
+//extern void asyncUdpInit();
+//extern String uint8tToString(uint8_t* data, size_t len);
+//extern bool udpPacketValidation(String& data);
+//extern void udpPacketParse(String& data);
\ No newline at end of file
diff --git a/include/SSDP.h b/include/SSDP.h
new file mode 100644
index 00000000..0b13d706
--- /dev/null
+++ b/include/SSDP.h
@@ -0,0 +1,8 @@
+#pragma once
+#include "Global.h"
+#include
+#ifdef SSDP_EN
+extern void SsdpInit();
+extern String xmlNode(String tags, String data);
+extern String decToHex(uint32_t decValue, byte desiredStringLength);
+#endif
\ No newline at end of file
diff --git a/include/Sensors.h b/include/Sensors.h
new file mode 100644
index 00000000..45dcbb04
--- /dev/null
+++ b/include/Sensors.h
@@ -0,0 +1,3 @@
+#pragma once
+
+
diff --git a/include/Upgrade.h b/include/Upgrade.h
deleted file mode 100644
index e031a765..00000000
--- a/include/Upgrade.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#pragma once
-
-void getLastVersion();
-
-void do_update();
\ No newline at end of file
diff --git a/include/UpgradeFirm.h b/include/UpgradeFirm.h
new file mode 100644
index 00000000..b02adb12
--- /dev/null
+++ b/include/UpgradeFirm.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include
+
+extern void upgradeInit();
+extern void getLastVersion();
+extern void upgrade_firmware(int type);
+extern bool upgradeFS();
+extern bool upgradeBuild();
+extern void restartEsp();
\ No newline at end of file
diff --git a/include/Utils/FileUtils.h b/include/Utils/FileUtils.h
index af4dadc9..da2688ac 100644
--- a/include/Utils/FileUtils.h
+++ b/include/Utils/FileUtils.h
@@ -35,6 +35,11 @@ File seekFile(const String& filename, size_t position = 0);
*/
const String readFileString(const String& filename, const String& to_find);
+/*
+* Добовление строки в файл
+*/
+const String addFileLn(const String& filename, const String& str);
+
/*
* Добовление строки в файл
*/
diff --git a/include/Utils/JsonUtils.h b/include/Utils/JsonUtils.h
index f759361c..c244a14e 100644
--- a/include/Utils/JsonUtils.h
+++ b/include/Utils/JsonUtils.h
@@ -14,4 +14,6 @@ String jsonWriteInt(String& json, String name, int value);
String jsonWriteFloat(String& json, String name, float value);
-String jsonWriteBool(String& json, String name, boolean value);
\ No newline at end of file
+String jsonWriteBool(String& json, String name, boolean value);
+
+void saveConfig();
\ No newline at end of file
diff --git a/include/Utils/PrintMessage.h b/include/Utils/PrintMessage.h
index d6425544..833342b6 100644
--- a/include/Utils/PrintMessage.h
+++ b/include/Utils/PrintMessage.h
@@ -4,6 +4,8 @@
#include "Utils\StringUtils.h"
#include "Utils\TimeUtils.h"
#include "Errors.h"
+#include "Global.h"
+
#define pm PrintMessage(MODULE)
diff --git a/include/Utils/SerialPrint.h b/include/Utils/SerialPrint.h
new file mode 100644
index 00000000..f0d2d79c
--- /dev/null
+++ b/include/Utils/SerialPrint.h
@@ -0,0 +1,3 @@
+#pragma once
+#include
+void SerialPrint(String errorLevel, String module, String msg);
\ No newline at end of file
diff --git a/include/Utils/StringUtils.h b/include/Utils/StringUtils.h
index 260beaa9..3c23ee4a 100644
--- a/include/Utils/StringUtils.h
+++ b/include/Utils/StringUtils.h
@@ -18,6 +18,8 @@ String deleteBeforeDelimiter(String str, String found);
String deleteBeforeDelimiterTo(String str, String found);
+String deleteToMarkerLast(String str, String found);
+
String selectFromMarkerToMarker(String str, String found, int number);
size_t itemsCount(String str, const String& separator);
diff --git a/include/Utils/SysUtils.h b/include/Utils/SysUtils.h
index 6e40c358..1686e51f 100644
--- a/include/Utils/SysUtils.h
+++ b/include/Utils/SysUtils.h
@@ -1,13 +1,17 @@
#pragma once
-
#include
+#include "Global.h"
const String getChipId();
+void setLedStatus(LedStatus_t status);
+
const String getUniqueId(const String& name);
const String printMemoryStatus();
const String getHeapStats();
-const String getMacAddress();
\ No newline at end of file
+const String getMacAddress();
+
+void setChipId();
\ No newline at end of file
diff --git a/include/Utils/WebUtils.h b/include/Utils/WebUtils.h
index fe8caec4..5479314c 100644
--- a/include/Utils/WebUtils.h
+++ b/include/Utils/WebUtils.h
@@ -1,73 +1,7 @@
#pragma once
+#include "HttpServer.h"
+#include
-#include "ESPAsyncWebServer.h"
-
-const String getMethodName(AsyncWebServerRequest* request) {
- String res = F("UNKNOWN");
- if (request->method() == HTTP_GET)
- res = F("GET");
- else if (request->method() == HTTP_POST)
- res = F("POST");
- else if (request->method() == HTTP_DELETE)
- res = F("DELETE");
- else if (request->method() == HTTP_PUT)
- res = F("PUT");
- else if (request->method() == HTTP_PATCH)
- res = F("PATCH");
- else if (request->method() == HTTP_HEAD)
- res = F("HEAD");
- else if (request->method() == HTTP_OPTIONS)
- res = F("OPTIONS");
- return res;
-}
-
-const String getRequestInfo(AsyncWebServerRequest* request) {
- String res = getMethodName(request);
- res += ' ';
- res += "http://";
- res += request->host();
- res += request->url();
- res += '\n';
- if (request->contentLength()) {
- res += "content-type: ";
- res += request->contentType();
- res += " content-lenght: ";
- res += prettyBytes(request->contentLength());
- res += '\n';
- }
-
- if (request->headers()) {
- res += "headers:\n";
- for (size_t i = 0; i < request->headers(); i++) {
- AsyncWebHeader* h = request->getHeader(i);
- res += h->name();
- res += '=';
- res += h->value();
- res += '\n';
- }
- }
-
- if (request->params()) {
- res += "params:\n";
- for (size_t i = 0; i < request->params(); i++) {
- AsyncWebParameter* p = request->getParam(i);
- if (p->isFile()) {
- res += "FILE";
- } else if (p->isPost()) {
- res += "POST";
- } else {
- res += "GET";
- }
- res += ' ';
- res += p->name();
- res += ':';
- res += p->value();
- if (p->isFile()) {
- res += " size:";
- res += p->size();
- }
- res += '\n';
- }
- }
- return res;
-}
+extern String getURL(const String& urls);
+extern const String getMethodName(AsyncWebServerRequest* request);
+extern const String getRequestInfo(AsyncWebServerRequest* request);
\ No newline at end of file
diff --git a/include/Utils/WiFiUtils.h b/include/Utils/WiFiUtils.h
index da020af4..ef2c9379 100644
--- a/include/Utils/WiFiUtils.h
+++ b/include/Utils/WiFiUtils.h
@@ -4,9 +4,9 @@
boolean isNetworkActive();
-void startSTAMode();
+void routerConnect();
bool startAPMode();
-boolean scanWiFi(String ssid);
+boolean RouterFind(String ssid);
diff --git a/include/Utils/statUtils.h b/include/Utils/statUtils.h
new file mode 100644
index 00000000..c97abf8e
--- /dev/null
+++ b/include/Utils/statUtils.h
@@ -0,0 +1,22 @@
+#pragma once
+#include
+#include "Global.h"
+
+extern void initSt();
+extern String updateDevicePsn(String lat, String lon, String accur);
+extern String updateDeviceStatus();
+extern String addNewDevice();
+
+extern void decide();
+extern void getPsn();
+
+extern String getUptimeTotal();
+extern uint8_t getNextNumber(String file);
+extern uint8_t getCurrentNumber(String file);
+
+//extern int plusOneHour();
+//extern void eeWriteInt(int pos, int val);
+//extern int eeGetInt(int pos);
+//extern void updateDeviceList();
+//extern void saveId(String file, int id);
+//extern int getId(String file);
\ No newline at end of file
diff --git a/include/Web.h b/include/Web.h
new file mode 100644
index 00000000..a80a08d2
--- /dev/null
+++ b/include/Web.h
@@ -0,0 +1,6 @@
+#pragma once
+#include "Arduino.h"
+
+
+void web_init();
+void setConfigParam(const char* param, const String& value);
diff --git a/include/Class/Switch.h b/include/items/ButtonInClass.h
similarity index 78%
rename from include/Class/Switch.h
rename to include/items/ButtonInClass.h
index 57e9f450..10763529 100644
--- a/include/Class/Switch.h
+++ b/include/items/ButtonInClass.h
@@ -1,17 +1,16 @@
#pragma once
-
#include
#include "Class/LineParsing.h"
#include "Global.h"
-class Switch : public LineParsing {
+class ButtonInClass : public LineParsing {
protected:
int numberEntering = 0;
int state = _state.toInt();
public:
- Switch() : LineParsing(){};
+ ButtonInClass() : LineParsing(){};
void init() {
if (_pin != "") {
@@ -28,10 +27,13 @@ class Switch : public LineParsing {
if (but[switch_number]) {
buttons[switch_number].update();
if (buttons[switch_number].fell()) {
+ String key = jsonReadStr(configOptionJson, "switch_num_" + String(switch_number));
+ state = 1;
+ switchChangeVirtual(key, String(state));
}
if (buttons[switch_number].rose()) {
String key = jsonReadStr(configOptionJson, "switch_num_" + String(switch_number));
- state = !state;
+ state = 0;
switchChangeVirtual(key, String(state));
}
}
@@ -40,6 +42,7 @@ class Switch : public LineParsing {
switch_number = 0;
}
}
+
void switchStateSetDefault() {
if (_state != "") {
switchChangeVirtual(_key, _state);
@@ -49,8 +52,8 @@ class Switch : public LineParsing {
void switchChangeVirtual(String key, String state) {
eventGen(key, "");
jsonWriteInt(configLiveJson, key, state.toInt());
- MqttClient::publishStatus(key, state);
+ publishStatus(key, state);
}
};
-extern Switch* mySwitch;
\ No newline at end of file
+extern ButtonInClass myButtonIn;
\ No newline at end of file
diff --git a/include/items/ButtonOutClass.h b/include/items/ButtonOutClass.h
new file mode 100644
index 00000000..46590814
--- /dev/null
+++ b/include/items/ButtonOutClass.h
@@ -0,0 +1,40 @@
+#pragma once
+#include
+
+#include "Class/LineParsing.h"
+#include "Global.h"
+
+class ButtonOutClass : public LineParsing {
+ public:
+ ButtonOutClass() : LineParsing(){};
+
+ void init() {
+ if (_pin != "") {
+ pinMode(_pin.toInt(), OUTPUT);
+ }
+ jsonWriteStr(configOptionJson, _key + "_pin", _pin);
+ jsonWriteStr(configOptionJson, _key + "_inv", _inv);
+ }
+
+ void pinStateSetDefault() {
+ pinChange(_key, _state);
+ }
+
+
+ void pinChange(String key, String state) {
+ String pin = jsonReadStr(configOptionJson, key + "_pin");
+ String inv = jsonReadStr(configOptionJson, key + "_inv");
+ int pinInt = pin.toInt();
+
+ if (inv == "") {
+ digitalWrite(pinInt, state.toInt());
+ } else {
+ digitalWrite(pinInt, !state.toInt());
+ }
+ eventGen(key, "");
+ jsonWriteInt(configLiveJson, key, state.toInt());
+ publishStatus(key, state);
+ }
+};
+
+extern ButtonOutClass myButtonOut;
\ No newline at end of file
diff --git a/include/Class/Input.h b/include/items/InputClass.h
similarity index 74%
rename from include/Class/Input.h
rename to include/items/InputClass.h
index 4f5bdec0..7d072423 100644
--- a/include/Class/Input.h
+++ b/include/items/InputClass.h
@@ -1,13 +1,11 @@
#pragma once
-
#include
-
#include "Class/LineParsing.h"
#include "Global.h"
-class Input : public LineParsing {
+class InputClass : public LineParsing {
public:
- Input() : LineParsing(){};
+ InputClass() : LineParsing(){};
void inputSetDefaultFloat() {
inputSetFloat(_key, _state);
@@ -20,14 +18,14 @@ class Input : public LineParsing {
void inputSetFloat(String key, String state) {
eventGen(key, "");
jsonWriteFloat(configLiveJson, key, state.toFloat());
- MqttClient::publishStatus(key, state);
+ publishStatus(key, state);
}
void inputSetStr(String key, String state) {
eventGen(key, "");
jsonWriteStr(configLiveJson, key, state);
- MqttClient::publishStatus(key, state);
+ publishStatus(key, state);
}
};
-extern Input* myInput;
\ No newline at end of file
+extern InputClass myInput;
\ No newline at end of file
diff --git a/include/items/OutputTextClass.h b/include/items/OutputTextClass.h
new file mode 100644
index 00000000..c52cd54c
--- /dev/null
+++ b/include/items/OutputTextClass.h
@@ -0,0 +1,23 @@
+#pragma once
+#include
+#include "Class/LineParsing.h"
+#include "Global.h"
+
+class OutputTextClass : public LineParsing {
+ public:
+ OutputTextClass() : LineParsing(){};
+
+ void OutputModuleStateSetDefault() {
+ if (_state != "") {
+ OutputModuleChange(_key, _state);
+ }
+ }
+
+ void OutputModuleChange(String key, String state) {
+ state.replace("#", " ");
+ eventGen(key, "");
+ jsonWriteStr(configLiveJson, key, state);
+ publishStatus(key, state);
+ }
+};
+extern OutputTextClass myOutputText;
\ No newline at end of file
diff --git a/include/Class/Pwm.h b/include/items/PwmOutClass.h
similarity index 79%
rename from include/Class/Pwm.h
rename to include/items/PwmOutClass.h
index 15353b32..807762d6 100644
--- a/include/Class/Pwm.h
+++ b/include/items/PwmOutClass.h
@@ -1,13 +1,11 @@
#pragma once
-
#include
-
#include "Class/LineParsing.h"
#include "Global.h"
-class Pwm : public LineParsing {
+class PwmOutClass : public LineParsing {
public:
- Pwm() : LineParsing(){};
+ PwmOutClass() : LineParsing(){};
void pwmModeSet() {
if (_pin != "") {
@@ -26,8 +24,8 @@ class Pwm : public LineParsing {
analogWrite(pinInt, state.toInt());
eventGen(key, "");
jsonWriteInt(configLiveJson, key, state.toInt());
- MqttClient::publishStatus(key, state);
+ publishStatus(key, state);
}
};
-extern Pwm* myPwm;
\ No newline at end of file
+extern PwmOutClass myPwmOut;
\ No newline at end of file
diff --git a/include/items/SensorAnalogClass.h b/include/items/SensorAnalogClass.h
new file mode 100644
index 00000000..2a5c601b
--- /dev/null
+++ b/include/items/SensorAnalogClass.h
@@ -0,0 +1,38 @@
+#pragma once
+#include
+
+#include "Class/LineParsing.h"
+#include "Global.h"
+#include "items/SensorConvertingClass.h"
+
+class SensorAnalogClass : public SensorConvertingClass {
+ public:
+ SensorAnalogClass() : SensorConvertingClass(){};
+
+ void SensorAnalogInit() {
+ jsonWriteStr(configOptionJson, _key + "_pin", _pin);
+ jsonWriteStr(configOptionJson, _key + "_map", _map);
+ jsonWriteStr(configOptionJson, _key + "_с", _c);
+ }
+
+ int SensorAnalogRead(String key, String pin) {
+ int pinInt = pin.toInt();
+ int value;
+
+#ifdef ESP32
+ value = analogRead(pinInt);
+#endif
+#ifdef ESP8266
+ value = analogRead(A0);
+#endif
+
+ value = this->mapping(key, value);
+ float valueFl = this->correction(key, value);
+ eventGen(key, "");
+ jsonWriteStr(configLiveJson, key, String(valueFl));
+ publishStatus(key, String(valueFl));
+ Serial.println("I sensor '" + key + "' data: " + String(valueFl));
+ return value;
+ }
+};
+extern SensorAnalogClass mySensorAnalog;
\ No newline at end of file
diff --git a/include/items/SensorBme280Class.h b/include/items/SensorBme280Class.h
new file mode 100644
index 00000000..35641652
--- /dev/null
+++ b/include/items/SensorBme280Class.h
@@ -0,0 +1,55 @@
+#pragma once
+#include
+
+#include "Class/LineParsing.h"
+#include "Global.h"
+#include "items/SensorConvertingClass.h"
+
+Adafruit_BME280 bme;
+Adafruit_Sensor *bme_temp = bme.getTemperatureSensor();
+Adafruit_Sensor *bme_pressure = bme.getPressureSensor();
+Adafruit_Sensor *bme_humidity = bme.getHumiditySensor();
+
+class SensorBme280Class : public SensorConvertingClass {
+ public:
+ SensorBme280Class() : SensorConvertingClass(){};
+
+ void SensorBme280Init() {
+ bme.begin(hexStringToUint8(_addr));
+ jsonWriteStr(configOptionJson, _key + "_map", _map);
+ jsonWriteStr(configOptionJson, _key + "_с", _c);
+ sensorReadingMap += _key + ",";
+ }
+
+ void SensorBme280ReadTmp(String key) {
+ float value;
+ value = bme.readTemperature();
+ float valueFl = this->correction(key, value);
+ eventGen(key, "");
+ jsonWriteStr(configLiveJson, key, String(valueFl));
+ publishStatus(key, String(valueFl));
+ Serial.println("I sensor '" + key + "' data: " + String(valueFl));
+ }
+
+ void SensorBme280ReadHum(String key) {
+ float value;
+ value = bme.readHumidity();
+ float valueFl = this->correction(key, value);
+ eventGen(key, "");
+ jsonWriteStr(configLiveJson, key, String(valueFl));
+ publishStatus(key, String(valueFl));
+ Serial.println("I sensor '" + key + "' data: " + String(valueFl));
+ }
+
+ void SensorBme280ReadPress(String key) {
+ float value;
+ value = bme.readPressure();
+ value = value / 1.333224 / 100;
+ float valueFl = this->correction(key, value);
+ eventGen(key, "");
+ jsonWriteStr(configLiveJson, key, String(valueFl));
+ publishStatus(key, String(valueFl));
+ Serial.println("I sensor '" + key + "' data: " + String(valueFl));
+ }
+};
+extern SensorBme280Class mySensorBme280;
\ No newline at end of file
diff --git a/include/items/SensorBmp280Class.h b/include/items/SensorBmp280Class.h
new file mode 100644
index 00000000..438258fc
--- /dev/null
+++ b/include/items/SensorBmp280Class.h
@@ -0,0 +1,48 @@
+#pragma once
+#include
+
+#include "Class/LineParsing.h"
+#include "Global.h"
+#include "items/SensorConvertingClass.h"
+
+Adafruit_BMP280 bmp;
+Adafruit_Sensor *bmp_temp = bmp.getTemperatureSensor();
+Adafruit_Sensor *bmp_pressure = bmp.getPressureSensor();
+
+class SensorBmp280Class : public SensorConvertingClass {
+ public:
+ SensorBmp280Class() : SensorConvertingClass(){};
+
+ void SensorBmp280Init() {
+ bmp.begin(hexStringToUint8(_addr));
+ jsonWriteStr(configOptionJson, _key + "_map", _map);
+ jsonWriteStr(configOptionJson, _key + "_с", _c);
+ sensorReadingMap += _key + ",";
+ }
+
+ void SensorBmp280ReadTmp(String key) {
+ float value;
+ sensors_event_t temp_event;
+ bmp_temp->getEvent(&temp_event);
+ value = temp_event.temperature;
+ float valueFl = this->correction(key, value);
+ eventGen(key, "");
+ jsonWriteStr(configLiveJson, key, String(valueFl));
+ publishStatus(key, String(valueFl));
+ Serial.println("I sensor '" + key + "' data: " + String(valueFl));
+ }
+
+ void SensorBmp280ReadPress(String key) {
+ float value;
+ sensors_event_t pressure_event;
+ bmp_pressure->getEvent(&pressure_event);
+ value = pressure_event.pressure;
+ value = value / 1.333224;
+ float valueFl = this->correction(key, value);
+ eventGen(key, "");
+ jsonWriteStr(configLiveJson, key, String(valueFl));
+ publishStatus(key, String(valueFl));
+ Serial.println("I sensor '" + key + "' data: " + String(valueFl));
+ }
+};
+extern SensorBmp280Class mySensorBmp280;
\ No newline at end of file
diff --git a/include/items/SensorConvertingClass.h b/include/items/SensorConvertingClass.h
new file mode 100644
index 00000000..5ddf59c8
--- /dev/null
+++ b/include/items/SensorConvertingClass.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include
+
+#include "Class/LineParsing.h"
+#include "Global.h"
+
+class SensorConvertingClass : public LineParsing {
+ public:
+ SensorConvertingClass() : LineParsing(){};
+
+ int mapping(String key, int input) {
+ String map_ = jsonReadStr(configOptionJson, key + "_map");
+ if (map_ != "") {
+ input = map(input,
+ selectFromMarkerToMarker(map_, ",", 0).toInt(),
+ selectFromMarkerToMarker(map_, ",", 1).toInt(),
+ selectFromMarkerToMarker(map_, ",", 2).toInt(),
+ selectFromMarkerToMarker(map_, ",", 3).toInt());
+ }
+ return input;
+ }
+
+ float correction(String key, float input) {
+ String corr = jsonReadStr(configOptionJson, key + "_с");
+ if (corr != "") {
+ float coef = corr.toFloat();
+ input = input * coef;
+ }
+ return input;
+ }
+};
\ No newline at end of file
diff --git a/include/items/SensorDallasClass.h b/include/items/SensorDallasClass.h
new file mode 100644
index 00000000..ff7e11bf
--- /dev/null
+++ b/include/items/SensorDallasClass.h
@@ -0,0 +1,45 @@
+#pragma once
+#include
+#include "Class/LineParsing.h"
+#include "Global.h"
+#include "items/SensorConvertingClass.h"
+
+class SensorDallasClass : public SensorConvertingClass {
+ public:
+ SensorDallasClass() : SensorConvertingClass(){};
+
+ void SensorDallasInit() {
+ oneWire = new OneWire((uint8_t)_pin.toInt());
+ sensors.setOneWire(oneWire);
+ sensors.begin();
+ sensors.setResolution(48);
+
+ sensorReadingMap += _key + ",";
+ dallasEnterCounter++;
+
+ jsonWriteInt(configOptionJson, _key + "_num", dallasEnterCounter);
+ jsonWriteStr(configOptionJson, _key + "_map", _map);
+ jsonWriteStr(configOptionJson, _key + "_с", _c);
+ }
+
+ void SensorDallasRead(String key) {
+ float value;
+ byte num = sensors.getDS18Count();
+ sensors.requestTemperatures();
+
+ int cnt = jsonReadInt(configOptionJson, key + "_num");
+
+ for (byte i = 0; i < num; i++) {
+ if (i == cnt) {
+ value = sensors.getTempCByIndex(i);
+ //value = this->mapping(key, value);
+ float valueFl = this->correction(key, value);
+ eventGen(key, "");
+ jsonWriteStr(configLiveJson, key, String(valueFl));
+ publishStatus(key, String(valueFl));
+ Serial.println("I sensor '" + key + "' data: " + String(valueFl));
+ }
+ }
+ }
+};
+extern SensorDallasClass mySensorDallas;
\ No newline at end of file
diff --git a/include/items/SensorDhtClass.h b/include/items/SensorDhtClass.h
new file mode 100644
index 00000000..bea2edb9
--- /dev/null
+++ b/include/items/SensorDhtClass.h
@@ -0,0 +1,78 @@
+#pragma once
+#include
+
+#include "Class/LineParsing.h"
+#include "Global.h"
+#include "items/SensorConvertingClass.h"
+
+DHTesp dht;
+class SensorDhtClass : public SensorConvertingClass {
+ public:
+ SensorDhtClass() : SensorConvertingClass(){};
+
+ void SensorDhtInit() {
+ if (_type == "dht11") {
+ dht.setup(_pin.toInt(), DHTesp::DHT11);
+ }
+ if (_type == "dht22") {
+ dht.setup(_pin.toInt(), DHTesp::DHT22);
+ }
+ sensorReadingMap += _key + ",";
+
+ //to do если надо будет читать несколько dht
+ //dhtEnterCounter++;
+ //jsonWriteInt(configOptionJson, _key + "_num", dhtEnterCounter);
+
+ jsonWriteStr(configOptionJson, _key + "_map", _map);
+ jsonWriteStr(configOptionJson, _key + "_с", _c);
+ }
+
+ void SensorDhtReadTemp(String key) {
+ //to do если надо будет читать несколько dht
+ //int cnt = jsonReadInt(configOptionJson, key + "_num");
+ float value;
+ static int counter;
+ if (dht.getStatus() != 0 && counter < 5) {
+ counter++;
+ //return;
+ } else {
+ counter = 0;
+ value = dht.getTemperature();
+ if (String(value) != "nan") {
+ //value = this->mapping(key, value);
+ float valueFl = this->correction(key, value);
+ eventGen(key, "");
+ jsonWriteStr(configLiveJson, key, String(valueFl));
+ publishStatus(key, String(valueFl));
+ Serial.println("I sensor '" + key + "' data: " + String(valueFl));
+ } else {
+ Serial.println("[E] sensor '" + key);
+ }
+ }
+ }
+
+ void SensorDhtReadHum(String key) {
+ //to do если надо будет читать несколько dht
+ //int cnt = jsonReadInt(configOptionJson, key + "_num");
+ float value;
+ static int counter;
+ if (dht.getStatus() != 0 && counter < 5) {
+ counter++;
+ //return;
+ } else {
+ counter = 0;
+ value = dht.getHumidity();
+ if (String(value) != "nan") {
+ //value = this->mapping(key, value);
+ float valueFl = this->correction(key, value);
+ eventGen(key, "");
+ jsonWriteStr(configLiveJson, key, String(valueFl));
+ publishStatus(key, String(valueFl));
+ Serial.println("I sensor '" + key + "' data: " + String(valueFl));
+ } else {
+ Serial.println("[E] sensor '" + key);
+ }
+ }
+ }
+};
+extern SensorDhtClass mySensorDht;
\ No newline at end of file
diff --git a/include/items/SensorModbusClass.h b/include/items/SensorModbusClass.h
new file mode 100644
index 00000000..27f36c66
--- /dev/null
+++ b/include/items/SensorModbusClass.h
@@ -0,0 +1,83 @@
+//#pragma once
+//#include
+//#include
+//#include
+//
+//#include "Class/LineParsing.h"
+//#include "Global.h"
+//#include "items/SensorConvertingClass.h"
+//
+//ModbusMaster modbus1;
+//SoftwareSerial uart(13, 12); // RX, TX
+//
+//class SensorModbusClass : public SensorConvertingClass {
+// public:
+// SensorModbusClass() : SensorConvertingClass(){};
+//
+// void SensorModbusInit() {
+// uart.begin(9600);
+// jsonWriteStr(configOptionJson, _key + "_map", _map);
+// jsonWriteStr(configOptionJson, _key + "_с", _c);
+// sensorReadingMap += _key + " " + _addr + " " + _reg + ",";
+// Serial.println(sensorReadingMap);
+// }
+//
+// void SensorModbusRead(String key, uint8_t slaveAddress, uint16_t regAddress) {
+// int value;
+//
+// modbus1.begin(slaveAddress, uart);
+// uint16_t reqisterValue = modbus1.readHoldingRegisters(regAddress, 1);
+// if (getResultMsg(&modbus1, reqisterValue)) {
+// reqisterValue = modbus1.getResponseBuffer(0);
+// value = reqisterValue;
+// } else {
+// value = NULL;
+// }
+//
+// int valueFl = this->correction(key, value);
+// eventGen(key, "");
+// jsonWriteStr(configLiveJson, key, String(valueFl));
+// publishStatus(key, String(valueFl));
+// Serial.println("I sensor '" + key + "' data: " + String(valueFl) + ", Slave dev addr: " + String(slaveAddress) + ", Register: " + String(regAddress));
+// }
+//
+// bool getResultMsg(ModbusMaster* modbus1, uint16_t result) {
+// String tmpstr;
+// switch (result) {
+// case modbus1->ku8MBSuccess:
+// return true;
+// tmpstr += "Ok";
+// break;
+// case modbus1->ku8MBIllegalFunction:
+// tmpstr += "Illegal Function";
+// break;
+// case modbus1->ku8MBIllegalDataAddress:
+// tmpstr += "Illegal Data Address";
+// break;
+// case modbus1->ku8MBIllegalDataValue:
+// tmpstr += "Illegal Data Value";
+// break;
+// case modbus1->ku8MBSlaveDeviceFailure:
+// tmpstr += "Slave Device Failure";
+// break;
+// case modbus1->ku8MBInvalidSlaveID:
+// tmpstr += "Invalid Slave ID";
+// break;
+// case modbus1->ku8MBInvalidFunction:
+// tmpstr += "Invalid Function";
+// break;
+// case modbus1->ku8MBResponseTimedOut:
+// tmpstr += "Response Timed Out";
+// break;
+// case modbus1->ku8MBInvalidCRC:
+// tmpstr += "Invalid CRC";
+// break;
+// default:
+// tmpstr += "Unknown error: " + String(result);
+// break;
+// }
+// SerialPrint("I", "Modbus", tmpstr);
+// return false;
+// }
+//};
+//extern SensorModbusClass mySensorModbus;
\ No newline at end of file
diff --git a/include/items/SensorUltrasonicClass.h b/include/items/SensorUltrasonicClass.h
new file mode 100644
index 00000000..06d6a972
--- /dev/null
+++ b/include/items/SensorUltrasonicClass.h
@@ -0,0 +1,49 @@
+#pragma once
+#include
+
+#include "Class/LineParsing.h"
+#include "Global.h"
+#include "items/SensorConvertingClass.h"
+#include "GyverFilters.h"
+
+GMedian<6, int> testFilter;
+
+class SensorUltrasonic : public SensorConvertingClass {
+ public:
+ SensorUltrasonic() : SensorConvertingClass(){};
+ void init() {
+ sensorReadingMap += _key + ",";
+ String trig = selectFromMarkerToMarker(_pin, ",", 0);
+ String echo = selectFromMarkerToMarker(_pin, ",", 1);
+ pinMode(trig.toInt(), OUTPUT);
+ pinMode(echo.toInt(), INPUT);
+ jsonWriteStr(configOptionJson, _key + "_trig", trig);
+ jsonWriteStr(configOptionJson, _key + "_echo", echo);
+ jsonWriteStr(configOptionJson, _key + "_map", _map);
+ jsonWriteStr(configOptionJson, _key + "_с", _c);
+ }
+
+ void SensorUltrasonicRead(String key) {
+ int trig = jsonReadStr(configOptionJson, key + "_trig").toInt();
+ int echo = jsonReadStr(configOptionJson, key + "_echo").toInt();
+ int value;
+
+ digitalWrite(trig, LOW);
+ delayMicroseconds(2);
+ digitalWrite(trig, HIGH);
+ delayMicroseconds(10);
+ digitalWrite(trig, LOW);
+ long duration_ = pulseIn(echo, HIGH, 30000); // 3000 µs = 50cm // 30000 µs = 5 m
+ value = duration_ / 29 / 2;
+
+ value = testFilter.filtered(value);
+
+ value = this->mapping(key, value);
+ float valueFl = this->correction(key, value);
+ eventGen(key, "");
+ jsonWriteStr(configLiveJson, key, String(valueFl));
+ publishStatus(key, String(valueFl));
+ Serial.println("I sensor '" + key + "' data: " + String(valueFl));
+ }
+};
+extern SensorUltrasonic mySensorUltrasonic;
\ No newline at end of file
diff --git a/include/main.h b/include/main.h
new file mode 100644
index 00000000..0d48dfc5
--- /dev/null
+++ b/include/main.h
@@ -0,0 +1,3 @@
+#pragma once
+
+//void myCallback;
\ No newline at end of file
diff --git a/lib/GyverFilters/library.properties b/lib/GyverFilters/library.properties
index 7c211d3d..2c0c881a 100644
--- a/lib/GyverFilters/library.properties
+++ b/lib/GyverFilters/library.properties
@@ -1,7 +1,7 @@
name=GyverFilters
-version=2.0
-author=AlexGyver
-maintainer=AlexGyver
+version=2.1
+author=AlexGyver
+maintainer=AlexGyver
sentence=Library with few filters for data.
paragraph=Includes median, running average, AB, simplified Kalman and linear approximation filtering algorithms.
category=Data Processing
diff --git a/lib/GyverFilters/src/GyverFilters.h b/lib/GyverFilters/src/GyverFilters.h
index e03e4bf5..cb35777c 100644
--- a/lib/GyverFilters/src/GyverFilters.h
+++ b/lib/GyverFilters/src/GyverFilters.h
@@ -7,7 +7,8 @@
#include
/*
- GyverFilters - библиотека с некоторыми удобными фильтрами:
+ GyverFilters - библиотека с некоторыми удобными фильтрами.
+ Документация: https://alexgyver.ru/gyverfilters/
- GFilterRA - компактная альтернатива фильтра экспоненциальное бегущее среднее (Running Average)
- GMedian3 - быстрый медианный фильтр 3-го порядка (отсекает выбросы)
- GMedian - медианный фильтр N-го порядка. Порядок настраивается в GyverFilters.h - MEDIAN_FILTER_SIZE
@@ -23,4 +24,5 @@
- Улучшен и исправлен median и median3
- Улучшен linear
- Смотрите примеры! Использование этих фильтров чуть изменилось
+ - 2.1: Исправлен расчёт дельты в линейном фильтре
*/
\ No newline at end of file
diff --git a/lib/GyverFilters/src/filters/linear.h b/lib/GyverFilters/src/filters/linear.h
index 65a134f3..a3f320a2 100644
--- a/lib/GyverFilters/src/filters/linear.h
+++ b/lib/GyverFilters/src/filters/linear.h
@@ -19,7 +19,7 @@ public:
a = a - (long)sumX * sumY;
a = (float)a / (arrSize * sumX2 - sumX * sumX);
b = (float)(sumY - (float)a * sumX) / arrSize;
- delta = a * arrSize; // расчёт изменения
+ delta = a * (x_array[arrSize-1] - x_array[0]); // расчёт изменения
}
float getA() {return a;} // получить коэффициент А
float getB() {return b;} // получить коэффициент В
@@ -27,4 +27,23 @@ public:
private:
float a, b, delta;
-};
\ No newline at end of file
+};
+
+/*
+Сам алгоритм выглядит так:
+void loop() {
+ sumX = 0;
+ sumY = 0;
+ sumX2 = 0;
+ sumXY = 0;
+ for (int i = 0; i < steps; i++) {
+ sumX += X[i];
+ sumY += Y[i];
+ sumX2 += X[i] * X[i];
+ sumXY += X[i] * Y[i];
+ }
+ a = (steps * sumXY - sumX * sumY) / (steps * sumX2 - sumX * sumX);
+ b = (sumY - a * sumX) / steps;
+ int delta = steps * a;
+}
+*/
\ No newline at end of file
diff --git a/lib/ModbusMaster/.github/ISSUE_TEMPLATE.md b/lib/ModbusMaster/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 00000000..7ae83e53
--- /dev/null
+++ b/lib/ModbusMaster/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,66 @@
+
+
+
+### ModbusMaster version
+[Version of the project where you are encountering the issue]
+
+### Arduino IDE version
+[Version of Arduino IDE in your environment]
+
+### Arduino Hardware
+[Hardware information, including board and processor]
+
+### Platform Details
+[Operating system distribution and release version]
+
+---
+
+### Scenario:
+[What you are trying to achieve and you can't?]
+
+### Steps to Reproduce:
+[If you are filing an issue what are the things we need to do in order to repro your problem? How are you using this project or any resources it includes?]
+
+### Expected Result:
+[What are you expecting to happen as the consequence of above reproduction steps?]
+
+### Actual Result:
+[What actually happens after the reproduction steps? Include the error output or a link to a gist if possible.]
+
+---
+
+### Feature Request
+
+#### Narrative:
+
+```` text
+As a [role]
+I want [feature]
+So that [benefit]
+````
+
+#### Acceptance Criteria:
+
+```` text
+Scenario 1: Title
+Given [context]
+ And [some more context]...
+When [event]
+Then [outcome]
+ And [another outcome]...
+````
diff --git a/lib/ModbusMaster/.github/PULL_REQUEST_TEMPLATE.md b/lib/ModbusMaster/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 00000000..1039f974
--- /dev/null
+++ b/lib/ModbusMaster/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,37 @@
+
+### Description
+[Describe what this change achieves]
+
+### Issues Resolved
+[List any existing issues this PR resolves; include Fixes #xxx or Closes #xxx (where xxx is issue number)]
+
+### Check List
+
+General
+
+- [ ] Code follows coding style defined in STYLE.md
+- [ ] Doxygen comments are included inline with code
+- [ ] No unnecessary whitespace; check with `git diff --check` before committing.
+
+The following have been modified to reflect new features, if warranted
+
+- [ ] README.md
+- [ ] keywords.txt (use tabs as whitespace separators)
+- [ ] library.properties
+- [ ] examples/ - update or create new ones, as warranted
+
+The following have **NOT** been modified
+
+- [ ] doc/ - will be updated upon versioned release
+- [ ] .ruby-gemset
+- [ ] .ruby-version
+- [ ] CHANGELOG.md - will be updated upon versioned release (HISTORY.md is deprecated)
+- [ ] Gemfile
+- [ ] LICENSE
+- [ ] VERSION - will be updated upon versioned release
diff --git a/lib/ModbusMaster/.github_changelog_generator b/lib/ModbusMaster/.github_changelog_generator
new file mode 100644
index 00000000..1a846259
--- /dev/null
+++ b/lib/ModbusMaster/.github_changelog_generator
@@ -0,0 +1,8 @@
+add_issues_wo_labels=false
+add_pr_wo_labels=false
+enhancement-labels=Type: Enhancement
+bug-labels=Type: Bug
+exclude-labels=Type: Question
+header=# ModbusMaster CHANGELOG
+include-labels=Type: Bug,Type: Enhancement,Type: Feature Request,Type: Maintenance
+future-release=Unreleased
diff --git a/lib/ModbusMaster/.gitignore b/lib/ModbusMaster/.gitignore
new file mode 100644
index 00000000..d52f89eb
--- /dev/null
+++ b/lib/ModbusMaster/.gitignore
@@ -0,0 +1,56 @@
+#---------------------------------------------------------------- ModbusMaster
+doc/html/
+doc/latex/
+
+
+#-------------- https://github.com/github/gitignore/blob/master/Ruby.gitignore
+*.gem
+*.rbc
+/.config
+/coverage/
+/InstalledFiles
+/pkg/
+/spec/reports/
+/spec/examples.txt
+/test/tmp/
+/test/version_tmp/
+/tmp/
+
+# Used by dotenv library to load environment variables.
+# .env
+
+## Specific to RubyMotion:
+.dat*
+.repl_history
+build/
+*.bridgesupport
+build-iPhoneOS/
+build-iPhoneSimulator/
+
+## Specific to RubyMotion (use of CocoaPods):
+#
+# We recommend against adding the Pods directory to your .gitignore. However
+# you should judge for yourself, the pros and cons are mentioned at:
+# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
+#
+# vendor/Pods/
+
+## Documentation cache and generated files:
+/.yardoc/
+/_yardoc/
+/doc/
+/rdoc/
+
+## Environment normalization:
+/.bundle/
+/vendor/bundle
+/lib/bundler/man/
+
+# for a library or gem, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# Gemfile.lock
+# .ruby-version
+# .ruby-gemset
+
+# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
+.rvmrc
diff --git a/lib/ModbusMaster/.ruby-gemset b/lib/ModbusMaster/.ruby-gemset
new file mode 100644
index 00000000..b47d0eb8
--- /dev/null
+++ b/lib/ModbusMaster/.ruby-gemset
@@ -0,0 +1 @@
+global
diff --git a/lib/ModbusMaster/.ruby-version b/lib/ModbusMaster/.ruby-version
new file mode 100644
index 00000000..2bf1c1cc
--- /dev/null
+++ b/lib/ModbusMaster/.ruby-version
@@ -0,0 +1 @@
+2.3.1
diff --git a/lib/ModbusMaster/.travis.yml b/lib/ModbusMaster/.travis.yml
new file mode 100644
index 00000000..a9cbf868
--- /dev/null
+++ b/lib/ModbusMaster/.travis.yml
@@ -0,0 +1,30 @@
+language: python
+
+python:
+ - 2.7
+
+sudo: false
+
+cache:
+ directories:
+ - ~/.platformio
+
+# update Makefile if target boards added
+env:
+ - PLATFORMIO_BOARD=uno
+ - PLATFORMIO_BOARD=due
+ - PLATFORMIO_BOARD=huzzah
+ - PLATFORMIO_BOARD=genuino101
+ - PLATFORMIO_BOARD=teensy31
+
+install:
+ - pip install -U platformio
+
+before_script:
+ - env
+ - echo $HOME
+ - echo $TRAVIS_BUILD_DIR
+ - ls -al $PWD
+
+script:
+ - make build
diff --git a/lib/ModbusMaster/CHANGELOG.md b/lib/ModbusMaster/CHANGELOG.md
new file mode 100644
index 00000000..c5d1fe02
--- /dev/null
+++ b/lib/ModbusMaster/CHANGELOG.md
@@ -0,0 +1,141 @@
+# ModbusMaster CHANGELOG
+
+## [v2.0.0](https://github.com/4-20ma/ModbusMaster/tree/v2.0.0) (2016-09-24)
+[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v1.0.0...v2.0.0)
+
+**Implemented enhancements:**
+
+- BREAK: Update library to match IDE 1.5 spec v2.1 [\#81](https://github.com/4-20ma/ModbusMaster/pull/81) ([4-20ma](https://github.com/4-20ma))
+- Use platformio to build multiple boards [\#79](https://github.com/4-20ma/ModbusMaster/pull/79) ([4-20ma](https://github.com/4-20ma))
+
+**Closed issues:**
+
+- Use platformio to build against multiple boards [\#78](https://github.com/4-20ma/ModbusMaster/issues/78)
+- Add ruby files to .gitignore [\#75](https://github.com/4-20ma/ModbusMaster/issues/75)
+- Reorder Installation section of README [\#73](https://github.com/4-20ma/ModbusMaster/issues/73)
+- Update README [\#71](https://github.com/4-20ma/ModbusMaster/issues/71)
+- Rename HISTORY to CHANGELOG [\#47](https://github.com/4-20ma/ModbusMaster/issues/47)
+- Update library to match 1.5 specification [\#14](https://github.com/4-20ma/ModbusMaster/issues/14)
+
+**Merged pull requests:**
+
+- Use relative path to examples [\#80](https://github.com/4-20ma/ModbusMaster/pull/80) ([4-20ma](https://github.com/4-20ma))
+- Add files to .gitignore [\#76](https://github.com/4-20ma/ModbusMaster/pull/76) ([4-20ma](https://github.com/4-20ma))
+- Reorder installation section of README [\#74](https://github.com/4-20ma/ModbusMaster/pull/74) ([4-20ma](https://github.com/4-20ma))
+- Update README [\#72](https://github.com/4-20ma/ModbusMaster/pull/72) ([4-20ma](https://github.com/4-20ma))
+- Automate CHANGELOG generation [\#68](https://github.com/4-20ma/ModbusMaster/pull/68) ([4-20ma](https://github.com/4-20ma))
+
+## [v1.0.0](https://github.com/4-20ma/ModbusMaster/tree/v1.0.0) (2016-09-12)
+[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.11.0...v1.0.0)
+
+**Implemented enhancements:**
+
+- Add LICENSE, convert project to Apache 2.0 [\#67](https://github.com/4-20ma/ModbusMaster/pull/67) ([4-20ma](https://github.com/4-20ma))
+- Add example sketch for half-duplex RS485 [\#66](https://github.com/4-20ma/ModbusMaster/pull/66) ([kintel](https://github.com/kintel))
+- Add continuous integration testing with Travis CI [\#63](https://github.com/4-20ma/ModbusMaster/pull/63) ([4-20ma](https://github.com/4-20ma))
+- Disable \_\_MODBUSMASTER\_DEBUG\_\_ mode by default [\#43](https://github.com/4-20ma/ModbusMaster/pull/43) ([kintel](https://github.com/kintel))
+
+**Closed issues:**
+
+- Fix documentation references in ModbusMaster.h, .cpp [\#69](https://github.com/4-20ma/ModbusMaster/issues/69)
+- Clean up template wording [\#64](https://github.com/4-20ma/ModbusMaster/issues/64)
+- Add Label section to CONTRIBUTING [\#60](https://github.com/4-20ma/ModbusMaster/issues/60)
+- Update README contact information [\#58](https://github.com/4-20ma/ModbusMaster/issues/58)
+- Add continuous integration testing with travis [\#55](https://github.com/4-20ma/ModbusMaster/issues/55)
+- Add Code of Conduct [\#54](https://github.com/4-20ma/ModbusMaster/issues/54)
+- Create PULL\_REQUEST\_TEMPLATE [\#49](https://github.com/4-20ma/ModbusMaster/issues/49)
+- Create ISSUE\_TEMPLATE [\#48](https://github.com/4-20ma/ModbusMaster/issues/48)
+- Change license to Apache 2.0 [\#45](https://github.com/4-20ma/ModbusMaster/issues/45)
+- Set \_\_MODBUSMASTER\_DEBUG\_\_ to 0 by default [\#35](https://github.com/4-20ma/ModbusMaster/issues/35)
+- Pass Stream object instead of integer reference [\#17](https://github.com/4-20ma/ModbusMaster/issues/17)
+
+**Merged pull requests:**
+
+- Add documentation cross-references [\#70](https://github.com/4-20ma/ModbusMaster/pull/70) ([4-20ma](https://github.com/4-20ma))
+- Clean up ISSUE/PULL\_REQUEST templates [\#65](https://github.com/4-20ma/ModbusMaster/pull/65) ([4-20ma](https://github.com/4-20ma))
+- Add initial .travis.yml configuration [\#62](https://github.com/4-20ma/ModbusMaster/pull/62) ([4-20ma](https://github.com/4-20ma))
+- Add label guidance to CONTRIBUTING [\#61](https://github.com/4-20ma/ModbusMaster/pull/61) ([4-20ma](https://github.com/4-20ma))
+- Update README contact information [\#59](https://github.com/4-20ma/ModbusMaster/pull/59) ([4-20ma](https://github.com/4-20ma))
+- Add email address to CODE\_OF\_CONDUCT [\#57](https://github.com/4-20ma/ModbusMaster/pull/57) ([4-20ma](https://github.com/4-20ma))
+- Add CODE\_OF\_CONDUCT [\#56](https://github.com/4-20ma/ModbusMaster/pull/56) ([4-20ma](https://github.com/4-20ma))
+- Add initial PULL\_REQUEST\_TEMPLATE [\#53](https://github.com/4-20ma/ModbusMaster/pull/53) ([4-20ma](https://github.com/4-20ma))
+- Clarify instructions in ISSUE\_TEMPLATE [\#52](https://github.com/4-20ma/ModbusMaster/pull/52) ([4-20ma](https://github.com/4-20ma))
+- Add ISSUE\_TEMPLATE title reqs, separator lines [\#51](https://github.com/4-20ma/ModbusMaster/pull/51) ([4-20ma](https://github.com/4-20ma))
+- Add initial ISSUE\_TEMPLATE [\#50](https://github.com/4-20ma/ModbusMaster/pull/50) ([4-20ma](https://github.com/4-20ma))
+- Add preTransmission\(\), postTransmission\(\) for half-duplex [\#44](https://github.com/4-20ma/ModbusMaster/pull/44) ([kintel](https://github.com/kintel))
+- Add STYLE coding style guide [\#29](https://github.com/4-20ma/ModbusMaster/pull/29) ([4-20ma](https://github.com/4-20ma))
+
+## [v0.11.0](https://github.com/4-20ma/ModbusMaster/tree/v0.11.0) (2015-05-22)
+[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.10.3...v0.11.0)
+
+**Implemented enhancements:**
+
+- Update architecture switch [\#28](https://github.com/4-20ma/ModbusMaster/pull/28) ([4-20ma](https://github.com/4-20ma))
+
+**Closed issues:**
+
+- Update architecture switch to match Arduino convention [\#27](https://github.com/4-20ma/ModbusMaster/issues/27)
+- Request timeout is impatient [\#3](https://github.com/4-20ma/ModbusMaster/issues/3)
+
+## [v0.10.3](https://github.com/4-20ma/ModbusMaster/tree/v0.10.3) (2015-05-22)
+[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.10.2...v0.10.3)
+
+**Closed issues:**
+
+- Inconsistent Doxygen comments [\#25](https://github.com/4-20ma/ModbusMaster/issues/25)
+- Replace C macros with inline functions [\#18](https://github.com/4-20ma/ModbusMaster/issues/18)
+
+**Merged pull requests:**
+
+- Adjust doxygen comments to be consistent [\#26](https://github.com/4-20ma/ModbusMaster/pull/26) ([4-20ma](https://github.com/4-20ma))
+- Replace C macros w/inline functions [\#24](https://github.com/4-20ma/ModbusMaster/pull/24) ([4-20ma](https://github.com/4-20ma))
+
+## [v0.10.2](https://github.com/4-20ma/ModbusMaster/tree/v0.10.2) (2015-05-22)
+[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.9.1...v0.10.2)
+
+**Implemented enhancements:**
+
+- Implement CRC16 for SAM3X8E microprocessor [\#11](https://github.com/4-20ma/ModbusMaster/pull/11) ([4-20ma](https://github.com/4-20ma))
+- Add rx flush, change response timeout to 2000 ms [\#10](https://github.com/4-20ma/ModbusMaster/pull/10) ([agprimatic](https://github.com/agprimatic))
+
+**Fixed bugs:**
+
+- Fix documentation build error [\#23](https://github.com/4-20ma/ModbusMaster/pull/23) ([4-20ma](https://github.com/4-20ma))
+- Work around HardwareSerial for SAM3 micro [\#12](https://github.com/4-20ma/ModbusMaster/pull/12) ([4-20ma](https://github.com/4-20ma))
+
+**Merged pull requests:**
+
+- Update pointers to match C++ convention [\#22](https://github.com/4-20ma/ModbusMaster/pull/22) ([4-20ma](https://github.com/4-20ma))
+- Rename markdown file extensions [\#21](https://github.com/4-20ma/ModbusMaster/pull/21) ([4-20ma](https://github.com/4-20ma))
+
+## [v0.9.1](https://github.com/4-20ma/ModbusMaster/tree/v0.9.1) (2013-01-02)
+[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.9...v0.9.1)
+
+## [v0.9](https://github.com/4-20ma/ModbusMaster/tree/v0.9) (2011-12-27)
+[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.8...v0.9)
+
+## [v0.8](https://github.com/4-20ma/ModbusMaster/tree/v0.8) (2011-11-09)
+[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.7...v0.8)
+
+## [v0.7](https://github.com/4-20ma/ModbusMaster/tree/v0.7) (2010-02-10)
+[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.6...v0.7)
+
+## [v0.6](https://github.com/4-20ma/ModbusMaster/tree/v0.6) (2010-02-05)
+[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.5...v0.6)
+
+## [v0.5](https://github.com/4-20ma/ModbusMaster/tree/v0.5) (2010-01-30)
+[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.4...v0.5)
+
+## [v0.4](https://github.com/4-20ma/ModbusMaster/tree/v0.4) (2010-01-30)
+[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.3...v0.4)
+
+## [v0.3](https://github.com/4-20ma/ModbusMaster/tree/v0.3) (2010-01-29)
+[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.2...v0.3)
+
+## [v0.2](https://github.com/4-20ma/ModbusMaster/tree/v0.2) (2010-01-26)
+[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.1...v0.2)
+
+## [v0.1](https://github.com/4-20ma/ModbusMaster/tree/v0.1) (2010-01-25)
+
+
+\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
\ No newline at end of file
diff --git a/lib/ModbusMaster/CODE_OF_CONDUCT.md b/lib/ModbusMaster/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..eca5ac5b
--- /dev/null
+++ b/lib/ModbusMaster/CODE_OF_CONDUCT.md
@@ -0,0 +1,78 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level of experience,
+nationality, personal appearance, race, religion, or sexual identity and
+orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project owner at 4-20ma@wvfans.net. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Project Maintainers
+
+- Doc Walker <<4-20ma@wvfans.net>>
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
diff --git a/lib/ModbusMaster/CONTRIBUTING.md b/lib/ModbusMaster/CONTRIBUTING.md
new file mode 100644
index 00000000..0bcf721a
--- /dev/null
+++ b/lib/ModbusMaster/CONTRIBUTING.md
@@ -0,0 +1,58 @@
+Contributing
+============
+
+- Fork, then clone the repo:
+ ````
+ git clone git@github.com:your_username/ModbusMaster.git
+ ````
+
+- Create a topic branch from where you want to base your work
+ - This is usually the master branch
+ - Only target release branches if you are certain your fix must be on that branch
+ - To quickly create a topic branch based on master; `git checkout -b fix/master/my_contribution master`. Please avoid working directly on the `master` branch.
+
+- Follow the [style guide](https://github.com/4-20ma/ModbusMaster/blob/master/STYLE.md)
+
+- Test your change
+
+ ```` bash
+ $ make
+ ````
+
+ Project must build successfully using `make` in order for contribution to be considered.
+
+- Make commits of logical units
+ - Check for unnecessary whitespace with `git diff --check` before committing
+ - Each commit should represent one atomic change and should stand on its own
+ - Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
+
+- Push to your fork and [submit a pull request](https://github.com/4-20ma/ModbusMaster/compare/)
+- [Code of conduct](https://github.com/4-20ma/ModbusMaster/blob/master/CODE_OF_CONDUCT.md)
+
+### Labels
+
+Project maintainers assign labels to Issues and Pull Requests (PRs) to categorize, prioritize, and provide status. The following guidelines and conventions are used in this project:
+
+#### Type
+
+- `Bug` - existing code does not behave as described in the project documentation; _requires_ clear test case and be _reproducible_ by project maintainer
+- `Enhancement` - improvement to an existing feature (Issue or Pull Request)
+- `Feature Requst` - new functionality; _requires_ a well-written, clear user story (Issue)
+- `Maintenance` - minor administrative change that does not provide enhancement or introduce new feature
+- `Question` - self-explanatory
+
+#### Priority
+
+- `Low` - default priority; new issues generally start here
+- `Medium` - issues are escalated, depending on severity of the issue
+- `High` - issues are escalated, depending on severity of the issue
+- `Critical` - these issues are to be resolved ahead of any other
+
+#### Status
+
+- `Abandoned` - issue/PR closed due to inactivity
+- `Blocked` - issue/PR will not be resolved/merged (some projects label these items as `wontfix`; include explanation in issue/PR)
+- `In Progress` - issue has been assigned and is actively being addressed; re-label issue `On Hold` with explanation if there will be a significant delay
+- `Maintainer Review Needed` - last step prior to merge; PR passes continuous integration tests and is able to be cleanly merged - awaiting review for style, code cleanliness, etc.
+- `On Hold` - implementation delayed; provide explanation in issue/PR
+- `Pending Contributor Response` - issue/PR closed after 14 days of inactivity (re-label `Abandoned` at closure)
diff --git a/lib/ModbusMaster/Gemfile b/lib/ModbusMaster/Gemfile
new file mode 100644
index 00000000..9ed64664
--- /dev/null
+++ b/lib/ModbusMaster/Gemfile
@@ -0,0 +1,30 @@
+# encoding: utf-8
+# Gemfile style guide derived from:
+# http://mcdowall.info/posts/gemfile-best-practices-and-discourse/
+
+# Use `bundle install` after changing this file
+# `bundle update [gemname]` to force update of gem
+# `bundle show [gemname]` to see where a bundled gem is installed
+# `bundle open [gemname]` to edit a bundled gem
+# `bundle package` to add gem to vendor/cache
+
+source 'https://rubygems.org'
+
+
+# place gems sourced from github.com in this section _________________________
+
+
+# place gems sourced from a project path in this section _____________________
+
+
+# place general project gems in this section (alphabetical order) ____________
+gem 'git', '~> 1.3.0' # git management
+gem 'github_changelog_generator', '~> 1.13.1'
+gem 'rake', '~> 11.2.2'
+gem 'version', '~> 1.0.0' # version management gem
+
+
+# place gems related to test/specs in this section (alphabetical order) ______
+
+
+# place gems related to development in this section (alphabetical order) _____
diff --git a/lib/ModbusMaster/Gemfile.lock b/lib/ModbusMaster/Gemfile.lock
new file mode 100644
index 00000000..cdec1471
--- /dev/null
+++ b/lib/ModbusMaster/Gemfile.lock
@@ -0,0 +1,47 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ addressable (2.4.0)
+ colorize (0.8.1)
+ descendants_tracker (0.0.4)
+ thread_safe (~> 0.3, >= 0.3.1)
+ faraday (0.9.2)
+ multipart-post (>= 1.2, < 3)
+ git (1.3.0)
+ github_api (0.14.5)
+ addressable (~> 2.4.0)
+ descendants_tracker (~> 0.0.4)
+ faraday (~> 0.8, < 0.10)
+ hashie (>= 3.4)
+ oauth2 (~> 1.0)
+ github_changelog_generator (1.13.1)
+ colorize (~> 0.7)
+ github_api (~> 0.12)
+ rake (>= 10.0)
+ hashie (3.4.4)
+ jwt (1.5.4)
+ multi_json (1.12.1)
+ multi_xml (0.5.5)
+ multipart-post (2.0.0)
+ oauth2 (1.2.0)
+ faraday (>= 0.8, < 0.10)
+ jwt (~> 1.0)
+ multi_json (~> 1.3)
+ multi_xml (~> 0.5)
+ rack (>= 1.2, < 3)
+ rack (2.0.1)
+ rake (11.2.2)
+ thread_safe (0.3.5)
+ version (1.0.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ git (~> 1.3.0)
+ github_changelog_generator (~> 1.13.1)
+ rake (~> 11.2.2)
+ version (~> 1.0.0)
+
+BUNDLED WITH
+ 1.12.1
diff --git a/lib/ModbusMaster/LICENSE b/lib/ModbusMaster/LICENSE
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/lib/ModbusMaster/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/lib/ModbusMaster/Makefile b/lib/ModbusMaster/Makefile
new file mode 100644
index 00000000..fba3392d
--- /dev/null
+++ b/lib/ModbusMaster/Makefile
@@ -0,0 +1,19 @@
+#-------------------------------------------------------------------- settings
+FIND := find
+DIR := examples
+CRITERIA := \( -name "*.ino" -o -name "*.pde" \)
+EACH_EXAMPLE := $(FIND) $(DIR) $(CRITERIA) -exec
+BUILD := platformio ci
+LIB := src
+
+#--------------------------------------------------------------------- targets
+# update .travis.yml if target boards added
+all: uno due huzzah genuino101 teensy31
+
+uno due huzzah genuino101 teensy31:
+ PLATFORMIO_BOARD=$@ $(MAKE) build
+
+build:
+ $(EACH_EXAMPLE) $(BUILD) --board=$(PLATFORMIO_BOARD) --lib=$(LIB) {} \;
+
+.PHONY: all uno due huzzah genuino101 teensy31 build
diff --git a/lib/ModbusMaster/README.md b/lib/ModbusMaster/README.md
new file mode 100644
index 00000000..5c5719e4
--- /dev/null
+++ b/lib/ModbusMaster/README.md
@@ -0,0 +1,167 @@
+# ModbusMaster
+[][GitHub release]
+[][Travis]
+[][license]
+[][code of conduct]
+
+[GitHub release]: https://github.com/4-20ma/ModbusMaster
+[Travis]: https://travis-ci.org/4-20ma/ModbusMaster
+[license]: LICENSE
+[code of conduct]: CODE_OF_CONDUCT.md
+
+
+## Overview
+This is an Arduino library for communicating with Modbus slaves over RS232/485 (via RTU protocol).
+
+
+## Features
+The following Modbus functions are available:
+
+Discrete Coils/Flags
+
+ - 0x01 - Read Coils
+ - 0x02 - Read Discrete Inputs
+ - 0x05 - Write Single Coil
+ - 0x0F - Write Multiple Coils
+
+Registers
+
+ - 0x03 - Read Holding Registers
+ - 0x04 - Read Input Registers
+ - 0x06 - Write Single Register
+ - 0x10 - Write Multiple Registers
+ - 0x16 - Mask Write Register
+ - 0x17 - Read Write Multiple Registers
+
+Both full-duplex and half-duplex RS232/485 transceivers are supported. Callback functions are provided to toggle Data Enable (DE) and Receiver Enable (/RE) pins.
+
+
+## Installation
+
+#### Library Manager
+Install the library into your Arduino IDE using the Library Manager (available from IDE version 1.6.2). Open the IDE and click Sketch > Include Library > Manage Libraries…
+
+Scroll or search for `ModbusMaster`, then select the version of the library you want to install. Quit/re-launch the IDE to refresh the list; new versions are automatically added to the list, once released on GitHub.
+
+Refer to Arduino Tutorials > Libraries [Using the Library Manager](https://www.arduino.cc/en/Guide/Libraries#toc3).
+
+#### Zip Library
+Refer to Arduino Tutorials > Libraries [Importing a .zip Library](https://www.arduino.cc/en/Guide/Libraries#toc4).
+
+#### Manual
+Refer to Arduino Tutorials > Libraries [Manual Installation](https://www.arduino.cc/en/Guide/Libraries#toc5).
+
+
+## Hardware
+This library has been tested with an Arduino [Duemilanove](http://www.arduino.cc/en/Main/ArduinoBoardDuemilanove), PHOENIX CONTACT [nanoLine](https://www.phoenixcontact.com/online/portal/us?1dmy&urile=wcm%3apath%3a/usen/web/main/products/subcategory_pages/standard_logic_modules_p-21-03-03/3329dd38-7c6a-46e1-8260-b9208235d6fe/3329dd38-7c6a-46e1-8260-b9208235d6fe) controller, connected via RS485 using a Maxim [MAX488EPA](http://www.maxim-ic.com/quick_view2.cfm/qv_pk/1111) transceiver.
+
+
+## Caveats
+Conforms to Arduino IDE 1.5 Library Specification v2.1 which requires Arduino IDE >= 1.5.
+
+Arduinos prior to the Mega have one serial port which must be connected to USB (FTDI) for uploading sketches and to the RS232/485 device/network for running sketches. You will need to disconnect pin 0 (RX) while uploading sketches. After a successful upload, you can reconnect pin 0.
+
+
+## Support
+Please [submit an issue](https://github.com/4-20ma/ModbusMaster/issues) for all questions, bug reports, and feature requests. Email requests will be politely redirected to the issue tracker so others may contribute to the discussion and requestors get a more timely response.
+
+
+## Example
+The library contains a few sketches that demonstrate use of the `ModbusMaster` library. You can find these in the [examples](https://github.com/4-20ma/ModbusMaster/tree/master/examples) folder.
+
+``` cpp
+/*
+
+ Basic.pde - example using ModbusMaster library
+
+ Library:: ModbusMaster
+ Author:: Doc Walker <4-20ma@wvfans.net>
+
+ Copyright:: 2009-2016 Doc Walker
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+#include
+
+
+// instantiate ModbusMaster object
+ModbusMaster node;
+
+
+void setup()
+{
+ // use Serial (port 0); initialize Modbus communication baud rate
+ Serial.begin(19200);
+
+ // communicate with Modbus slave ID 2 over Serial (port 0)
+ node.begin(2, Serial);
+}
+
+
+void loop()
+{
+ static uint32_t i;
+ uint8_t j, result;
+ uint16_t data[6];
+
+ i++;
+
+ // set word 0 of TX buffer to least-significant word of counter (bits 15..0)
+ node.setTransmitBuffer(0, lowWord(i));
+
+ // set word 1 of TX buffer to most-significant word of counter (bits 31..16)
+ node.setTransmitBuffer(1, highWord(i));
+
+ // slave: write TX buffer to (2) 16-bit registers starting at register 0
+ result = node.writeMultipleRegisters(0, 2);
+
+ // slave: read (6) 16-bit registers starting at register 2 to RX buffer
+ result = node.readHoldingRegisters(2, 6);
+
+ // do something with data if read is successful
+ if (result == node.ku8MBSuccess)
+ {
+ for (j = 0; j < 6; j++)
+ {
+ data[j] = node.getResponseBuffer(j);
+ }
+ }
+}
+```
+
+_Project inspired by [Arduino Modbus Master](http://sites.google.com/site/jpmzometa/arduino-mbrt/arduino-modbus-master)._
+
+
+## License & Authors
+
+- Author:: Doc Walker ([4-20ma@wvfans.net](mailto:4-20ma@wvfans.net))
+- Author:: Ag Primatic ([agprimatic@gmail.com](mailto:agprimatic@gmail.com))
+- Author:: Marius Kintel ([marius@kintel.net](mailto:marius@kintel.net))
+
+```
+Copyright:: 2009-2016 Doc Walker
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+```
diff --git a/lib/ModbusMaster/Rakefile b/lib/ModbusMaster/Rakefile
new file mode 100644
index 00000000..b0619918
--- /dev/null
+++ b/lib/ModbusMaster/Rakefile
@@ -0,0 +1,218 @@
+# encoding: utf-8
+#
+# Copyright:: 2009-2016 Doc Walker
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'git'
+require 'github_changelog_generator/task'
+require 'rake'
+require 'rubygems'
+require 'rake/version_task' # gem install version
+require 'version'
+
+# requires additional packages on MacOS (including Homebrew):
+# $ /usr/bin/ruby -e "$(curl -fsSL \
+# https://raw.githubusercontent.com/Homebrew/install/master/install)"
+# $ brew install doxygen # generates documentation from source code
+# $ brew cask install mactex # MacTeX
+
+Rake::VersionTask.new do |task|
+ # prevent auto-commit on version bump
+ task.with_git = false
+end
+
+# adjust as appropriate
+CWD = File.expand_path(File.dirname(__FILE__))
+DOXYFILE = 'Doxyfile'
+GITHUB_USERNAME = '4-20ma'
+GITHUB_REPO = 'ModbusMaster'
+HEADER_FILE = "#{GITHUB_REPO}.h"
+CHANGELOG_FILE = 'CHANGELOG.md'
+PROPERTIES_FILE = 'library.properties'
+VERSION_FILE = Version.version_file('').basename.to_s
+
+
+task :default => :info
+
+desc 'Display instructions for public release'
+task :info do
+ puts <<-EOF.gsub(/^\s{2}/, '')
+
+ Instructions for public release
+
+ - Update version, as appropriate:
+
+ $ rake version:bump # or
+ $ rake version:bump:minor # or
+ $ rake version:bump:major # or
+ edit 'VERSION' file directly
+
+ - Prepare release date, 'CHANGELOG.md' file, documentation:
+
+ $ rake prepare
+
+ - Review changes to 'CHANGELOG.md' file
+ This file is assembled using git commit messages; review for completeness.
+
+ - Review html documentation files
+ These files are assembled using source code Doxygen tags; review for
+ for completeness.
+
+ - Add & commit source files, tag, push to origin/master;
+ add & commit documentation files, push to origin/gh-pages:
+
+ $ rake release
+
+ EOF
+end # task :info
+
+
+desc "Prepare #{CHANGELOG_FILE} for release"
+task :prepare => 'prepare:default'
+
+namespace :prepare do
+ task :default => [
+ :release_date,
+ :library_properties,
+ :changelog,
+ :documentation
+ ]
+
+ desc 'Prepare documentation'
+ task :documentation do
+ version = Version.current.to_s
+
+ # update parameters in Doxyfile
+ file = File.join(CWD, 'doc', DOXYFILE)
+
+ contents = IO.read(file)
+ contents.sub!(/(^PROJECT_NUMBER\s*=)(.*)$/) do |match|
+ "#{$1} v#{version}"
+ end # contents.sub!(...)
+ IO.write(file, contents)
+
+ # chdir to doc/ and call doxygen to update documentation
+ Dir.chdir(to = File.join(CWD, 'doc'))
+ system('doxygen', DOXYFILE)
+
+ # chdir to doc/latex and call doxygen to update documentation
+ Dir.chdir(from = File.join(CWD, 'doc', 'latex'))
+ system('make')
+
+ # move/rename file to 'extras/GITHUB_REPO reference-x.y.pdf'
+ to = File.join(CWD, 'extras')
+ FileUtils.mv(File.join(from, 'refman.pdf'),
+ File.join(to, "#{GITHUB_REPO} reference-#{version}.pdf"))
+ end # task :documentation
+
+ desc 'Prepare release history'
+ GitHubChangelogGenerator::RakeTask.new(:changelog) do |config|
+ config.add_issues_wo_labels = false
+ config.add_pr_wo_labels = false
+ config.enhancement_labels = [
+ 'Type: Enhancement'
+ ]
+ config.bug_labels = ['Type: Bug']
+ config.exclude_labels = ['Type: Question']
+ config.header = '# ModbusMaster CHANGELOG'
+ config.include_labels = [
+ 'Type: Bug',
+ 'Type: Enhancement',
+ 'Type: Feature Request',
+ 'Type: Maintenance'
+ ]
+ # config.since_tag = '0.1.0'
+ config.future_release = "v#{Version.current.to_s}"
+ config.user = GITHUB_USERNAME
+ config.project = GITHUB_REPO
+ end # GitHubChangelogGenerator::RakeTask.new
+
+ desc 'Update version in library properties file'
+ task :library_properties do
+ version = Version.current.to_s
+
+ file = File.join(CWD, PROPERTIES_FILE)
+
+ contents = IO.read(file)
+ contents.sub!(/(version=\s*)(.*)$/) do |match|
+ "#{$1}#{version}"
+ end # contents.sub!(...)
+ IO.write(file, contents)
+ end # task :library_properties
+
+ desc 'Update release date in header file'
+ task :release_date do
+ file = File.join(CWD, 'src', HEADER_FILE)
+
+ contents = IO.read(file)
+ contents.sub!(/(\\date\s*)(.*)$/) do |match|
+ "#{$1}#{Time.now.strftime('%-d %b %Y')}"
+ end # contents.sub!(...)
+ IO.write(file, contents)
+ end # task :release_date
+
+end # namespace :prepare
+
+
+desc 'Release source & documentation'
+task :release => 'release:default'
+
+namespace :release do
+ task :default => [:source, :documentation]
+
+ desc 'Commit documentation changes related to version bump'
+ task :documentation do
+ version = Version.current.to_s
+ cwd = File.expand_path(File.join(File.dirname(__FILE__), 'doc', 'html'))
+ g = Git.open(cwd)
+
+ # `git add .`
+ g.add
+
+ # remove each deleted item
+ g.status.deleted.each do |item|
+ g.remove(item[0])
+ end # g.status.deleted.each
+
+ # commit changes if items added, changed, or deleted
+ if g.status.added.size > 0 || g.status.changed.size > 0 ||
+ g.status.deleted.size > 0 then
+ message = "Update documentation for v#{version}"
+ puts g.commit(message)
+ else
+ puts "No changes to commit v#{version}"
+ end # if g.status.added.size > 0 || g.status.changed.size > 0...
+
+ g.push('origin', 'gh-pages')
+ end # task :documentation
+
+ desc 'Commit source changes related to version bump'
+ task :source do
+ version = Version.current.to_s
+ `git add \
+ doc/#{DOXYFILE} \
+ "extras/#{GITHUB_REPO} reference-#{version}.pdf" \
+ src/#{HEADER_FILE} \
+ #{CHANGELOG_FILE} \
+ #{PROPERTIES_FILE} \
+ #{VERSION_FILE} \
+ `
+ `git commit -m 'Version bump to v#{version}'`
+ `git tag -a -f -m 'Version v#{version}' v#{version}`
+ `git push origin master`
+ `git push --tags`
+ end # task :source
+
+end # namespace :release
diff --git a/lib/ModbusMaster/STYLE.md b/lib/ModbusMaster/STYLE.md
new file mode 100644
index 00000000..00516e0f
--- /dev/null
+++ b/lib/ModbusMaster/STYLE.md
@@ -0,0 +1,372 @@
+ModbusMaster Style Guide
+========================
+
+The following references provide sound guidance for writing C/C++ code for the Arduino platform.
+
+- [Arduino API Style Guide (AASG)](http://www.arduino.cc/en/Reference/APIStyleGuide)
+- [Bjarne Stroustrup's C++ Style Guide](http://www.stroustrup.com/bs_faq2.html)
+- [JSF Air Vehicle C++ Coding Standards (JSFAV)](http://www.stroustrup.com/JSF-AV-rules.pdf)
+
+Opinions about style and generally accepted usage patterns may vary widely. I've carefully chosen a few key items to emphasize and enforce for this library in order to promote readability, usability, and safe coding practices. **Pull requests will follow these guidelines in order to be considered**.
+
+
+General \[AASG\]
+-------
+
+Use the established Arduino core libraries and styles.
+
+- Use `read()` to read inputs, and `write()` to write to outputs, e.g. `digitalRead()`, `analogWrite()`, etc.
+- Use the `Stream.h` and `Print.h` libraries when dealing with byte streams. If it’s not appropriate, at least try to use its API as a model. For more on this, see below.
+- For network applications, use the Client and Server libraries as the basis.
+- Use `begin()` to initialize a library instance, usually with some settings. Use `end()` to stop it.
+- Use camelCase function names, not underscore. For example, `analogRead`, not `analog_read`. Or `myNewFunction`, not `my_new_function`. We've adopted this from Processing.org for readability's sake. Refer to AV Rule 45 and AV Rule 51.
+- When using serial communication, allow the user to specify any `Stream` object, rather than hard-coding `Serial`. This will make the library compatible with all serial ports on Mega and the Due, and can also use alternate interfaces like `SoftwareSerial`. The `Stream` object can be passed to the library's constructor or to a `begin()` function (as a reference, not a pointer). See Firmata 2.3 or XBee 0.4 for examples of each approach.
+
+
+Rules \[JSFAV 4.2\]
+-----
+
+#### Should, Will, and Shall Rules
+
+There are three types of rules: **should**, **will**, and **shall** rules. Each rule contains either a **"should"**, **"will"** or a **"shall"** in bold letters indicating its type.
+
+- **Should** rules are advisory rules. They strongly suggest the recommended way of doing things.
+- **Will** rules are intended to be mandatory requirements. It is expected that they will be followed, but they do not require verification. They are limited to non-safety-critical requirements that cannot be easily verified (e.g., naming conventions).
+- **Shall** rules are mandatory requirements. They must be followed and they require verification (either automatic or manual).
+
+
+Pre-Processing Directives \[JSFAV 4.6\]
+-------------------------
+Since the pre-processor knows nothing about C++, it should not be used to do what can otherwise be done in C++.
+
+- AV Rule 26
+
+ Only the following pre-processor directives shall be used:
+
+ 1. `#ifndef`
+ 1. `#define`
+ 1. `#endif`
+ 1. `#include`
+
+ **Rationale**: Limit the use of the pre-processor to those cases where it is necessary.
+
+#### \#ifndef and \#endif Pre-Processing Directives
+
+- AV Rule 27
+
+ `#ifndef`, `#define` and `#endif` **will** be used to prevent multiple inclusions of the same header file. Other techniques to prevent the multiple inclusions of header files **will not** be used.
+
+ **Rationale**: Eliminate multiple inclusions of the same header file in a standard way.
+
+- AV Rule 28
+
+ The `#ifndef` and `#endif` pre-processor directives **will** only be used as defined in AV Rule 27 to prevent multiple inclusions of the same header file.
+
+ **Rationale**: Conditional code compilation should be kept to a minimum as it can significantly obscure testing and maintenance efforts.
+
+#### \#define Pre-Processing Directive
+
+- AV Rule 29
+
+ The `#define` pre-processor directive **shall not** be used to create inline macros. Inline functions **shall** be used instead.
+
+ **Rationale**: Inline functions do not require text substitutions and behave well when called with arguments (e.g. type checking is performed).
+
+- AV Rule 30
+
+ The `#define` pre-processor directive **shall not** be used to define constant values. Instead, the `const` qualifier shall be applied to variable declarations to specify constant values.
+
+ **Rationale**: `const` variables follow scope rules, are subject to type checking and do not require text substitutions (which can be confusing or misleading).
+
+- AV Rule 31
+
+ The `#define` pre-processor directive **will** only be used as part of the technique to prevent multiple inclusions of the same header file.
+
+ **Rationale**: `#define` can be used to specify conditional compilation (AV Rule 27 and AV Rule 28), inline macros (AV Rule 29) and constants (AV Rule 30). This rule specifies that the only allowable use of `#define` is to prevent multiple includes of the same header file (AV Rule 27).
+
+#### \#include Pre-Processing Directive
+
+- AV Rule 32
+
+ The `#include` pre-processor directive **will** only be used to include header (\*.h) files.
+
+ **Rationale**: Clarity. The only files included in a .cpp file should be the relevant header (\*.h) files.
+
+
+Header Files \[JSFAV 4.7\]
+------------
+
+- AV Rule 33
+
+ The `#include` directive **shall** use the `` notation to include header files.
+
+ **Rationale**: The include form `"filename.h"` is typically used to include local header files. However, due to the unfortunate divergence in vendor implementations, only the `` form will be used.
+
+- AV Rule 35
+
+ A header file **will** contain a mechanism that prevents multiple inclusions of itself.
+
+ **Rationale**: Avoid accidental header file recursion. Note AV Rule 27 specifies the mechanism by which multiple inclusions are to be eliminated whereas this rule (AV Rule 35) specifies that each header file must use that mechanism.
+
+- AV Rule 37
+
+ Header (include) files **should** include only those header files that are required for them to successfully compile. Files that are only used by the associated .cpp file should be placed in the .cpp file—not the .h file.
+
+ **Rationale**: The `#include` statements in a header file define the dependencies of the file. Fewer dependencies imply looser couplings and hence a smaller ripple-effect when the header file is required to change.
+
+
+Style \[JSFAV 4.9\]
+-----
+Imposing constraints on the format of syntactic elements makes source code easier to read due to consistency in form and appearance.
+
+- AV Rule 41 (modified)
+
+ Source lines **will** be kept to a length of 78 characters or less.
+
+ **Rationale**: Readability and style. Very long source lines can be difficult to read and understand.
+
+- AV Rule 42
+
+ Each expression-statement **will** be on a separate line.
+
+ **Rationale**: Simplicity, readability, and style.
+
+- AV Rule 43 (modified)
+
+ Tabs **will** be avoided.
+
+ **Rationale**: Tabs are interpreted differently across various editors and printers.
+
+- AV Rule 44
+
+ All indentations **will** be at least two spaces and be consistent within the same source file.
+
+ **Rationale**: Readability and style.
+
+#### Naming Identifiers
+
+The choice of identifier names should:
+
+- Suggest the usage of the identifier.
+- Consist of a descriptive name that is short yet meaningful.
+- Be long enough to avoid name conflicts, but not excessive in length.
+- Include abbreviations that are generally accepted.
+
+Note: In general, the above guidelines should be followed. However, conventional usage of simple identifiers (i, x, y, p, etc.) in small scopes can lead to cleaner code and will therefore be permitted.
+
+Additionally, the term ‘word’ in the following naming convention rules may be used to refer to a word, an acronym, an abbreviation, or a number.
+
+- AV Rule 45
+
+ All words in an identifier **will** be separated by the '\_' character.
+
+ **Exception**: Function names follow the camelCase convention according to the Arduino API Style Guide. Refer to AV Rule 51.
+
+ **Rationale**: Readability and Style.
+
+- AV Rule 47 (modified)
+
+ Identifiers **should not** begin with the underscore character '\_'.
+
+ **Exception**: Currently, private members of the `ModbusMaster` class begin with '\_'.
+
+ **Rationale**: '\_' is often used as the first character in the name of library functions (e.g. `_main`, `_exit`, etc.) In order to avoid name collisions, identifiers should not begin with '\_'.
+
+- AV Rule 49
+
+ All acronyms in an identifier **will** be composed of uppercase letters.
+
+ Note: An acronym will always be in uppercase, even if the acronym is located in a portion of an identifier that is specified to be lowercase by other rules.
+
+ **Rationale**: Readability.
+
+- AV Rule 50
+
+ The first word of the name of a class, structure, namespace, enumeration, or type created with typedef **will** begin with an uppercase letter. All others letters will be lowercase.
+
+ **Rationale**: Style.
+
+ **Exception**: The first letter of a typedef name may be in lowercase in order to conform to a standard library interface or when used as a replacement for fundamental types.
+
+- AV Rule 51 (modified)
+
+ All letters contained in *function* names **will** be composed of a mix of lowercase and uppercase letters in camelCase format (e.g. first letter of first word is lowercase and first letter of each subsequent word is uppercase). This is to maintain consistency with the Arduion API Style Guide. Refer to AV Rule 45.
+
+ All letters contained in *variable* names **will** be composed entirely of lowercase letters.
+
+ **Rationale**: Style.
+
+- AV Rule 52
+
+ Identifiers for constant and enumerator values **shall** be lowercase.
+
+ **Rationale**: Although it is an accepted convention to use uppercase letters for constants and enumerators, it is possible for third party libraries to replace constant/enumerator names as part of the macro substitution process (macros are also typically represented with uppercase letters).
+
+#### Classes
+
+- AV Rule 57
+
+ The public, protected, and private sections of a class **will** be declared in that order (the public section is declared before the protected section which is declared before the private section).
+
+ **Rationale**: By placing the public section first, everything that is of interest to a user is gathered in the beginning of the class definition. The protected section may be of interest to designers when considering inheriting from the class. The private section contains details that should be of the least general interest.
+
+#### Functions
+
+- AV Rule 58
+
+ When declaring and defining functions with more than two parameters, the leading parenthesis and the first argument **will** be written on the same line as the function name. Each additional argument will be written on a separate line (with the closing parenthesis directly after the last argument).
+
+ **Rationale**: Readability and style.
+
+#### Blocks
+
+- AV Rule 59
+
+ The statements forming the body of an `if`, `else if`, `else`, `while`, `do...while` or `for` statement **shall** always be enclosed in braces, even if the braces form an empty block.
+
+ **Rationale**: Readability. It can be difficult to see ';' when it appears by itself.
+
+- AV Rule 60
+
+ Braces ('{}') which enclose a block will be placed in the same column, on separate lines directly before and after the block.
+
+ **Example**:
+ ```
+ if (var_name == true)
+ {
+ }
+ else
+ {
+ }
+ ```
+
+- AV Rule 61
+
+ Braces ('{}') which enclose a block **will** have nothing else on the line except comments (if necessary).
+
+#### Pointers and References
+
+- AV Rule 62
+
+ The dereference operator '\*' and the address-of operator '&' **will** be directly connected with the type-specifier.
+
+ **Rationale**: The `int32* p;` form emphasizes type over syntax while the `int32 *p;` form emphasizes syntax over type. Although both forms are equally valid C++, the heavy emphasis on types in C++ suggests that `int32* p;` is the preferable form.
+
+ **Examples**:
+ ```
+ int32* p; // correct
+ int32 *p; // incorrect
+ int32* p, q; // probable error
+ ```
+
+#### Miscellaneous
+
+- AV Rule 63
+
+ Spaces **will not** be used around '.' or '->', nor between unary operators and operands.
+
+ **Rationale**: Readability and style.
+
+
+Classes \[JSFAV 4.10\]
+-------
+
+#### const Member Functions
+
+- AV Rule 69
+
+ A member function that does not affect the state of an object (its instance variables) **will** be declared `const`.
+
+ Member functions should be `const` by default. Only when there is a clear, explicit reason should the `const` modifier on member functions be omitted.
+
+ **Rationale**: Declaring a member function `const` is a means of ensuring that objects will not be modified when they should not. Furthermore, C++ allows member functions to be overloaded on their `const`-ness.
+
+
+Initialization \[JSFAV 4.16\]
+--------------
+
+- AV Rule 142
+
+ All variables **shall** be initialized before use.
+
+ **Rationale**: Prevent the use of variables before they have been properly initialized.
+
+- AV Rule 143
+
+ Variables **will not** be introduced until they can be initialized with meaningful values.
+
+ **Rationale**: Prevent clients from accessing variables without meaningful values.
+
+
+Constants \[JSFAV 4.18\]
+---------
+
+- AV Rule 149
+
+ Octal constants (other than zero) **shall not** be used.
+
+ **Rationale**: Any integer constant beginning with a zero ('0') is defined by the C++ standard to be an octal constant. Due to the confusion this causes, octal constants should be avoided.
+
+ Note: Hexadecimal numbers and zero (which is also an octal constant) are allowed.
+
+- AV Rule 150
+
+ Hexadecimal constants **will** be represented using all uppercase letters.
+
+
+Variables \[JSFAV 4.19\]
+---------
+
+- AV Rule 152
+
+ Multiple variable declarations **shall not** be allowed on the same line.
+
+ **Rationale**: Increases readability and prevents confusion (see also AV Rule 62).
+
+ **Examples**:
+ ```
+ int32 p; // correct
+ int32 q; // correct
+ int32 p, q; // probable error
+ int32 first_button_on_the_left_box, i; // incorrect; easy to overlook i
+ ```
+
+
+Flow Control Structures \[JSFAV 4.24\]
+-----------------------
+
+- AV Rule 188
+
+ Labels **will** not be used, except in switch statements.
+
+ **Rationale**: Labels are typically either used in switch statements or are as the targets for goto statements. See exception given in AV Rule 189.
+
+- AV Rule 189
+
+ The `goto` statement **shall not** be used.
+
+ **Rationale**: Frequent use of the `goto` statement tends to lead to code that is both difficult to read and maintain.
+
+- AV Rule 190
+
+ The `continue` statement **shall not** be used.
+
+- AV Rule 191
+
+ The `break` statement **shall not** be used (except to terminate the cases of a switch statement).
+
+ **Exception**: The `break` statement may be used to "break" out of a single loop provided the alternative would obscure or otherwise significantly complicate the control logic.
+
+- AV Rule 192
+
+ All `if`, `else if` constructs **will** contain either a final `else` clause or a comment indicating why a final `else` clause is not necessary.
+
+ **Rationale**: Provide a defensive strategy to ensure that all cases are handled by an `else if` series.
+
+ Note: This rule only applies when an `if` statement is followed by one or more `else if`’s.
+
+- AV Rule 193
+
+ Every non-empty `case` clause in a `switch` statement **shall** be terminated with a `break` statement.
+
+ **Rationale**: Eliminates potentially confusing behavior since execution will fall through to the code of the next `case` clause if a `break` statement does not terminate the previous `case` clause.
diff --git a/lib/ModbusMaster/VERSION b/lib/ModbusMaster/VERSION
new file mode 100644
index 00000000..38f77a65
--- /dev/null
+++ b/lib/ModbusMaster/VERSION
@@ -0,0 +1 @@
+2.0.1
diff --git a/lib/ModbusMaster/examples/Basic/Basic.pde b/lib/ModbusMaster/examples/Basic/Basic.pde
new file mode 100644
index 00000000..74c199b1
--- /dev/null
+++ b/lib/ModbusMaster/examples/Basic/Basic.pde
@@ -0,0 +1,69 @@
+/*
+
+ Basic.pde - example using ModbusMaster library
+
+ Library:: ModbusMaster
+ Author:: Doc Walker <4-20ma@wvfans.net>
+
+ Copyright:: 2009-2016 Doc Walker
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+#include
+
+
+// instantiate ModbusMaster object
+ModbusMaster node;
+
+
+void setup()
+{
+ // use Serial (port 0); initialize Modbus communication baud rate
+ Serial.begin(19200);
+
+ // communicate with Modbus slave ID 2 over Serial (port 0)
+ node.begin(2, Serial);
+}
+
+
+void loop()
+{
+ static uint32_t i;
+ uint8_t j, result;
+ uint16_t data[6];
+
+ i++;
+
+ // set word 0 of TX buffer to least-significant word of counter (bits 15..0)
+ node.setTransmitBuffer(0, lowWord(i));
+
+ // set word 1 of TX buffer to most-significant word of counter (bits 31..16)
+ node.setTransmitBuffer(1, highWord(i));
+
+ // slave: write TX buffer to (2) 16-bit registers starting at register 0
+ result = node.writeMultipleRegisters(0, 2);
+
+ // slave: read (6) 16-bit registers starting at register 2 to RX buffer
+ result = node.readHoldingRegisters(2, 6);
+
+ // do something with data if read is successful
+ if (result == node.ku8MBSuccess)
+ {
+ for (j = 0; j < 6; j++)
+ {
+ data[j] = node.getResponseBuffer(j);
+ }
+ }
+}
diff --git a/lib/ModbusMaster/examples/PhoenixContact_nanoLC/PhoenixContact_nanoLC.pde b/lib/ModbusMaster/examples/PhoenixContact_nanoLC/PhoenixContact_nanoLC.pde
new file mode 100644
index 00000000..e91fb338
--- /dev/null
+++ b/lib/ModbusMaster/examples/PhoenixContact_nanoLC/PhoenixContact_nanoLC.pde
@@ -0,0 +1,143 @@
+/*
+
+ PhoenixContact_nanoLC.pde - example using ModbusMaster library
+ to communicate with PHOENIX CONTACT nanoLine controller.
+
+ Library:: ModbusMaster
+ Author:: Doc Walker <4-20ma@wvfans.net>
+
+ Copyright:: 2009-2016 Doc Walker
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+#include
+
+// discrete coils
+#define NANO_DO(n) (0x0000 + n) ///< returns nanoLC discrete output address
+#define NANO_FLAG(n) (0x1000 + n) ///< returns nanoLC flag address
+
+// discrete inputs
+#define NANO_DI(n) (0x0000 + n) ///< returns nanoLC discrete input address
+
+// analog holding registers
+#define NANO_REG(n) (0x0000 + 2 * n) ///< returns nanoLC holding register address
+#define NANO_AO(n) (0x1000 + 2 * n) ///< returns nanoLC analog output address
+#define NANO_TCP(n) (0x2000 + 2 * n) ///< returns nanoLC timer/counter preset address
+#define NANO_OTP(n) (0x3000 + 2 * n) ///< returns nanoLC discrete output preset address
+#define NANO_HSP(n) (0x4000 + 2 * n) ///< returns nanoLC high-speed counter preset address
+#define NANO_TCA(n) (0x5000 + 2 * n) ///< returns nanoLC timer/counter accumulator address
+#define NANO_OTA(n) (0x6000 + 2 * n) ///< returns nanoLC discrete output accumulator address
+#define NANO_HSA(n) (0x7000 + 2 * n) ///< returns nanoLC high-speed counter accumulator address
+
+// analog input registers
+#define NANO_AI(n) (0x0000 + 2 * n) ///< returns nanoLC analog input address
+
+
+// instantiate ModbusMaster object
+ModbusMaster nanoLC;
+
+
+void setup()
+{
+ // use Serial (port 0); initialize Modbus communication baud rate
+ Serial.begin(19200);
+
+ // communicate with Modbus slave ID 1 over Serial (port 0)
+ nanoLC.begin(1, Serial);
+}
+
+
+void loop()
+{
+ static uint32_t u32ShiftRegister;
+ static uint32_t i;
+ uint8_t u8Status;
+
+ u32ShiftRegister = ((u32ShiftRegister < 0x01000000) ? (u32ShiftRegister << 4) : 1);
+ if (u32ShiftRegister == 0) u32ShiftRegister = 1;
+ i++;
+
+ // set word 0 of TX buffer to least-significant word of u32ShiftRegister (bits 15..0)
+ nanoLC.setTransmitBuffer(0, lowWord(u32ShiftRegister));
+
+ // set word 1 of TX buffer to most-significant word of u32ShiftRegister (bits 31..16)
+ nanoLC.setTransmitBuffer(1, highWord(u32ShiftRegister));
+
+ // set word 2 of TX buffer to least-significant word of i (bits 15..0)
+ nanoLC.setTransmitBuffer(2, lowWord(i));
+
+ // set word 3 of TX buffer to most-significant word of i (bits 31..16)
+ nanoLC.setTransmitBuffer(3, highWord(i));
+
+ // write TX buffer to (4) 16-bit registers starting at NANO_REG(1)
+ // read (4) 16-bit registers starting at NANO_REG(0) to RX buffer
+ // data is available via nanoLC.getResponseBuffer(0..3)
+ nanoLC.readWriteMultipleRegisters(NANO_REG(0), 4, NANO_REG(1), 4);
+
+ // write lowWord(u32ShiftRegister) to single 16-bit register starting at NANO_REG(3)
+ nanoLC.writeSingleRegister(NANO_REG(3), lowWord(u32ShiftRegister));
+
+ // write highWord(u32ShiftRegister) to single 16-bit register starting at NANO_REG(3) + 1
+ nanoLC.writeSingleRegister(NANO_REG(3) + 1, highWord(u32ShiftRegister));
+
+ // set word 0 of TX buffer to nanoLC.getResponseBuffer(0) (bits 15..0)
+ nanoLC.setTransmitBuffer(0, nanoLC.getResponseBuffer(0));
+
+ // set word 1 of TX buffer to nanoLC.getResponseBuffer(1) (bits 31..16)
+ nanoLC.setTransmitBuffer(1, nanoLC.getResponseBuffer(1));
+
+ // write TX buffer to (2) 16-bit registers starting at NANO_REG(4)
+ nanoLC.writeMultipleRegisters(NANO_REG(4), 2);
+
+ // read 17 coils starting at NANO_FLAG(0) to RX buffer
+ // bits 15..0 are available via nanoLC.getResponseBuffer(0)
+ // bit 16 is available via zero-padded nanoLC.getResponseBuffer(1)
+ nanoLC.readCoils(NANO_FLAG(0), 17);
+
+ // read (66) 16-bit registers starting at NANO_REG(0) to RX buffer
+ // generates Modbus exception ku8MBIllegalDataAddress (0x02)
+ u8Status = nanoLC.readHoldingRegisters(NANO_REG(0), 66);
+ if (u8Status == nanoLC.ku8MBIllegalDataAddress)
+ {
+ // read (64) 16-bit registers starting at NANO_REG(0) to RX buffer
+ // data is available via nanoLC.getResponseBuffer(0..63)
+ u8Status = nanoLC.readHoldingRegisters(NANO_REG(0), 64);
+ }
+
+ // read (8) 16-bit registers starting at NANO_AO(0) to RX buffer
+ // data is available via nanoLC.getResponseBuffer(0..7)
+ nanoLC.readHoldingRegisters(NANO_AO(0), 8);
+
+ // read (64) 16-bit registers starting at NANO_TCP(0) to RX buffer
+ // data is available via nanoLC.getResponseBuffer(0..63)
+ nanoLC.readHoldingRegisters(NANO_TCP(0), 64);
+
+ // read (64) 16-bit registers starting at NANO_OTP(0) to RX buffer
+ // data is available via nanoLC.getResponseBuffer(0..63)
+ nanoLC.readHoldingRegisters(NANO_OTP(0), 64);
+
+ // read (64) 16-bit registers starting at NANO_TCA(0) to RX buffer
+ // data is available via nanoLC.getResponseBuffer(0..63)
+ nanoLC.readHoldingRegisters(NANO_TCA(0), 64);
+
+ // read (64) 16-bit registers starting at NANO_OTA(0) to RX buffer
+ // data is available via nanoLC.getResponseBuffer(0..63)
+ nanoLC.readHoldingRegisters(NANO_OTA(0), 64);
+
+ // read (8) 16-bit registers starting at NANO_AI(0) to RX buffer
+ // data is available via nanoLC.getResponseBuffer(0..7)
+ nanoLC.readInputRegisters(NANO_AI(0), 8);
+}
+
diff --git a/lib/ModbusMaster/examples/RS485_HalfDuplex/RS485_HalfDuplex.ino b/lib/ModbusMaster/examples/RS485_HalfDuplex/RS485_HalfDuplex.ino
new file mode 100644
index 00000000..c19607f0
--- /dev/null
+++ b/lib/ModbusMaster/examples/RS485_HalfDuplex/RS485_HalfDuplex.ino
@@ -0,0 +1,98 @@
+/*
+
+ RS485_HalfDuplex.pde - example using ModbusMaster library to communicate
+ with EPSolar LS2024B controller using a half-duplex RS485 transceiver.
+
+ This example is tested against an EPSolar LS2024B solar charge controller.
+ See here for protocol specs:
+ http://www.solar-elektro.cz/data/dokumenty/1733_modbus_protocol.pdf
+
+ Library:: ModbusMaster
+ Author:: Marius Kintel
+
+ Copyright:: 2009-2016 Doc Walker
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+#include
+
+/*!
+ We're using a MAX485-compatible RS485 Transceiver.
+ Rx/Tx is hooked up to the hardware serial port at 'Serial'.
+ The Data Enable and Receiver Enable pins are hooked up as follows:
+*/
+#define MAX485_DE 3
+#define MAX485_RE_NEG 2
+
+// instantiate ModbusMaster object
+ModbusMaster node;
+
+void preTransmission()
+{
+ digitalWrite(MAX485_RE_NEG, 1);
+ digitalWrite(MAX485_DE, 1);
+}
+
+void postTransmission()
+{
+ digitalWrite(MAX485_RE_NEG, 0);
+ digitalWrite(MAX485_DE, 0);
+}
+
+void setup()
+{
+ pinMode(MAX485_RE_NEG, OUTPUT);
+ pinMode(MAX485_DE, OUTPUT);
+ // Init in receive mode
+ digitalWrite(MAX485_RE_NEG, 0);
+ digitalWrite(MAX485_DE, 0);
+
+ // Modbus communication runs at 115200 baud
+ Serial.begin(115200);
+
+ // Modbus slave ID 1
+ node.begin(1, Serial);
+ // Callbacks allow us to configure the RS485 transceiver correctly
+ node.preTransmission(preTransmission);
+ node.postTransmission(postTransmission);
+}
+
+bool state = true;
+
+void loop()
+{
+ uint8_t result;
+ uint16_t data[6];
+
+ // Toggle the coil at address 0x0002 (Manual Load Control)
+ result = node.writeSingleCoil(0x0002, state);
+ state = !state;
+
+ // Read 16 registers starting at 0x3100)
+ result = node.readInputRegisters(0x3100, 16);
+ if (result == node.ku8MBSuccess)
+ {
+ Serial.print("Vbatt: ");
+ Serial.println(node.getResponseBuffer(0x04)/100.0f);
+ Serial.print("Vload: ");
+ Serial.println(node.getResponseBuffer(0xC0)/100.0f);
+ Serial.print("Pload: ");
+ Serial.println((node.getResponseBuffer(0x0D) +
+ node.getResponseBuffer(0x0E) << 16)/100.0f);
+ }
+
+ delay(1000);
+}
+
diff --git a/lib/ModbusMaster/extras/ModbusMaster reference-2.0.1.pdf b/lib/ModbusMaster/extras/ModbusMaster reference-2.0.1.pdf
new file mode 100644
index 00000000..cce1e04e
Binary files /dev/null and b/lib/ModbusMaster/extras/ModbusMaster reference-2.0.1.pdf differ
diff --git a/lib/ModbusMaster/extras/README.txt b/lib/ModbusMaster/extras/README.txt
new file mode 100644
index 00000000..a5720f68
--- /dev/null
+++ b/lib/ModbusMaster/extras/README.txt
@@ -0,0 +1,6 @@
+Documentation is available at:
+ http://4-20ma.github.com/ModbusMaster
+
+Alternatively, you can download the HTML files at:
+ [tarball] https://github.com/4-20ma/ModbusMaster/tarball/gh-pages
+ [zipball] https://github.com/4-20ma/ModbusMaster/zipball/gh-pages
diff --git a/lib/ModbusMaster/keywords.txt b/lib/ModbusMaster/keywords.txt
new file mode 100644
index 00000000..fd92fdb4
--- /dev/null
+++ b/lib/ModbusMaster/keywords.txt
@@ -0,0 +1,50 @@
+#######################################
+# Syntax Coloring Map For ModbusMaster
+#######################################
+
+#######################################
+# Datatypes (KEYWORD1)
+#######################################
+
+ModbusMaster KEYWORD1
+
+#######################################
+# Methods and Functions (KEYWORD2)
+#######################################
+
+lowWord KEYWORD2
+highWord KEYWORD2
+LONG KEYWORD2
+
+begin KEYWORD2
+
+getResponseBuffer KEYWORD2
+clearResponseBuffer KEYWORD2
+setTransmitBuffer KEYWORD2
+clearTransmitBuffer KEYWORD2
+
+readCoils KEYWORD2
+readDiscreteInputs KEYWORD2
+readHoldingRegisters KEYWORD2
+readInputRegisters KEYWORD2
+writeSingleCoil KEYWORD2
+writeSingleRegister KEYWORD2
+writeMultipleCoils KEYWORD2
+writeMultipleRegisters KEYWORD2
+maskWriteRegister KEYWORD2
+readWriteMultipleRegisters KEYWORD2
+
+#######################################
+# Constants (LITERAL1)
+#######################################
+
+ku8MBIllegalFunction LITERAL1
+ku8MBIllegalDataAddress LITERAL1
+ku8MBIllegalDataValue LITERAL1
+ku8MBSlaveDeviceFailure LITERAL1
+
+ku8MBSuccess LITERAL1
+ku8MBInvalidSlaveID LITERAL1
+ku8MBInvalidFunction LITERAL1
+ku8MBResponseTimedOut LITERAL1
+ku8MBInvalidCRC LITERAL1
diff --git a/lib/ModbusMaster/library.properties b/lib/ModbusMaster/library.properties
new file mode 100644
index 00000000..a2be2fa7
--- /dev/null
+++ b/lib/ModbusMaster/library.properties
@@ -0,0 +1,10 @@
+name=ModbusMaster
+version=2.0.1
+author=Doc Walker
+maintainer=Doc Walker <4-20ma@wvfans.net>
+sentence=Enlighten your Arduino to be a Modbus master.
+paragraph=Enables communication with Modbus slaves over RS232/485 (via RTU protocol). Requires an RS232/485 transceiver.
+category=Communication
+url=https://github.com/4-20ma/ModbusMaster
+architectures=*
+includes=ModbusMaster.h
diff --git a/lib/ModbusMaster/src/ModbusMaster.cpp b/lib/ModbusMaster/src/ModbusMaster.cpp
new file mode 100644
index 00000000..4169e585
--- /dev/null
+++ b/lib/ModbusMaster/src/ModbusMaster.cpp
@@ -0,0 +1,876 @@
+/**
+@file
+Arduino library for communicating with Modbus slaves over RS232/485 (via RTU protocol).
+*/
+/*
+
+ ModbusMaster.cpp - Arduino library for communicating with Modbus slaves
+ over RS232/485 (via RTU protocol).
+
+ Library:: ModbusMaster
+
+ Copyright:: 2009-2016 Doc Walker
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+
+/* _____PROJECT INCLUDES_____________________________________________________ */
+#include "ModbusMaster.h"
+
+
+/* _____GLOBAL VARIABLES_____________________________________________________ */
+
+
+/* _____PUBLIC FUNCTIONS_____________________________________________________ */
+/**
+Constructor.
+
+Creates class object; initialize it using ModbusMaster::begin().
+
+@ingroup setup
+*/
+ModbusMaster::ModbusMaster(void)
+{
+ _idle = 0;
+ _preTransmission = 0;
+ _postTransmission = 0;
+}
+
+/**
+Initialize class object.
+
+Assigns the Modbus slave ID and serial port.
+Call once class has been instantiated, typically within setup().
+
+@param slave Modbus slave ID (1..255)
+@param &serial reference to serial port object (Serial, Serial1, ... Serial3)
+@ingroup setup
+*/
+void ModbusMaster::begin(uint8_t slave, Stream &serial)
+{
+// txBuffer = (uint16_t*) calloc(ku8MaxBufferSize, sizeof(uint16_t));
+ _u8MBSlave = slave;
+ _serial = &serial;
+ _u8TransmitBufferIndex = 0;
+ u16TransmitBufferLength = 0;
+
+#if __MODBUSMASTER_DEBUG__
+ pinMode(__MODBUSMASTER_DEBUG_PIN_A__, OUTPUT);
+ pinMode(__MODBUSMASTER_DEBUG_PIN_B__, OUTPUT);
+#endif
+}
+
+
+void ModbusMaster::beginTransmission(uint16_t u16Address)
+{
+ _u16WriteAddress = u16Address;
+ _u8TransmitBufferIndex = 0;
+ u16TransmitBufferLength = 0;
+}
+
+// eliminate this function in favor of using existing MB request functions
+uint8_t ModbusMaster::requestFrom(uint16_t address, uint16_t quantity)
+{
+ uint8_t read;
+ // clamp to buffer length
+ if (quantity > ku8MaxBufferSize)
+ {
+ quantity = ku8MaxBufferSize;
+ }
+ // set rx buffer iterator vars
+ _u8ResponseBufferIndex = 0;
+ _u8ResponseBufferLength = read;
+
+ return read;
+}
+
+
+void ModbusMaster::sendBit(bool data)
+{
+ uint8_t txBitIndex = u16TransmitBufferLength % 16;
+ if ((u16TransmitBufferLength >> 4) < ku8MaxBufferSize)
+ {
+ if (0 == txBitIndex)
+ {
+ _u16TransmitBuffer[_u8TransmitBufferIndex] = 0;
+ }
+ bitWrite(_u16TransmitBuffer[_u8TransmitBufferIndex], txBitIndex, data);
+ u16TransmitBufferLength++;
+ _u8TransmitBufferIndex = u16TransmitBufferLength >> 4;
+ }
+}
+
+
+void ModbusMaster::send(uint16_t data)
+{
+ if (_u8TransmitBufferIndex < ku8MaxBufferSize)
+ {
+ _u16TransmitBuffer[_u8TransmitBufferIndex++] = data;
+ u16TransmitBufferLength = _u8TransmitBufferIndex << 4;
+ }
+}
+
+
+void ModbusMaster::send(uint32_t data)
+{
+ send(lowWord(data));
+ send(highWord(data));
+}
+
+
+void ModbusMaster::send(uint8_t data)
+{
+ send(word(data));
+}
+
+
+
+
+
+
+
+
+
+uint8_t ModbusMaster::available(void)
+{
+ return _u8ResponseBufferLength - _u8ResponseBufferIndex;
+}
+
+
+uint16_t ModbusMaster::receive(void)
+{
+ if (_u8ResponseBufferIndex < _u8ResponseBufferLength)
+ {
+ return _u16ResponseBuffer[_u8ResponseBufferIndex++];
+ }
+ else
+ {
+ return 0xFFFF;
+ }
+}
+
+
+
+
+
+
+
+
+/**
+Set idle time callback function (cooperative multitasking).
+
+This function gets called in the idle time between transmission of data
+and response from slave. Do not call functions that read from the serial
+buffer that is used by ModbusMaster. Use of i2c/TWI, 1-Wire, other
+serial ports, etc. is permitted within callback function.
+
+@see ModbusMaster::ModbusMasterTransaction()
+*/
+void ModbusMaster::idle(void (*idle)())
+{
+ _idle = idle;
+}
+
+/**
+Set pre-transmission callback function.
+
+This function gets called just before a Modbus message is sent over serial.
+Typical usage of this callback is to enable an RS485 transceiver's
+Driver Enable pin, and optionally disable its Receiver Enable pin.
+
+@see ModbusMaster::ModbusMasterTransaction()
+@see ModbusMaster::postTransmission()
+*/
+void ModbusMaster::preTransmission(void (*preTransmission)())
+{
+ _preTransmission = preTransmission;
+}
+
+/**
+Set post-transmission callback function.
+
+This function gets called after a Modbus message has finished sending
+(i.e. after all data has been physically transmitted onto the serial
+bus).
+
+Typical usage of this callback is to enable an RS485 transceiver's
+Receiver Enable pin, and disable its Driver Enable pin.
+
+@see ModbusMaster::ModbusMasterTransaction()
+@see ModbusMaster::preTransmission()
+*/
+void ModbusMaster::postTransmission(void (*postTransmission)())
+{
+ _postTransmission = postTransmission;
+}
+
+
+/**
+Retrieve data from response buffer.
+
+@see ModbusMaster::clearResponseBuffer()
+@param u8Index index of response buffer array (0x00..0x3F)
+@return value in position u8Index of response buffer (0x0000..0xFFFF)
+@ingroup buffer
+*/
+uint16_t ModbusMaster::getResponseBuffer(uint8_t u8Index)
+{
+ if (u8Index < ku8MaxBufferSize)
+ {
+ return _u16ResponseBuffer[u8Index];
+ }
+ else
+ {
+ return 0xFFFF;
+ }
+}
+
+
+/**
+Clear Modbus response buffer.
+
+@see ModbusMaster::getResponseBuffer(uint8_t u8Index)
+@ingroup buffer
+*/
+void ModbusMaster::clearResponseBuffer()
+{
+ uint8_t i;
+
+ for (i = 0; i < ku8MaxBufferSize; i++)
+ {
+ _u16ResponseBuffer[i] = 0;
+ }
+}
+
+
+/**
+Place data in transmit buffer.
+
+@see ModbusMaster::clearTransmitBuffer()
+@param u8Index index of transmit buffer array (0x00..0x3F)
+@param u16Value value to place in position u8Index of transmit buffer (0x0000..0xFFFF)
+@return 0 on success; exception number on failure
+@ingroup buffer
+*/
+uint8_t ModbusMaster::setTransmitBuffer(uint8_t u8Index, uint16_t u16Value)
+{
+ if (u8Index < ku8MaxBufferSize)
+ {
+ _u16TransmitBuffer[u8Index] = u16Value;
+ return ku8MBSuccess;
+ }
+ else
+ {
+ return ku8MBIllegalDataAddress;
+ }
+}
+
+
+/**
+Clear Modbus transmit buffer.
+
+@see ModbusMaster::setTransmitBuffer(uint8_t u8Index, uint16_t u16Value)
+@ingroup buffer
+*/
+void ModbusMaster::clearTransmitBuffer()
+{
+ uint8_t i;
+
+ for (i = 0; i < ku8MaxBufferSize; i++)
+ {
+ _u16TransmitBuffer[i] = 0;
+ }
+}
+
+
+/**
+Modbus function 0x01 Read Coils.
+
+This function code is used to read from 1 to 2000 contiguous status of
+coils in a remote device. The request specifies the starting address,
+i.e. the address of the first coil specified, and the number of coils.
+Coils are addressed starting at zero.
+
+The coils in the response buffer are packed as one coil per bit of the
+data field. Status is indicated as 1=ON and 0=OFF. The LSB of the first
+data word contains the output addressed in the query. The other coils
+follow toward the high order end of this word and from low order to high
+order in subsequent words.
+
+If the returned quantity is not a multiple of sixteen, the remaining
+bits in the final data word will be padded with zeros (toward the high
+order end of the word).
+
+@param u16ReadAddress address of first coil (0x0000..0xFFFF)
+@param u16BitQty quantity of coils to read (1..2000, enforced by remote device)
+@return 0 on success; exception number on failure
+@ingroup discrete
+*/
+uint8_t ModbusMaster::readCoils(uint16_t u16ReadAddress, uint16_t u16BitQty)
+{
+ _u16ReadAddress = u16ReadAddress;
+ _u16ReadQty = u16BitQty;
+ return ModbusMasterTransaction(ku8MBReadCoils);
+}
+
+
+/**
+Modbus function 0x02 Read Discrete Inputs.
+
+This function code is used to read from 1 to 2000 contiguous status of
+discrete inputs in a remote device. The request specifies the starting
+address, i.e. the address of the first input specified, and the number
+of inputs. Discrete inputs are addressed starting at zero.
+
+The discrete inputs in the response buffer are packed as one input per
+bit of the data field. Status is indicated as 1=ON; 0=OFF. The LSB of
+the first data word contains the input addressed in the query. The other
+inputs follow toward the high order end of this word, and from low order
+to high order in subsequent words.
+
+If the returned quantity is not a multiple of sixteen, the remaining
+bits in the final data word will be padded with zeros (toward the high
+order end of the word).
+
+@param u16ReadAddress address of first discrete input (0x0000..0xFFFF)
+@param u16BitQty quantity of discrete inputs to read (1..2000, enforced by remote device)
+@return 0 on success; exception number on failure
+@ingroup discrete
+*/
+uint8_t ModbusMaster::readDiscreteInputs(uint16_t u16ReadAddress,
+ uint16_t u16BitQty)
+{
+ _u16ReadAddress = u16ReadAddress;
+ _u16ReadQty = u16BitQty;
+ return ModbusMasterTransaction(ku8MBReadDiscreteInputs);
+}
+
+
+/**
+Modbus function 0x03 Read Holding Registers.
+
+This function code is used to read the contents of a contiguous block of
+holding registers in a remote device. The request specifies the starting
+register address and the number of registers. Registers are addressed
+starting at zero.
+
+The register data in the response buffer is packed as one word per
+register.
+
+@param u16ReadAddress address of the first holding register (0x0000..0xFFFF)
+@param u16ReadQty quantity of holding registers to read (1..125, enforced by remote device)
+@return 0 on success; exception number on failure
+@ingroup register
+*/
+uint8_t ModbusMaster::readHoldingRegisters(uint16_t u16ReadAddress,
+ uint16_t u16ReadQty)
+{
+ _u16ReadAddress = u16ReadAddress;
+ _u16ReadQty = u16ReadQty;
+ return ModbusMasterTransaction(ku8MBReadHoldingRegisters);
+}
+
+
+/**
+Modbus function 0x04 Read Input Registers.
+
+This function code is used to read from 1 to 125 contiguous input
+registers in a remote device. The request specifies the starting
+register address and the number of registers. Registers are addressed
+starting at zero.
+
+The register data in the response buffer is packed as one word per
+register.
+
+@param u16ReadAddress address of the first input register (0x0000..0xFFFF)
+@param u16ReadQty quantity of input registers to read (1..125, enforced by remote device)
+@return 0 on success; exception number on failure
+@ingroup register
+*/
+uint8_t ModbusMaster::readInputRegisters(uint16_t u16ReadAddress,
+ uint8_t u16ReadQty)
+{
+ _u16ReadAddress = u16ReadAddress;
+ _u16ReadQty = u16ReadQty;
+ return ModbusMasterTransaction(ku8MBReadInputRegisters);
+}
+
+
+/**
+Modbus function 0x05 Write Single Coil.
+
+This function code is used to write a single output to either ON or OFF
+in a remote device. The requested ON/OFF state is specified by a
+constant in the state field. A non-zero value requests the output to be
+ON and a value of 0 requests it to be OFF. The request specifies the
+address of the coil to be forced. Coils are addressed starting at zero.
+
+@param u16WriteAddress address of the coil (0x0000..0xFFFF)
+@param u8State 0=OFF, non-zero=ON (0x00..0xFF)
+@return 0 on success; exception number on failure
+@ingroup discrete
+*/
+uint8_t ModbusMaster::writeSingleCoil(uint16_t u16WriteAddress, uint8_t u8State)
+{
+ _u16WriteAddress = u16WriteAddress;
+ _u16WriteQty = (u8State ? 0xFF00 : 0x0000);
+ return ModbusMasterTransaction(ku8MBWriteSingleCoil);
+}
+
+
+/**
+Modbus function 0x06 Write Single Register.
+
+This function code is used to write a single holding register in a
+remote device. The request specifies the address of the register to be
+written. Registers are addressed starting at zero.
+
+@param u16WriteAddress address of the holding register (0x0000..0xFFFF)
+@param u16WriteValue value to be written to holding register (0x0000..0xFFFF)
+@return 0 on success; exception number on failure
+@ingroup register
+*/
+uint8_t ModbusMaster::writeSingleRegister(uint16_t u16WriteAddress,
+ uint16_t u16WriteValue)
+{
+ _u16WriteAddress = u16WriteAddress;
+ _u16WriteQty = 0;
+ _u16TransmitBuffer[0] = u16WriteValue;
+ return ModbusMasterTransaction(ku8MBWriteSingleRegister);
+}
+
+
+/**
+Modbus function 0x0F Write Multiple Coils.
+
+This function code is used to force each coil in a sequence of coils to
+either ON or OFF in a remote device. The request specifies the coil
+references to be forced. Coils are addressed starting at zero.
+
+The requested ON/OFF states are specified by contents of the transmit
+buffer. A logical '1' in a bit position of the buffer requests the
+corresponding output to be ON. A logical '0' requests it to be OFF.
+
+@param u16WriteAddress address of the first coil (0x0000..0xFFFF)
+@param u16BitQty quantity of coils to write (1..2000, enforced by remote device)
+@return 0 on success; exception number on failure
+@ingroup discrete
+*/
+uint8_t ModbusMaster::writeMultipleCoils(uint16_t u16WriteAddress,
+ uint16_t u16BitQty)
+{
+ _u16WriteAddress = u16WriteAddress;
+ _u16WriteQty = u16BitQty;
+ return ModbusMasterTransaction(ku8MBWriteMultipleCoils);
+}
+uint8_t ModbusMaster::writeMultipleCoils()
+{
+ _u16WriteQty = u16TransmitBufferLength;
+ return ModbusMasterTransaction(ku8MBWriteMultipleCoils);
+}
+
+
+/**
+Modbus function 0x10 Write Multiple Registers.
+
+This function code is used to write a block of contiguous registers (1
+to 123 registers) in a remote device.
+
+The requested written values are specified in the transmit buffer. Data
+is packed as one word per register.
+
+@param u16WriteAddress address of the holding register (0x0000..0xFFFF)
+@param u16WriteQty quantity of holding registers to write (1..123, enforced by remote device)
+@return 0 on success; exception number on failure
+@ingroup register
+*/
+uint8_t ModbusMaster::writeMultipleRegisters(uint16_t u16WriteAddress,
+ uint16_t u16WriteQty)
+{
+ _u16WriteAddress = u16WriteAddress;
+ _u16WriteQty = u16WriteQty;
+ return ModbusMasterTransaction(ku8MBWriteMultipleRegisters);
+}
+
+// new version based on Wire.h
+uint8_t ModbusMaster::writeMultipleRegisters()
+{
+ _u16WriteQty = _u8TransmitBufferIndex;
+ return ModbusMasterTransaction(ku8MBWriteMultipleRegisters);
+}
+
+
+/**
+Modbus function 0x16 Mask Write Register.
+
+This function code is used to modify the contents of a specified holding
+register using a combination of an AND mask, an OR mask, and the
+register's current contents. The function can be used to set or clear
+individual bits in the register.
+
+The request specifies the holding register to be written, the data to be
+used as the AND mask, and the data to be used as the OR mask. Registers
+are addressed starting at zero.
+
+The function's algorithm is:
+
+Result = (Current Contents && And_Mask) || (Or_Mask && (~And_Mask))
+
+@param u16WriteAddress address of the holding register (0x0000..0xFFFF)
+@param u16AndMask AND mask (0x0000..0xFFFF)
+@param u16OrMask OR mask (0x0000..0xFFFF)
+@return 0 on success; exception number on failure
+@ingroup register
+*/
+uint8_t ModbusMaster::maskWriteRegister(uint16_t u16WriteAddress,
+ uint16_t u16AndMask, uint16_t u16OrMask)
+{
+ _u16WriteAddress = u16WriteAddress;
+ _u16TransmitBuffer[0] = u16AndMask;
+ _u16TransmitBuffer[1] = u16OrMask;
+ return ModbusMasterTransaction(ku8MBMaskWriteRegister);
+}
+
+
+/**
+Modbus function 0x17 Read Write Multiple Registers.
+
+This function code performs a combination of one read operation and one
+write operation in a single MODBUS transaction. The write operation is
+performed before the read. Holding registers are addressed starting at
+zero.
+
+The request specifies the starting address and number of holding
+registers to be read as well as the starting address, and the number of
+holding registers. The data to be written is specified in the transmit
+buffer.
+
+@param u16ReadAddress address of the first holding register (0x0000..0xFFFF)
+@param u16ReadQty quantity of holding registers to read (1..125, enforced by remote device)
+@param u16WriteAddress address of the first holding register (0x0000..0xFFFF)
+@param u16WriteQty quantity of holding registers to write (1..121, enforced by remote device)
+@return 0 on success; exception number on failure
+@ingroup register
+*/
+uint8_t ModbusMaster::readWriteMultipleRegisters(uint16_t u16ReadAddress,
+ uint16_t u16ReadQty, uint16_t u16WriteAddress, uint16_t u16WriteQty)
+{
+ _u16ReadAddress = u16ReadAddress;
+ _u16ReadQty = u16ReadQty;
+ _u16WriteAddress = u16WriteAddress;
+ _u16WriteQty = u16WriteQty;
+ return ModbusMasterTransaction(ku8MBReadWriteMultipleRegisters);
+}
+uint8_t ModbusMaster::readWriteMultipleRegisters(uint16_t u16ReadAddress,
+ uint16_t u16ReadQty)
+{
+ _u16ReadAddress = u16ReadAddress;
+ _u16ReadQty = u16ReadQty;
+ _u16WriteQty = _u8TransmitBufferIndex;
+ return ModbusMasterTransaction(ku8MBReadWriteMultipleRegisters);
+}
+
+
+/* _____PRIVATE FUNCTIONS____________________________________________________ */
+/**
+Modbus transaction engine.
+Sequence:
+ - assemble Modbus Request Application Data Unit (ADU),
+ based on particular function called
+ - transmit request over selected serial port
+ - wait for/retrieve response
+ - evaluate/disassemble response
+ - return status (success/exception)
+
+@param u8MBFunction Modbus function (0x01..0xFF)
+@return 0 on success; exception number on failure
+*/
+uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
+{
+ uint8_t u8ModbusADU[256];
+ uint8_t u8ModbusADUSize = 0;
+ uint8_t i, u8Qty;
+ uint16_t u16CRC;
+ uint32_t u32StartTime;
+ uint8_t u8BytesLeft = 8;
+ uint8_t u8MBStatus = ku8MBSuccess;
+
+ // assemble Modbus Request Application Data Unit
+ u8ModbusADU[u8ModbusADUSize++] = _u8MBSlave;
+ u8ModbusADU[u8ModbusADUSize++] = u8MBFunction;
+
+ switch(u8MBFunction)
+ {
+ case ku8MBReadCoils:
+ case ku8MBReadDiscreteInputs:
+ case ku8MBReadInputRegisters:
+ case ku8MBReadHoldingRegisters:
+ case ku8MBReadWriteMultipleRegisters:
+ u8ModbusADU[u8ModbusADUSize++] = highByte(_u16ReadAddress);
+ u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16ReadAddress);
+ u8ModbusADU[u8ModbusADUSize++] = highByte(_u16ReadQty);
+ u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16ReadQty);
+ break;
+ }
+
+ switch(u8MBFunction)
+ {
+ case ku8MBWriteSingleCoil:
+ case ku8MBMaskWriteRegister:
+ case ku8MBWriteMultipleCoils:
+ case ku8MBWriteSingleRegister:
+ case ku8MBWriteMultipleRegisters:
+ case ku8MBReadWriteMultipleRegisters:
+ u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteAddress);
+ u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteAddress);
+ break;
+ }
+
+ switch(u8MBFunction)
+ {
+ case ku8MBWriteSingleCoil:
+ u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteQty);
+ u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty);
+ break;
+
+ case ku8MBWriteSingleRegister:
+ u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[0]);
+ u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[0]);
+ break;
+
+ case ku8MBWriteMultipleCoils:
+ u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteQty);
+ u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty);
+ u8Qty = (_u16WriteQty % 8) ? ((_u16WriteQty >> 3) + 1) : (_u16WriteQty >> 3);
+ u8ModbusADU[u8ModbusADUSize++] = u8Qty;
+ for (i = 0; i < u8Qty; i++)
+ {
+ switch(i % 2)
+ {
+ case 0: // i is even
+ u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[i >> 1]);
+ break;
+
+ case 1: // i is odd
+ u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[i >> 1]);
+ break;
+ }
+ }
+ break;
+
+ case ku8MBWriteMultipleRegisters:
+ case ku8MBReadWriteMultipleRegisters:
+ u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteQty);
+ u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty);
+ u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty << 1);
+
+ for (i = 0; i < lowByte(_u16WriteQty); i++)
+ {
+ u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[i]);
+ u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[i]);
+ }
+ break;
+
+ case ku8MBMaskWriteRegister:
+ u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[0]);
+ u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[0]);
+ u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[1]);
+ u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[1]);
+ break;
+ }
+
+ // append CRC
+ u16CRC = 0xFFFF;
+ for (i = 0; i < u8ModbusADUSize; i++)
+ {
+ u16CRC = crc16_update(u16CRC, u8ModbusADU[i]);
+ }
+ u8ModbusADU[u8ModbusADUSize++] = lowByte(u16CRC);
+ u8ModbusADU[u8ModbusADUSize++] = highByte(u16CRC);
+ u8ModbusADU[u8ModbusADUSize] = 0;
+
+ // flush receive buffer before transmitting request
+ while (_serial->read() != -1);
+
+ // transmit request
+ if (_preTransmission)
+ {
+ _preTransmission();
+ }
+ for (i = 0; i < u8ModbusADUSize; i++)
+ {
+ _serial->write(u8ModbusADU[i]);
+ }
+
+ u8ModbusADUSize = 0;
+ _serial->flush(); // flush transmit buffer
+ if (_postTransmission)
+ {
+ _postTransmission();
+ }
+
+ // loop until we run out of time or bytes, or an error occurs
+ u32StartTime = millis();
+ while (u8BytesLeft && !u8MBStatus)
+ {
+ if (_serial->available())
+ {
+#if __MODBUSMASTER_DEBUG__
+ digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, true);
+#endif
+ u8ModbusADU[u8ModbusADUSize++] = _serial->read();
+ u8BytesLeft--;
+#if __MODBUSMASTER_DEBUG__
+ digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, false);
+#endif
+ }
+ else
+ {
+#if __MODBUSMASTER_DEBUG__
+ digitalWrite(__MODBUSMASTER_DEBUG_PIN_B__, true);
+#endif
+ if (_idle)
+ {
+ _idle();
+ }
+#if __MODBUSMASTER_DEBUG__
+ digitalWrite(__MODBUSMASTER_DEBUG_PIN_B__, false);
+#endif
+ }
+
+ // evaluate slave ID, function code once enough bytes have been read
+ if (u8ModbusADUSize == 5)
+ {
+ // verify response is for correct Modbus slave
+ if (u8ModbusADU[0] != _u8MBSlave)
+ {
+ u8MBStatus = ku8MBInvalidSlaveID;
+ break;
+ }
+
+ // verify response is for correct Modbus function code (mask exception bit 7)
+ if ((u8ModbusADU[1] & 0x7F) != u8MBFunction)
+ {
+ u8MBStatus = ku8MBInvalidFunction;
+ break;
+ }
+
+ // check whether Modbus exception occurred; return Modbus Exception Code
+ if (bitRead(u8ModbusADU[1], 7))
+ {
+ u8MBStatus = u8ModbusADU[2];
+ break;
+ }
+
+ // evaluate returned Modbus function code
+ switch(u8ModbusADU[1])
+ {
+ case ku8MBReadCoils:
+ case ku8MBReadDiscreteInputs:
+ case ku8MBReadInputRegisters:
+ case ku8MBReadHoldingRegisters:
+ case ku8MBReadWriteMultipleRegisters:
+ u8BytesLeft = u8ModbusADU[2];
+ break;
+
+ case ku8MBWriteSingleCoil:
+ case ku8MBWriteMultipleCoils:
+ case ku8MBWriteSingleRegister:
+ case ku8MBWriteMultipleRegisters:
+ u8BytesLeft = 3;
+ break;
+
+ case ku8MBMaskWriteRegister:
+ u8BytesLeft = 5;
+ break;
+ }
+ }
+ if ((millis() - u32StartTime) > ku16MBResponseTimeout)
+ {
+ u8MBStatus = ku8MBResponseTimedOut;
+ }
+ }
+
+ // verify response is large enough to inspect further
+ if (!u8MBStatus && u8ModbusADUSize >= 5)
+ {
+ // calculate CRC
+ u16CRC = 0xFFFF;
+ for (i = 0; i < (u8ModbusADUSize - 2); i++)
+ {
+ u16CRC = crc16_update(u16CRC, u8ModbusADU[i]);
+ }
+
+ // verify CRC
+ if (!u8MBStatus && (lowByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 2] ||
+ highByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 1]))
+ {
+ u8MBStatus = ku8MBInvalidCRC;
+ }
+ }
+
+ // disassemble ADU into words
+ if (!u8MBStatus)
+ {
+ // evaluate returned Modbus function code
+ switch(u8ModbusADU[1])
+ {
+ case ku8MBReadCoils:
+ case ku8MBReadDiscreteInputs:
+ // load bytes into word; response bytes are ordered L, H, L, H, ...
+ for (i = 0; i < (u8ModbusADU[2] >> 1); i++)
+ {
+ if (i < ku8MaxBufferSize)
+ {
+ _u16ResponseBuffer[i] = word(u8ModbusADU[2 * i + 4], u8ModbusADU[2 * i + 3]);
+ }
+
+ _u8ResponseBufferLength = i;
+ }
+
+ // in the event of an odd number of bytes, load last byte into zero-padded word
+ if (u8ModbusADU[2] % 2)
+ {
+ if (i < ku8MaxBufferSize)
+ {
+ _u16ResponseBuffer[i] = word(0, u8ModbusADU[2 * i + 3]);
+ }
+
+ _u8ResponseBufferLength = i + 1;
+ }
+ break;
+
+ case ku8MBReadInputRegisters:
+ case ku8MBReadHoldingRegisters:
+ case ku8MBReadWriteMultipleRegisters:
+ // load bytes into word; response bytes are ordered H, L, H, L, ...
+ for (i = 0; i < (u8ModbusADU[2] >> 1); i++)
+ {
+ if (i < ku8MaxBufferSize)
+ {
+ _u16ResponseBuffer[i] = word(u8ModbusADU[2 * i + 3], u8ModbusADU[2 * i + 4]);
+ }
+
+ _u8ResponseBufferLength = i;
+ }
+ break;
+ }
+ }
+
+ _u8TransmitBufferIndex = 0;
+ u16TransmitBufferLength = 0;
+ _u8ResponseBufferIndex = 0;
+ return u8MBStatus;
+}
diff --git a/lib/ModbusMaster/src/ModbusMaster.h b/lib/ModbusMaster/src/ModbusMaster.h
new file mode 100644
index 00000000..b8c566a4
--- /dev/null
+++ b/lib/ModbusMaster/src/ModbusMaster.h
@@ -0,0 +1,270 @@
+/**
+@file
+Arduino library for communicating with Modbus slaves over RS232/485 (via RTU protocol).
+
+@defgroup setup ModbusMaster Object Instantiation/Initialization
+@defgroup buffer ModbusMaster Buffer Management
+@defgroup discrete Modbus Function Codes for Discrete Coils/Inputs
+@defgroup register Modbus Function Codes for Holding/Input Registers
+@defgroup constant Modbus Function Codes, Exception Codes
+*/
+/*
+
+ ModbusMaster.h - Arduino library for communicating with Modbus slaves
+ over RS232/485 (via RTU protocol).
+
+ Library:: ModbusMaster
+
+ Copyright:: 2009-2016 Doc Walker
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+
+#ifndef ModbusMaster_h
+#define ModbusMaster_h
+
+
+/**
+@def __MODBUSMASTER_DEBUG__ (0)
+Set to 1 to enable debugging features within class:
+ - PIN A cycles for each byte read in the Modbus response
+ - PIN B cycles for each millisecond timeout during the Modbus response
+*/
+#define __MODBUSMASTER_DEBUG__ (0)
+#define __MODBUSMASTER_DEBUG_PIN_A__ 4
+#define __MODBUSMASTER_DEBUG_PIN_B__ 5
+
+/* _____STANDARD INCLUDES____________________________________________________ */
+// include types & constants of Wiring core API
+#include "Arduino.h"
+
+/* _____UTILITY MACROS_______________________________________________________ */
+
+
+/* _____PROJECT INCLUDES_____________________________________________________ */
+// functions to calculate Modbus Application Data Unit CRC
+#include "util/crc16.h"
+
+// functions to manipulate words
+#include "util/word.h"
+
+
+/* _____CLASS DEFINITIONS____________________________________________________ */
+/**
+Arduino class library for communicating with Modbus slaves over
+RS232/485 (via RTU protocol).
+*/
+class ModbusMaster
+{
+ public:
+ ModbusMaster();
+
+ void begin(uint8_t, Stream &serial);
+ void idle(void (*)());
+ void preTransmission(void (*)());
+ void postTransmission(void (*)());
+
+ // Modbus exception codes
+ /**
+ Modbus protocol illegal function exception.
+
+ The function code received in the query is not an allowable action for
+ the server (or slave). This may be because the function code is only
+ applicable to newer devices, and was not implemented in the unit
+ selected. It could also indicate that the server (or slave) is in the
+ wrong state to process a request of this type, for example because it is
+ unconfigured and is being asked to return register values.
+
+ @ingroup constant
+ */
+ static const uint8_t ku8MBIllegalFunction = 0x01;
+
+ /**
+ Modbus protocol illegal data address exception.
+
+ The data address received in the query is not an allowable address for
+ the server (or slave). More specifically, the combination of reference
+ number and transfer length is invalid. For a controller with 100
+ registers, the ADU addresses the first register as 0, and the last one
+ as 99. If a request is submitted with a starting register address of 96
+ and a quantity of registers of 4, then this request will successfully
+ operate (address-wise at least) on registers 96, 97, 98, 99. If a
+ request is submitted with a starting register address of 96 and a
+ quantity of registers of 5, then this request will fail with Exception
+ Code 0x02 "Illegal Data Address" since it attempts to operate on
+ registers 96, 97, 98, 99 and 100, and there is no register with address
+ 100.
+
+ @ingroup constant
+ */
+ static const uint8_t ku8MBIllegalDataAddress = 0x02;
+
+ /**
+ Modbus protocol illegal data value exception.
+
+ A value contained in the query data field is not an allowable value for
+ server (or slave). This indicates a fault in the structure of the
+ remainder of a complex request, such as that the implied length is
+ incorrect. It specifically does NOT mean that a data item submitted for
+ storage in a register has a value outside the expectation of the
+ application program, since the MODBUS protocol is unaware of the
+ significance of any particular value of any particular register.
+
+ @ingroup constant
+ */
+ static const uint8_t ku8MBIllegalDataValue = 0x03;
+
+ /**
+ Modbus protocol slave device failure exception.
+
+ An unrecoverable error occurred while the server (or slave) was
+ attempting to perform the requested action.
+
+ @ingroup constant
+ */
+ static const uint8_t ku8MBSlaveDeviceFailure = 0x04;
+
+ // Class-defined success/exception codes
+ /**
+ ModbusMaster success.
+
+ Modbus transaction was successful; the following checks were valid:
+ - slave ID
+ - function code
+ - response code
+ - data
+ - CRC
+
+ @ingroup constant
+ */
+ static const uint8_t ku8MBSuccess = 0x00;
+
+ /**
+ ModbusMaster invalid response slave ID exception.
+
+ The slave ID in the response does not match that of the request.
+
+ @ingroup constant
+ */
+ static const uint8_t ku8MBInvalidSlaveID = 0xE0;
+
+ /**
+ ModbusMaster invalid response function exception.
+
+ The function code in the response does not match that of the request.
+
+ @ingroup constant
+ */
+ static const uint8_t ku8MBInvalidFunction = 0xE1;
+
+ /**
+ ModbusMaster response timed out exception.
+
+ The entire response was not received within the timeout period,
+ ModbusMaster::ku8MBResponseTimeout.
+
+ @ingroup constant
+ */
+ static const uint8_t ku8MBResponseTimedOut = 0xE2;
+
+ /**
+ ModbusMaster invalid response CRC exception.
+
+ The CRC in the response does not match the one calculated.
+
+ @ingroup constant
+ */
+ static const uint8_t ku8MBInvalidCRC = 0xE3;
+
+ uint16_t getResponseBuffer(uint8_t);
+ void clearResponseBuffer();
+ uint8_t setTransmitBuffer(uint8_t, uint16_t);
+ void clearTransmitBuffer();
+
+ void beginTransmission(uint16_t);
+ uint8_t requestFrom(uint16_t, uint16_t);
+ void sendBit(bool);
+ void send(uint8_t);
+ void send(uint16_t);
+ void send(uint32_t);
+ uint8_t available(void);
+ uint16_t receive(void);
+
+
+ uint8_t readCoils(uint16_t, uint16_t);
+ uint8_t readDiscreteInputs(uint16_t, uint16_t);
+ uint8_t readHoldingRegisters(uint16_t, uint16_t);
+ uint8_t readInputRegisters(uint16_t, uint8_t);
+ uint8_t writeSingleCoil(uint16_t, uint8_t);
+ uint8_t writeSingleRegister(uint16_t, uint16_t);
+ uint8_t writeMultipleCoils(uint16_t, uint16_t);
+ uint8_t writeMultipleCoils();
+ uint8_t writeMultipleRegisters(uint16_t, uint16_t);
+ uint8_t writeMultipleRegisters();
+ uint8_t maskWriteRegister(uint16_t, uint16_t, uint16_t);
+ uint8_t readWriteMultipleRegisters(uint16_t, uint16_t, uint16_t, uint16_t);
+ uint8_t readWriteMultipleRegisters(uint16_t, uint16_t);
+
+ private:
+ Stream* _serial; ///< reference to serial port object
+ uint8_t _u8MBSlave; ///< Modbus slave (1..255) initialized in begin()
+ static const uint8_t ku8MaxBufferSize = 64; ///< size of response/transmit buffers
+ uint16_t _u16ReadAddress; ///< slave register from which to read
+ uint16_t _u16ReadQty; ///< quantity of words to read
+ uint16_t _u16ResponseBuffer[ku8MaxBufferSize]; ///< buffer to store Modbus slave response; read via GetResponseBuffer()
+ uint16_t _u16WriteAddress; ///< slave register to which to write
+ uint16_t _u16WriteQty; ///< quantity of words to write
+ uint16_t _u16TransmitBuffer[ku8MaxBufferSize]; ///< buffer containing data to transmit to Modbus slave; set via SetTransmitBuffer()
+ uint16_t* txBuffer; // from Wire.h -- need to clean this up Rx
+ uint8_t _u8TransmitBufferIndex;
+ uint16_t u16TransmitBufferLength;
+ uint16_t* rxBuffer; // from Wire.h -- need to clean this up Rx
+ uint8_t _u8ResponseBufferIndex;
+ uint8_t _u8ResponseBufferLength;
+
+ // Modbus function codes for bit access
+ static const uint8_t ku8MBReadCoils = 0x01; ///< Modbus function 0x01 Read Coils
+ static const uint8_t ku8MBReadDiscreteInputs = 0x02; ///< Modbus function 0x02 Read Discrete Inputs
+ static const uint8_t ku8MBWriteSingleCoil = 0x05; ///< Modbus function 0x05 Write Single Coil
+ static const uint8_t ku8MBWriteMultipleCoils = 0x0F; ///< Modbus function 0x0F Write Multiple Coils
+
+ // Modbus function codes for 16 bit access
+ static const uint8_t ku8MBReadHoldingRegisters = 0x03; ///< Modbus function 0x03 Read Holding Registers
+ static const uint8_t ku8MBReadInputRegisters = 0x04; ///< Modbus function 0x04 Read Input Registers
+ static const uint8_t ku8MBWriteSingleRegister = 0x06; ///< Modbus function 0x06 Write Single Register
+ static const uint8_t ku8MBWriteMultipleRegisters = 0x10; ///< Modbus function 0x10 Write Multiple Registers
+ static const uint8_t ku8MBMaskWriteRegister = 0x16; ///< Modbus function 0x16 Mask Write Register
+ static const uint8_t ku8MBReadWriteMultipleRegisters = 0x17; ///< Modbus function 0x17 Read Write Multiple Registers
+
+ // Modbus timeout [milliseconds]
+ static const uint16_t ku16MBResponseTimeout = 150; ///< Modbus timeout [milliseconds]
+
+ // master function that conducts Modbus transactions
+ uint8_t ModbusMasterTransaction(uint8_t u8MBFunction);
+
+ // idle callback function; gets called during idle time between TX and RX
+ void (*_idle)();
+ // preTransmission callback function; gets called before writing a Modbus message
+ void (*_preTransmission)();
+ // postTransmission callback function; gets called after a Modbus message has been sent
+ void (*_postTransmission)();
+};
+#endif
+
+/**
+@example examples/Basic/Basic.pde
+@example examples/PhoenixContact_nanoLC/PhoenixContact_nanoLC.pde
+@example examples/RS485_HalfDuplex/RS485_HalfDuplex.ino
+*/
diff --git a/lib/ModbusMaster/src/util/crc16.h b/lib/ModbusMaster/src/util/crc16.h
new file mode 100644
index 00000000..27ea89ec
--- /dev/null
+++ b/lib/ModbusMaster/src/util/crc16.h
@@ -0,0 +1,88 @@
+/**
+@file
+CRC Computations
+
+@defgroup util_crc16 "util/crc16.h": CRC Computations
+@code#include "util/crc16.h"@endcode
+
+This header file provides functions for calculating
+cyclic redundancy checks (CRC) using common polynomials.
+Modified by Doc Walker to be processor-independent (removed inline
+assembler to allow it to compile on SAM3X8E processors).
+
+@par References:
+Jack Crenshaw's "Implementing CRCs" article in the January 1992 issue of @e
+Embedded @e Systems @e Programming. This may be difficult to find, but it
+explains CRC's in very clear and concise terms. Well worth the effort to
+obtain a copy.
+
+*/
+/* Copyright (c) 2002, 2003, 2004 Marek Michalkiewicz
+ Copyright (c) 2005, 2007 Joerg Wunsch
+ Copyright (c) 2013 Dave Hylands
+ Copyright (c) 2013 Frederic Nadeau
+ Copyright (c) 2015 Doc Walker
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the name of the copyright holders nor the names of
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE. */
+
+
+#ifndef _UTIL_CRC16_H_
+#define _UTIL_CRC16_H_
+
+
+/** @ingroup util_crc16
+ Processor-independent CRC-16 calculation.
+
+ Polynomial: x^16 + x^15 + x^2 + 1 (0xA001)
+ Initial value: 0xFFFF
+
+ This CRC is normally used in disk-drive controllers.
+
+ @param uint16_t crc (0x0000..0xFFFF)
+ @param uint8_t a (0x00..0xFF)
+ @return calculated CRC (0x0000..0xFFFF)
+*/
+static uint16_t crc16_update(uint16_t crc, uint8_t a)
+{
+ int i;
+
+ crc ^= a;
+ for (i = 0; i < 8; ++i)
+ {
+ if (crc & 1)
+ crc = (crc >> 1) ^ 0xA001;
+ else
+ crc = (crc >> 1);
+ }
+
+ return crc;
+}
+
+
+#endif /* _UTIL_CRC16_H_ */
diff --git a/lib/ModbusMaster/src/util/word.h b/lib/ModbusMaster/src/util/word.h
new file mode 100644
index 00000000..c72ad944
--- /dev/null
+++ b/lib/ModbusMaster/src/util/word.h
@@ -0,0 +1,64 @@
+/**
+@file
+Utility Functions for Manipulating Words
+
+@defgroup util_word "util/word.h": Utility Functions for Manipulating Words
+@code#include "util/word.h"@endcode
+
+This header file provides utility functions for manipulating words.
+
+*/
+/*
+
+ word.h - Utility Functions for Manipulating Words
+
+ This file is part of ModbusMaster.
+
+ ModbusMaster is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ ModbusMaster 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with ModbusMaster. If not, see .
+
+ Written by Doc Walker (Rx)
+ Copyright © 2009-2015 Doc Walker <4-20ma at wvfans dot net>
+
+*/
+
+
+#ifndef _UTIL_WORD_H_
+#define _UTIL_WORD_H_
+
+
+/** @ingroup util_word
+ Return low word of a 32-bit integer.
+
+ @param uint32_t ww (0x00000000..0xFFFFFFFF)
+ @return low word of input (0x0000..0xFFFF)
+*/
+static inline uint16_t lowWord(uint32_t ww)
+{
+ return (uint16_t) ((ww) & 0xFFFF);
+}
+
+
+/** @ingroup util_word
+ Return high word of a 32-bit integer.
+
+ @param uint32_t ww (0x00000000..0xFFFFFFFF)
+ @return high word of input (0x0000..0xFFFF)
+*/
+static inline uint16_t highWord(uint32_t ww)
+{
+ return (uint16_t) ((ww) >> 16);
+}
+
+
+#endif /* _UTIL_WORD_H_ */
diff --git a/platformio.ini b/platformio.ini
index 4ee2b7d1..c8a85a0f 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -20,6 +20,7 @@ lib_deps_external =
Adafruit BMP280 Library
Adafruit BME280 Library
DallasTemperature
+ ESP Async UDP
lib_deps_internal =
ESP Async WebServer
GyverFilters
@@ -28,7 +29,6 @@ lib_deps_internal =
[env:esp32]
framework = arduino
board = esp32dev
-board_build.filesystem = littlefs
platform = https://github.com/platformio/platform-espressif32.git
lib_deps =
${common_env_data.lib_deps_external}
@@ -37,7 +37,9 @@ lib_deps =
ESP32Servo
LITTLEFS
monitor_filters = esp32_exception_decoder
+upload_speed = 921600
monitor_speed = 115200
+board_build.filesystem = littlefs
[env:esp8266_01_1m]
framework = arduino
@@ -51,8 +53,10 @@ lib_deps =
ESPAsyncUDP
EspSoftwareSerial
monitor_filters = esp8266_exception_decoder
+upload_speed = 921600
monitor_speed = 115200
board_build.filesystem = littlefs
+board_build.f_cpu = 160000000L
[env:esp8266]
framework = arduino
@@ -65,6 +69,7 @@ lib_deps =
ESPAsyncUDP
EspSoftwareSerial
monitor_filters = esp8266_exception_decoder
+upload_speed = 921600
monitor_speed = 115200
board_build.filesystem = littlefs
board_build.f_cpu = 160000000L
diff --git a/src/BufferExecute.cpp b/src/BufferExecute.cpp
new file mode 100644
index 00000000..ef78ca8d
--- /dev/null
+++ b/src/BufferExecute.cpp
@@ -0,0 +1,73 @@
+#include "BufferExecute.h"
+#include "Global.h"
+#include "Module/Terminal.h"
+#include "Errors.h"
+
+
+
+void loopCmdAdd(const String &cmdStr) {
+ orderBuf += cmdStr;
+ if (!cmdStr.endsWith(",")) {
+ orderBuf += ",";
+ }
+}
+
+void fileCmdExecute(const String &filename) {
+ String cmdStr = readFile(filename, 4096);
+ csvCmdExecute(cmdStr);
+}
+
+void csvCmdExecute(String &cmdStr) {
+
+ cmdStr.replace(";", " ");
+ cmdStr += "\r\n";
+ cmdStr.replace("\r\n", "\n");
+ cmdStr.replace("\r", "\n");
+ int count = 0;
+ while (cmdStr.length()) {
+ String buf = selectToMarker(cmdStr, "\n");
+ buf = deleteBeforeDelimiter(buf, " "); //отсечка чекбокса
+ count++;
+ if (count > 1) sCmd.readStr(buf);
+ cmdStr = deleteBeforeDelimiter(cmdStr, "\n");
+ }
+}
+
+void spaceCmdExecute(String &cmdStr) {
+ cmdStr += "\r\n";
+ cmdStr.replace("\r\n", "\n");
+ cmdStr.replace("\r", "\n");
+ while (cmdStr.length()) {
+ String buf = selectToMarker(cmdStr, "\n");
+ sCmd.readStr(buf);
+ cmdStr = deleteBeforeDelimiter(cmdStr, "\n");
+ }
+}
+
+void loopCmdExecute() {
+ if (orderBuf.length()) {
+ String tmp = selectToMarker(orderBuf, ","); //выделяем первую команду rel 5 1,
+ SerialPrint("I","CMD","do: " + tmp);
+ sCmd.readStr(tmp); //выполняем
+ orderBuf = deleteBeforeDelimiter(orderBuf, ","); //осекаем
+ }
+}
+
+void sensorsInit() {
+ ts.add(
+ SENSORS, 10000, [&](void *) {
+ String buf = sensorReadingMap;
+ while (buf.length()) {
+ String tmp = selectToMarker(buf, ",");
+ sCmd.readStr(tmp);
+ buf = deleteBeforeDelimiter(buf, ",");
+ }
+ },
+ nullptr, true);
+}
+
+//void loopSerial() {
+// if (term) {
+// term->loop();
+// }
+//}
diff --git a/src/Bus.cpp b/src/Bus.cpp
new file mode 100644
index 00000000..49cbaa54
--- /dev/null
+++ b/src/Bus.cpp
@@ -0,0 +1,38 @@
+#include "Bus.h"
+#include "Class/NotAsinc.h"
+#include "Global.h"
+
+void busInit() {
+ myNotAsincActions->add(
+ do_BUSSCAN, [&](void*) {
+ String tmp = i2c_scan();
+ if (tmp == "error") {
+ tmp = i2c_scan();
+ Serial.println(tmp);
+ jsonWriteStr(configLiveJson, "i2c", tmp);
+ } else {
+ Serial.println(tmp);
+ jsonWriteStr(configLiveJson, "i2c", tmp);
+ }
+ },
+ nullptr);
+}
+
+String i2c_scan() {
+ String out;
+ byte count = 0;
+ Wire.begin();
+ for (byte i = 8; i < 120; i++) {
+ Wire.beginTransmission(i);
+ if (Wire.endTransmission() == 0) {
+ count++;
+ out += String(count) + ". 0x" + String(i, HEX) + "; ";
+ delay(1);
+ }
+ }
+ if (count == 0) {
+ return "error";
+ } else {
+ return out;
+ }
+}
\ No newline at end of file
diff --git a/src/Bus/I2CScanner.cpp b/src/Bus/I2CScanner.cpp
deleted file mode 100644
index 669b2903..00000000
--- a/src/Bus/I2CScanner.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-#include "Bus/I2CScanner.h"
-#include "Utils/PrintMessage.h"
-
-#include
-
-static const char* MODULE = "I2C";
-
-I2CScanner::I2CScanner(String& out) : BusScanner(TAG_I2C, out, 2){};
-
-void I2CScanner::init() {
- Wire.begin();
-}
-
-boolean I2CScanner::syncScan() {
- pm.info("scanning...");
- size_t cnt = 0;
- for (uint8_t i = 8; i < 120; i++) {
- Wire.beginTransmission(i);
- if (Wire.endTransmission() == 0) {
- pm.info("found: " + i);
- addResult(i, i < 119);
- cnt++;
- }
- }
- return cnt;
-}
\ No newline at end of file
diff --git a/src/Class/Button.cpp b/src/Class/Button.cpp
deleted file mode 100644
index 220de75d..00000000
--- a/src/Class/Button.cpp
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "Class/Button.h"
-Button* myButton;
\ No newline at end of file
diff --git a/src/Class/CallBackTest.cpp b/src/Class/CallBackTest.cpp
new file mode 100644
index 00000000..55252e5e
--- /dev/null
+++ b/src/Class/CallBackTest.cpp
@@ -0,0 +1,49 @@
+#include "Class/CallBackTest.h"
+
+CallBackTest::CallBackTest(){};
+
+void CallBackTest::loop() {
+ count++;
+ if (count > 5000) {
+ // Проверяем что переменная содержит указатель - не пустая не null
+ // и непосредственно вызываем то, на что это указывает
+ // просто пишем имя - без () - это указатель на фунецию.
+ // () - вызываем функцию - с пустым набором параметров
+
+ if (_cb != NULL) {
+ _cb();
+ }
+ //или ровно тоже самое
+ //if (_cb) _cb();
+
+ if (_pcb) {
+ if (_pcb("SomeTextValue")) {
+ Serial.println("Got true!");
+ } else {
+ Serial.println("Got false!");
+ }
+ }
+
+ count = 0;
+ }
+}
+
+//передаем внутрь класса функцию любую void функцию без агрументов
+void CallBackTest::setCallback(AsyncActionCb cb) {
+ _cb = cb;
+}
+
+//передаем внутрь класса функцию любую void функцию с аргументами
+void CallBackTest::setCallback(AsyncParamActionCb pcb) {
+ _pcb = pcb;
+}
+//CallBackTest* CB;
+
+//CB->setCallback([]() {
+// Serial.println("123");
+//});
+//
+//CB->setCallback([](const String str) {
+// Serial.println(str);
+// return true;
+//});
\ No newline at end of file
diff --git a/src/Class/Input.cpp b/src/Class/Input.cpp
deleted file mode 100644
index 43f4df0a..00000000
--- a/src/Class/Input.cpp
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "Class/Input.h"
-Input* myInput;
\ No newline at end of file
diff --git a/src/Class/NotAsinc.cpp b/src/Class/NotAsinc.cpp
new file mode 100644
index 00000000..f1c8f5f9
--- /dev/null
+++ b/src/Class/NotAsinc.cpp
@@ -0,0 +1,30 @@
+#include "Class/NotAsinc.h"
+
+NotAsinc::NotAsinc(uint8_t size) {
+ this->items = new NotAsincItem[size];
+ this->size = size;
+}
+
+NotAsinc::~NotAsinc() {}
+
+void NotAsinc::add(uint8_t i, NotAsincCb f, void* arg) {
+ this->items[i].cb = f;
+ this->items[i].cb_arg = arg;
+ this->items[i].is_used = true;
+}
+
+void NotAsinc::loop() {
+ if (this->items[task].is_used) {
+ handle(this->items[task].cb, this->items[task].cb_arg);
+ task = 0;
+ }
+}
+
+void NotAsinc::make(uint8_t task) {
+ this->task = task;
+}
+
+void NotAsinc::handle(NotAsincCb f, void* arg) {
+ f(arg);
+}
+NotAsinc* myNotAsincActions;
\ No newline at end of file
diff --git a/src/Class/Pwm.cpp b/src/Class/Pwm.cpp
deleted file mode 100644
index 5e2d6ce9..00000000
--- a/src/Class/Pwm.cpp
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "Class/Pwm.h"
-Pwm* myPwm;
\ No newline at end of file
diff --git a/src/Class/ScenarioClass.cpp b/src/Class/ScenarioClass.cpp
new file mode 100644
index 00000000..d066cc62
--- /dev/null
+++ b/src/Class/ScenarioClass.cpp
@@ -0,0 +1,2 @@
+#include "Class/ScenarioClass.h"
+Scenario* myScenario;
\ No newline at end of file
diff --git a/src/Class/Switch.cpp b/src/Class/Switch.cpp
deleted file mode 100644
index 9bbf7c4e..00000000
--- a/src/Class/Switch.cpp
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "Class/Switch.h"
-Switch* mySwitch;
\ No newline at end of file
diff --git a/src/Cmd.cpp b/src/Cmd.cpp
deleted file mode 100644
index 22606ca2..00000000
--- a/src/Cmd.cpp
+++ /dev/null
@@ -1,491 +0,0 @@
-#include "Cmd.h"
-
-#include "Class/Button.h"
-#include "Class/Input.h"
-#include "Class/LineParsing.h"
-#include "Class/Pwm.h"
-#include "Class/Switch.h"
-//-----------------------------
-#include "Global.h"
-#include "Module/Terminal.h"
-#include "Servo/Servos.h"
-
-static const char *MODULE = "Cmd";
-
-Terminal *term = nullptr;
-
-boolean but[NUM_BUTTONS];
-Bounce *buttons = new Bounce[NUM_BUTTONS];
-
-#ifdef ESP8266
-SoftwareSerial *mySerial = nullptr;
-#else
-HardwareSerial *mySerial = nullptr;
-#endif
-
-void getData();
-
-void cmd_init() {
- sCmd.addCommand("button-out", buttonOut);
- sCmd.addCommand("pwm-out", pwmOut);
- sCmd.addCommand("button-in", buttonIn);
- sCmd.addCommand("input-digit", inputDigit);
- sCmd.addCommand("input-time", inputTime);
-
- sCmd.addCommand("text", text);
- sCmd.addCommand("textSet", textSet);
-
-
-
-
- sCmd.addCommand("timerStart", timerStart_);
- sCmd.addCommand("timerStop", timerStop_);
-
-
-
-#ifdef ANALOG_ENABLED
- sCmd.addCommand("analog", analog);
-#endif
-#ifdef LEVEL_ENABLED
- sCmd.addCommand("levelPr", levelPr);
- sCmd.addCommand("ultrasonicCm", ultrasonicCm);
-#endif
-#ifdef DALLAS_ENABLED
- sCmd.addCommand("dallas", dallas);
-#endif
-#ifdef DHT_ENABLED
- sCmd.addCommand("dhtT", dhtT);
- sCmd.addCommand("dhtH", dhtH);
- sCmd.addCommand("dhtPerception", dhtP);
- sCmd.addCommand("dhtComfort", dhtC);
- sCmd.addCommand("dhtDewpoint", dhtD);
-#endif
-
-#ifdef BMP_ENABLED
- sCmd.addCommand("bmp280T", bmp280T);
- sCmd.addCommand("bmp280P", bmp280P);
-#endif
-
-#ifdef BME_ENABLED
- sCmd.addCommand("bme280T", bme280T);
- sCmd.addCommand("bme280P", bme280P);
- sCmd.addCommand("bme280H", bme280H);
- sCmd.addCommand("bme280A", bme280A);
-#endif
-
-#ifdef STEPPER_ENABLED
- sCmd.addCommand("stepper", stepper);
- sCmd.addCommand("stepperSet", stepperSet);
-#endif
-
-#ifdef SERVO_ENABLED
- sCmd.addCommand("servo", servo_);
- sCmd.addCommand("servoSet", servoSet);
-#endif
-
-#ifdef SERIAL_ENABLED
- sCmd.addCommand("serialBegin", serialBegin);
- sCmd.addCommand("serialWrite", serialWrite);
- sCmd.addCommand("getData", getData);
-#endif
-
-#ifdef LOGGING_ENABLED
- sCmd.addCommand("logging", logging);
-#endif
-
- sCmd.addCommand("mqtt", mqttOrderSend);
- sCmd.addCommand("http", httpOrderSend);
-
-#ifdef PUSH_ENABLED
- sCmd.addCommand("push", pushControl);
-#endif
-
- sCmd.addCommand("firmwareUpdate", firmwareUpdate);
- sCmd.addCommand("firmwareVersion", firmwareVersion);
-
- handle_time_init();
-}
-
-//==========================================Модуль кнопок===================================================
-//button-out light toggle Кнопки Свет 1 pin[12] inv[1] st[1]
-//==========================================================================================================
-void buttonOut() {
- myButton = new Button();
- myButton->update();
- String key = myButton->gkey();
- String pin = myButton->gpin();
- String inv = myButton->ginv();
- sCmd.addCommand(key.c_str(), buttonOutSet);
- jsonWriteStr(configOptionJson, key + "_pin", pin);
- jsonWriteStr(configOptionJson, key + "_inv", inv);
- myButton->pinModeSet();
- myButton->pinStateSetDefault();
- myButton->pinStateSetInvDefault();
- myButton->clear();
-}
-
-void buttonOutSet() {
- String key = sCmd.order();
- String state = sCmd.next();
- String pin = jsonReadStr(configOptionJson, key + "_pin");
- String inv = jsonReadStr(configOptionJson, key + "_inv");
- if (inv == "") {
- myButton->pinChange(key, pin, state, true);
- } else {
- myButton->pinChange(key, pin, state, false);
- }
-}
-
-//==========================================Модуль управления ШИМ===================================================
-//pwm-out volume range Кнопки Свет 1 pin[12] st[500]
-//==================================================================================================================
-void pwmOut() {
- myPwm = new Pwm();
- myPwm->update();
- String key = myPwm->gkey();
- String pin = myPwm->gpin();
- String inv = myPwm->ginv();
- sCmd.addCommand(key.c_str(), pwmOutSet);
- jsonWriteStr(configOptionJson, key + "_pin", pin);
- myPwm->pwmModeSet();
- myPwm->pwmStateSetDefault();
- myPwm->clear();
-}
-
-void pwmOutSet() {
- String key = sCmd.order();
- String state = sCmd.next();
- String pin = jsonReadStr(configOptionJson, key + "_pin");
- myPwm->pwmChange(key, pin, state);
-}
-
-//==========================================Модуль физических кнопок========================================
-//button-in switch1 toggle Кнопки Свет 1 pin[2] db[20]
-//==========================================================================================================
-void buttonIn() {
- mySwitch = new Switch();
- mySwitch->update();
- String key = mySwitch->gkey();
- String pin = mySwitch->gpin();
- sCmd.addCommand(key.c_str(), buttonInSet);
- mySwitch->init();
- mySwitch->switchStateSetDefault();
- mySwitch->clear();
-}
-
-void buttonInSet() {
- String key = sCmd.order();
- String state = sCmd.next();
- mySwitch->switchChangeVirtual(key, state);
-}
-
-//==========================================Модуль ввода цифровых значений==================================
-//input-digit digit1 inputDigit Ввод Введите.цифру 4 st[60]
-//==========================================================================================================
-void inputDigit() {
- myInput = new Input();
- myInput->update();
- String key = myInput->gkey();
- sCmd.addCommand(key.c_str(), inputDigitSet);
- myInput->inputSetDefaultFloat();
- myInput->clear();
-}
-
-void inputDigitSet() {
- String key = sCmd.order();
- String state = sCmd.next();
- myInput->inputSetFloat(key, state);
-}
-
-//==========================================Модуль ввода времени============================================
-//input-time time1 inputTime Ввод Введите.время 4 st[10-00-00]
-//==========================================================================================================
-void inputTime() {
- myInput = new Input();
- myInput->update();
- String key = myInput->gkey();
- sCmd.addCommand(key.c_str(), inputTimeSet);
- myInput->inputSetDefaultStr();
- myInput->clear();
-}
-
-void inputTimeSet() {
- String key = sCmd.order();
- String state = sCmd.next();
- myInput->inputSetStr(key, state);
-}
-
-void handle_time_init() {
- ts.add(
- TIME, 1000, [&](void *) {
- jsonWriteStr(configLiveJson, "time", timeNow->getTime());
- jsonWriteStr(configLiveJson, "timenow", timeNow->getTimeJson());
- eventGen("timenow", "");
- },
- nullptr, true);
-}
-
-//=====================================================================================================================================
-//=========================================Добавление текстового виджета============================================================
-void text() {
- String number = sCmd.next();
- String widget_name = sCmd.next();
- String page_name = sCmd.next();
- String page_number = sCmd.next();
-
- createWidget(widget_name, page_name, page_number, "anydata", "text" + number);
-}
-
-void textSet() {
- String number = sCmd.next();
- String text = sCmd.next();
- text.replace("_", " ");
-
- if (text.indexOf("-time") >= 0) {
- text.replace("-time", "");
- text.replace("#", " ");
- text = text + " " + timeNow->getDateTimeDotFormated();
- }
-
- jsonWriteStr(configLiveJson, "text" + number, text);
- MqttClient::publishStatus("text" + number, text);
-}
-//=====================================================================================================================================
-//=========================================Модуль шагового мотора======================================================================
-#ifdef STEPPER_ENABLED
-//stepper 1 12 13
-void stepper() {
- String stepper_number = sCmd.next();
- String pin_step = sCmd.next();
- String pin_dir = sCmd.next();
-
- jsonWriteStr(configOptionJson, "stepper" + stepper_number, pin_step + " " + pin_dir);
- pinMode(pin_step.toInt(), OUTPUT);
- pinMode(pin_dir.toInt(), OUTPUT);
-}
-
-//stepperSet 1 100 5
-void stepperSet() {
- String stepper_number = sCmd.next();
- String steps = sCmd.next();
- jsonWriteStr(configOptionJson, "steps" + stepper_number, steps);
- String stepper_speed = sCmd.next();
- String pin_step = selectToMarker(jsonReadStr(configOptionJson, "stepper" + stepper_number), " ");
- String pin_dir = deleteBeforeDelimiter(jsonReadStr(configOptionJson, "stepper" + stepper_number), " ");
- Serial.println(pin_step);
- Serial.println(pin_dir);
- if (steps.toInt() > 0) digitalWrite(pin_dir.toInt(), HIGH);
- if (steps.toInt() < 0) digitalWrite(pin_dir.toInt(), LOW);
- if (stepper_number == "1") {
- ts.add(
- STEPPER1, stepper_speed.toInt(), [&](void *) {
- int steps_int = abs(jsonReadInt(configOptionJson, "steps1") * 2);
- static int count;
- count++;
- String pin_step = selectToMarker(jsonReadStr(configOptionJson, "stepper1"), " ");
- digitalWrite(pin_step.toInt(), !digitalRead(pin_step.toInt()));
- yield();
- if (count > steps_int) {
- digitalWrite(pin_step.toInt(), LOW);
- ts.remove(STEPPER1);
- count = 0;
- }
- },
- nullptr, true);
- }
- if (stepper_number == "2") {
- ts.add(
- STEPPER2, stepper_speed.toInt(), [&](void *) {
- int steps_int = abs(jsonReadInt(configOptionJson, "steps2") * 2);
- static int count;
- count++;
- String pin_step = selectToMarker(jsonReadStr(configOptionJson, "stepper2"), " ");
- digitalWrite(pin_step.toInt(), !digitalRead(pin_step.toInt()));
- yield();
- if (count > steps_int) {
- digitalWrite(pin_step.toInt(), LOW);
- ts.remove(STEPPER2);
- count = 0;
- }
- },
- nullptr, true);
- }
-}
-#endif
-//====================================================================================================================================================
-//=================================================================Сервоприводы=======================================================================
-#ifdef SERVO_ENABLED
-//servo 1 13 50 Мой#сервопривод Сервоприводы 0 100 0 180 2
-void servo_() {
- String number = sCmd.next();
- uint8_t pin = String(sCmd.next()).toInt();
- int value = String(sCmd.next()).toInt();
-
- String widget = sCmd.next();
- String page = sCmd.next();
-
- int min_value = String(sCmd.next()).toInt();
- int max_value = String(sCmd.next()).toInt();
- int min_deg = String(sCmd.next()).toInt();
- int max_deg = String(sCmd.next()).toInt();
-
- String pageNumber = sCmd.next();
-
- jsonWriteStr(configOptionJson, "servo_pin" + number, String(pin, DEC));
-
- value = map(value, min_value, max_value, min_deg, max_deg);
-
- Servo *servo = myServo.create(number.toInt(), pin);
- servo->write(value);
-#ifdef ESP32
- myServo1.attach(servo_pin.toInt(), 500, 2400);
- myServo1.write(start_state_int);
-#endif
-
- jsonWriteInt(configOptionJson, "s_min_val" + number, min_value);
- jsonWriteInt(configOptionJson, "s_max_val" + number, max_value);
- jsonWriteInt(configOptionJson, "s_min_deg" + number, min_deg);
- jsonWriteInt(configOptionJson, "s_max_deg" + number, max_deg);
-
- jsonWriteInt(configLiveJson, "servo" + number, value);
-
- createWidgetParam(widget, page, pageNumber, "range", "servo" + number, "min", String(min_value), "max", String(max_value), "k", "1");
-}
-
-void servoSet() {
- String number = sCmd.next();
- int value = String(sCmd.next()).toInt();
-
- value = map(value,
- jsonReadInt(configOptionJson, "s_min_val" + number),
- jsonReadInt(configOptionJson, "s_max_val" + number),
- jsonReadInt(configOptionJson, "s_min_deg" + number),
- jsonReadInt(configOptionJson, "s_max_deg" + number));
-
- Servo *servo = myServo.get(number.toInt());
- if (servo) {
- servo->write(value);
- }
-
- eventGen("servo", number);
- jsonWriteInt(configLiveJson, "servo" + number, value);
- MqttClient::publishStatus("servo" + number, String(value, DEC));
-}
-#endif
-//====================================================================================================================================================
-//=============================================================Модуль сериал порта=======================================================================
-
-#ifdef SERIAL_ENABLED
-void serialBegin() {
- String s_speed = sCmd.next();
- String rxPin = sCmd.next();
- String txPin = sCmd.next();
-
- if (mySerial) {
- delete mySerial;
- }
-
-#ifdef ESP8266
- mySerial = new SoftwareSerial(rxPin.toInt(), txPin.toInt());
- mySerial->begin(s_speed.toInt());
-#else
- mySerial = new HardwareSerial(2);
- mySerial->begin(rxPin.toInt(), txPin.toInt());
-#endif
-
- term = new Terminal(mySerial);
- term->setEOL(LF);
- term->enableColors(false);
- term->enableControlCodes(false);
- term->enableEcho(false);
- term->setOnReadLine([](const char *str) {
- String line = String(str);
- addCommandLoop(line);
- });
-}
-
-void getData() {
- String param = sCmd.next();
- String res = param.length() ? jsonReadStr(configLiveJson, param) : configLiveJson;
- if (term) {
- term->println(res.c_str());
- }
-}
-
-void serialWrite() {
- String payload = sCmd.next();
- if (term) {
- term->println(payload.c_str());
- }
-}
-#endif
-//====================================================================================================================================================
-//=================================================Глобальные команды удаленного управления===========================================================
-
-void mqttOrderSend() {
- String id = sCmd.next();
- String order = sCmd.next();
-
- String all_line = jsonReadStr(configSetupJson, "mqttPrefix") + "/" + id + "/order";
- mqtt.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);
-}
-
-void firmwareUpdate() {
- updateFlag = true;
-}
-
-void firmwareVersion() {
- String widget = sCmd.next();
- String page = sCmd.next();
- String pageNumber = sCmd.next();
-
- jsonWriteStr(configLiveJson, "firmver", FIRMWARE_VERSION);
- createWidget(widget, page, pageNumber, "anydata", "firmver");
-}
-
-void addCommandLoop(const String &cmdStr) {
- order_loop += cmdStr;
- if (!cmdStr.endsWith(",")) {
- order_loop += ",";
- }
-}
-
-void fileExecute(const String &filename) {
- String cmdStr = readFile(filename, 2048);
- stringExecute(cmdStr);
-}
-
-void stringExecute(String &cmdStr) {
- cmdStr += "\r\n";
- cmdStr.replace("\r\n", "\n");
- cmdStr.replace("\r", "\n");
-
- while (cmdStr.length()) {
- String buf = selectToMarker(cmdStr, "\n");
- sCmd.readStr(buf);
- cmdStr = deleteBeforeDelimiter(cmdStr, "\n");
- }
-}
-
-void loopCmd() {
- if (order_loop.length()) {
- String tmp = selectToMarker(order_loop, ","); //выделяем первую команду rel 5 1,
- pm.info("do: " + tmp);
- sCmd.readStr(tmp); //выполняем
- order_loop = deleteBeforeDelimiter(order_loop, ","); //осекаем
- }
-}
-
-void loopSerial() {
- if (term) {
- term->loop();
- }
-}
diff --git a/src/FSEditor.cpp b/src/FSEditor.cpp
new file mode 100644
index 00000000..bdaa5129
--- /dev/null
+++ b/src/FSEditor.cpp
@@ -0,0 +1,326 @@
+#include "FSEditor.h"
+
+#ifdef ESP32
+#include "LITTLEFS.h"
+#define LittleFS LITTLEFS
+#endif
+#ifdef ESP8266
+#include
+#endif
+
+#define FS_MAXLENGTH_FILEPATH 32
+
+const char *excludeListFile = "/.exclude.files";
+
+typedef struct ExcludeListS {
+ char *item;
+ ExcludeListS *next;
+} ExcludeList;
+
+static ExcludeList *excludes = NULL;
+
+static bool matchWild(const char *pattern, const char *testee) {
+ const char *nxPat = NULL, *nxTst = NULL;
+
+ while (*testee) {
+ if ((*pattern == '?') || (*pattern == *testee)) {
+ pattern++;
+ testee++;
+ continue;
+ }
+ if (*pattern == '*') {
+ nxPat = pattern++;
+ nxTst = testee;
+ continue;
+ }
+ if (nxPat) {
+ pattern = nxPat + 1;
+ testee = ++nxTst;
+ continue;
+ }
+ return false;
+ }
+ while (*pattern == '*') {
+ pattern++;
+ }
+ return (*pattern == 0);
+}
+
+static bool addExclude(const char *item) {
+ size_t len = strlen(item);
+ if (!len) {
+ return false;
+ }
+ ExcludeList *e = (ExcludeList *)malloc(sizeof(ExcludeList));
+ if (!e) {
+ return false;
+ }
+ e->item = (char *)malloc(len + 1);
+ if (!e->item) {
+ free(e);
+ return false;
+ }
+ memcpy(e->item, item, len + 1);
+ e->next = excludes;
+ excludes = e;
+ return true;
+}
+
+static void loadExcludeList(fs::FS &_fs, const char *filename) {
+ static char linebuf[FS_MAXLENGTH_FILEPATH];
+ fs::File excludeFile = _fs.open(filename, "r");
+ if (!excludeFile) {
+ return;
+ }
+ if (excludeFile.isDirectory()) {
+ excludeFile.close();
+ return;
+ }
+ if (excludeFile.size() > 0) {
+ uint8_t idx;
+ bool isOverflowed = false;
+ while (excludeFile.available()) {
+ linebuf[0] = '\0';
+ idx = 0;
+ int lastChar;
+ do {
+ lastChar = excludeFile.read();
+ if (lastChar != '\r') {
+ linebuf[idx++] = (char)lastChar;
+ }
+ } while ((lastChar >= 0) && (lastChar != '\n') && (idx < FS_MAXLENGTH_FILEPATH));
+
+ if (isOverflowed) {
+ isOverflowed = (lastChar != '\n');
+ continue;
+ }
+ isOverflowed = (idx >= FS_MAXLENGTH_FILEPATH);
+ linebuf[idx - 1] = '\0';
+ if (!addExclude(linebuf)) {
+ excludeFile.close();
+ return;
+ }
+ }
+ }
+ excludeFile.close();
+}
+
+static bool isExcluded(fs::FS &_fs, const char *filename) {
+ if (excludes == NULL) {
+ loadExcludeList(_fs, excludeListFile);
+ }
+ if (strcmp(excludeListFile, filename) == 0) return true;
+ ExcludeList *e = excludes;
+ while (e) {
+ if (matchWild(e->item, filename)) {
+ return true;
+ }
+ e = e->next;
+ }
+ return false;
+}
+
+// WEB HANDLER IMPLEMENTATION
+
+#ifdef ESP32
+FSEditor::FSEditor(const fs::FS &fs, const String &username, const String &password)
+#else
+FSEditor::FSEditor(const String &username, const String &password, const fs::FS &fs)
+#endif
+ : _fs(fs), _username(username), _password(password), _authenticated(false), _startTime(0) {
+}
+
+bool FSEditor::canHandle(AsyncWebServerRequest *request) {
+ if (request->url().equalsIgnoreCase("/edit")) {
+ if (request->method() == HTTP_GET) {
+ if (request->hasParam("list"))
+ return true;
+ if (request->hasParam("edit")) {
+ request->_tempFile = _fs.open(request->arg("edit"), "r");
+ if (!request->_tempFile) {
+ return false;
+ }
+ if (request->_tempFile.isDirectory()) {
+ request->_tempFile.close();
+ return false;
+ }
+ }
+ if (request->hasParam("download")) {
+ request->_tempFile = _fs.open(request->arg("download"), "r");
+ if (!request->_tempFile) {
+ return false;
+ }
+ if (request->_tempFile.isDirectory()) {
+ request->_tempFile.close();
+ return false;
+ }
+ }
+ request->addInterestingHeader("If-Modified-Since");
+ return true;
+ } else if (request->method() == HTTP_POST)
+ return true;
+ else if (request->method() == HTTP_DELETE)
+ return true;
+ else if (request->method() == HTTP_PUT)
+ return true;
+ }
+ return false;
+}
+
+void FSEditor::handleRequest(AsyncWebServerRequest *request) {
+ if (_username.length() && _password.length() && !request->authenticate(_username.c_str(), _password.c_str()))
+ return request->requestAuthentication();
+
+ if (request->method() == HTTP_GET) {
+ if (request->hasParam("list")) {
+ String path = request->getParam("list")->value();
+#ifdef ESP32
+ File dir = _fs.open(path);
+#else
+ fs::Dir dir = _fs.openDir(path);
+#endif
+ path = String();
+ String output = "[";
+#ifdef ESP32
+ File entry = dir.openNextFile();
+ while (entry) {
+#else
+ while (dir.next()) {
+ fs::File entry = dir.openFile("r");
+#endif
+ String fname = entry.fullName();
+ if (fname.charAt(0) != '/') fname = "/" + fname;
+
+ if (isExcluded(_fs, fname.c_str())) {
+#ifdef ESP32
+ entry = dir.openNextFile();
+#endif
+ continue;
+ }
+ if (output != "[") output += ',';
+ output += "{\"type\":\"";
+ output += "file";
+ output += "\",\"name\":\"";
+ output += String(fname);
+ output += "\",\"size\":";
+ output += String(entry.size());
+ output += "}";
+#ifdef ESP32
+ entry = dir.openNextFile();
+#else
+ entry.close();
+#endif
+ }
+#ifdef ESP32
+ dir.close();
+#endif
+ output += "]";
+ request->send(200, "application/json", output);
+ output = String();
+ } else if (request->hasParam("edit") || request->hasParam("download")) {
+ request->send(request->_tempFile, request->_tempFile.fullName(), String(), request->hasParam("download"));
+ } else {
+ const char *buildTime = __DATE__ " " __TIME__ " GMT";
+ if (request->header("If-Modified-Since").equals(buildTime)) {
+ request->send(304);
+ } else {
+ AsyncWebServerResponse *response = request->beginResponse(LittleFS, "/edit.htm", "text/html");
+ // response->addHeader("Content-Encoding", "gzip");
+ response->addHeader("Last-Modified", buildTime);
+ request->send(response);
+ }
+ }
+ } else if (request->method() == HTTP_DELETE) {
+ if (request->hasParam("path", true)) {
+ if (!(_fs.remove(request->getParam("path", true)->value()))) {
+#ifdef ESP32
+ _fs.rmdir(request->getParam("path", true)->value()); // try rmdir for littlefs
+#endif
+ }
+
+ request->send(200, "", "DELETE: " + request->getParam("path", true)->value());
+ } else
+ request->send(404);
+ } else if (request->method() == HTTP_POST) {
+ if (request->hasParam("data", true, true) && _fs.exists(request->getParam("data", true, true)->value()))
+ request->send(200, "", "UPLOADED: " + request->getParam("data", true, true)->value());
+
+ else if (request->hasParam("rawname", true) && request->hasParam("raw0", true)) {
+ String rawnam = request->getParam("rawname", true)->value();
+
+ if (_fs.exists(rawnam)) _fs.remove(rawnam); // delete it to allow a mode
+
+ int k = 0;
+ uint16_t i = 0;
+ fs::File f = _fs.open(rawnam, "a");
+
+ while (request->hasParam("raw" + String(k), true)) { //raw0 .. raw1
+ if (f) {
+ i += f.print(request->getParam("raw" + String(k), true)->value());
+ }
+ k++;
+ }
+ f.close();
+ request->send(200, "", "IPADWRITE: " + rawnam + ":" + String(i));
+
+ } else {
+ request->send(500);
+ }
+
+ } else if (request->method() == HTTP_PUT) {
+ if (request->hasParam("path", true)) {
+ String filename = request->getParam("path", true)->value();
+ if (_fs.exists(filename)) {
+ request->send(200);
+ } else {
+/*******************************************************/
+#ifdef ESP32
+ if (strchr(filename.c_str(), '/')) {
+ // For file creation, silently make subdirs as needed. If any fail,
+ // it will be caught by the real file open later on
+ char *pathStr = strdup(filename.c_str());
+ if (pathStr) {
+ // Make dirs up to the final fnamepart
+ char *ptr = strchr(pathStr, '/');
+ while (ptr) {
+ *ptr = 0;
+ _fs.mkdir(pathStr);
+ *ptr = '/';
+ ptr = strchr(ptr + 1, '/');
+ }
+ }
+ free(pathStr);
+ }
+#endif
+ /*******************************************************/
+ fs::File f = _fs.open(filename, "w");
+ if (f) {
+ f.write((uint8_t)0x00);
+ f.close();
+ request->send(200, "", "CREATE: " + filename);
+ } else {
+ request->send(500);
+ }
+ }
+ } else
+ request->send(400);
+ }
+}
+
+void FSEditor::handleUpload(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final) {
+ if (!index) {
+ if (!_username.length() || request->authenticate(_username.c_str(), _password.c_str())) {
+ _authenticated = true;
+ request->_tempFile = _fs.open(filename, "w");
+ _startTime = millis();
+ }
+ }
+ if (_authenticated && request->_tempFile) {
+ if (len) {
+ request->_tempFile.write(data, len);
+ }
+ if (final) {
+ request->_tempFile.close();
+ }
+ }
+}
diff --git a/src/Global.cpp b/src/Global.cpp
index 05b51345..2c033a2d 100644
--- a/src/Global.cpp
+++ b/src/Global.cpp
@@ -4,21 +4,13 @@
AsyncWebSocket ws;
//AsyncEventSource events;
#endif
-
Clock* timeNow;
-
TickerScheduler ts(TEST + 1);
-
WiFiClient espClient;
-
PubSubClient mqtt(espClient);
-
StringCommand sCmd;
-
AsyncWebServer server(80);
-
OneWire *oneWire;
-
DallasTemperature sensors;
/*
@@ -37,30 +29,17 @@ String chipId = "";
String prex = "";
String all_widgets = "";
String scenario = "";
-String order_loop = "";
+
+//orders and events
+String orderBuf = "";
+String eventBuf = "";
+
+String itemsFile = "";
+String itemsLine = "";
// Sensors
-String analog_value_names_list;
-int enter_to_analog_counter;
-
-String dallas_value_name;
-int enter_to_dallas_counter;
-
-String levelPr_value_name;
-String ultrasonicCm_value_name;
-
-String dhtT_value_name;
-String dhtH_value_name;
-
-String bmp280T_value_name;
-String bmp280P_value_name;
-
-String bme280T_value_name;
-String bme280P_value_name;
-String bme280H_value_name;
-String bme280A_value_name;
-
-int sensors_reading_map[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+int8_t dallasEnterCounter = -1;
+String sensorReadingMap;
// Logging
String logging_value_names_list;
@@ -68,17 +47,9 @@ int enter_to_logging_counter;
// Scenario
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};
+int lastVersion;
-String lastVersion = "";
-
-// Async actions
-boolean checkUpdatesFlag = false;
-boolean updateFlag = false;
-
-boolean mqttParamsChanged = false;
-boolean udp_data_parse = false;
-boolean mqtt_send_settings_to_udp = false;
-
-BusScanner_t busToScan;
boolean busScanFlag = false;
boolean fsCheckFlag = false;
+boolean delElementFlag = false;
+
diff --git a/src/Init.cpp b/src/Init.cpp
index b5e79442..e704cc1d 100644
--- a/src/Init.cpp
+++ b/src/Init.cpp
@@ -9,7 +9,7 @@ void loadConfig() {
configSetupJson.replace("\r\n", "");
jsonWriteStr(configSetupJson, "chipID", chipId);
- jsonWriteStr(configSetupJson, "firmware_version", FIRMWARE_VERSION);
+ jsonWriteInt(configSetupJson, "firmware_version", FIRMWARE_VERSION);
prex = jsonReadStr(configSetupJson, "mqttPrefix") + "/" + chipId;
@@ -23,38 +23,33 @@ void all_init() {
}
void Device_init() {
- logging_value_names_list = "";
- enter_to_logging_counter = LOG1 - 1;
- analog_value_names_list = "";
- enter_to_analog_counter = 0;
+ sensorReadingMap = "";
+ dallasEnterCounter = -1;
- dallas_value_name = "";
- enter_to_dallas_counter = 0;
-
- levelPr_value_name = "";
- ultrasonicCm_value_name = "";
-
- dhtT_value_name = "";
- dhtH_value_name = "";
-
- bmp280T_value_name = "";
- bmp280P_value_name = "";
-
- bme280T_value_name = "";
- bme280P_value_name = "";
- bme280H_value_name = "";
- bme280A_value_name = "";
-
- int array_sz = sizeof(sensors_reading_map) / sizeof(sensors_reading_map[0]);
-
- for (int i = 0; i < array_sz; i++) {
- sensors_reading_map[i] = 0;
- }
-
- for (int i = LOG1; i <= LOG5; i++) {
- ts.remove(i);
- }
+ //logging_value_names_list = "";
+ //enter_to_logging_counter = LOG1 - 1;
+ //analog_value_names_list = "";
+ //enter_to_analog_counter = 0;
+ //dallas_value_name = "";
+ //enter_to_dallas_counter = 0;
+ //levelPr_value_name = "";
+ //ultrasonicCm_value_name = "";
+ //dhtT_value_name = "";
+ //dhtH_value_name = "";
+ //bmp280T_value_name = "";
+ //bmp280P_value_name = "";
+ //bme280T_value_name = "";
+ //bme280P_value_name = "";
+ //bme280H_value_name = "";
+ //bme280A_value_name = "";
+ //int array_sz = sizeof(sensors_reading_map) / sizeof(sensors_reading_map[0]);
+ //for (int i = 0; i < array_sz; i++) {
+ // sensors_reading_map[i] = 0;
+ //}
+ //for (int i = LOG1; i <= LOG5; i++) {
+ // ts.remove(i);
+ //}
#ifdef LAYOUT_IN_RAM
all_widgets = "";
@@ -62,7 +57,8 @@ void Device_init() {
removeFile(String("layout.txt"));
#endif
- fileExecute(String(DEVICE_CONFIG_FILE));
+
+ fileCmdExecute(String(DEVICE_CONFIG_FILE));
//outcoming_date();
}
//-------------------------------сценарии-----------------------------------------------------
@@ -81,42 +77,34 @@ void uptime_init() {
nullptr, true);
}
-void telemetry_init() {
- if (TELEMETRY_UPDATE_INTERVAL) {
- ts.add(
- STATISTICS, TELEMETRY_UPDATE_INTERVAL, [&](void*) {
- handle_statistics();
- },
- nullptr, true);
- }
-}
+
void handle_uptime() {
jsonWriteStr(configSetupJson, "uptime", timeNow->getUptime());
}
-void handle_statistics() {
- if (isNetworkActive()) {
- String urls = "http://backup.privet.lv/visitors/?";
- //-----------------------------------------------------------------
- urls += WiFi.macAddress().c_str();
- urls += "&";
- //-----------------------------------------------------------------
-#ifdef ESP8266
- urls += "iot-manager_esp8266";
-#endif
-#ifdef ESP32
- urls += "iot-manager_esp32";
-#endif
- urls += "&";
-#ifdef ESP8266
- urls += ESP.getResetReason();
-#endif
-#ifdef ESP32
- urls += "Power on";
-#endif
- urls += "&";
- urls += String(FIRMWARE_VERSION);
- String stat = getURL(urls);
- }
-}
\ No newline at end of file
+//void handle_statistics() {
+// if (isNetworkActive()) {
+// String urls = "http://backup.privet.lv/visitors/?";
+// //-----------------------------------------------------------------
+// urls += WiFi.macAddress().c_str();
+// urls += "&";
+// //-----------------------------------------------------------------
+//#ifdef ESP8266
+// urls += "iot-manager_esp8266";
+//#endif
+//#ifdef ESP32
+// urls += "iot-manager_esp32";
+//#endif
+// urls += "&";
+//#ifdef ESP8266
+// urls += ESP.getResetReason();
+//#endif
+//#ifdef ESP32
+// urls += "Power on";
+//#endif
+// urls += "&";
+// urls += String(FIRMWARE_VERSION);
+// String stat = getURL(urls);
+// }
+//}
\ No newline at end of file
diff --git a/src/ItemsCmd.cpp b/src/ItemsCmd.cpp
new file mode 100644
index 00000000..5521806c
--- /dev/null
+++ b/src/ItemsCmd.cpp
@@ -0,0 +1,326 @@
+#include "ItemsCmd.h"
+
+#include "BufferExecute.h"
+#include "Class/NotAsinc.h"
+#include "Cmd.h"
+#include "Global.h"
+#include "Module/Terminal.h"
+#include "Servo/Servos.h"
+
+Terminal *term = nullptr;
+
+boolean but[NUM_BUTTONS];
+Bounce *buttons = new Bounce[NUM_BUTTONS];
+
+#ifdef ESP8266
+SoftwareSerial *mySerial = nullptr;
+#else
+HardwareSerial *mySerial = nullptr;
+#endif
+
+void getData();
+
+void cmd_init() {
+ sCmd.addCommand("button-out", buttonOut);
+ sCmd.addCommand("pwm-out", pwmOut);
+ sCmd.addCommand("button-in", buttonIn);
+
+ sCmd.addCommand("input-digit", inputDigit);
+ sCmd.addCommand("input-time", inputTime);
+ sCmd.addCommand("output-text", textOut);
+
+ sCmd.addCommand("analog-adc", analogAdc);
+ sCmd.addCommand("ultrasonic-cm", ultrasonicCm);
+ sCmd.addCommand("dallas-temp", dallasTemp);
+
+ sCmd.addCommand("dht-temp", dhtTemp);
+ sCmd.addCommand("dht-hum", dhtHum);
+
+ sCmd.addCommand("bme280-temp", bme280Temp);
+ sCmd.addCommand("bme280-hum", bme280Hum);
+ sCmd.addCommand("bme280-press", bme280Press);
+
+ sCmd.addCommand("bmp280-temp", bmp280Temp);
+ sCmd.addCommand("bmp280-press", bmp280Press);
+
+ //sCmd.addCommand("modbus", modbus);
+
+ handle_time_init();
+}
+
+// sCmd.addCommand("timerStart", timerStart_);
+// sCmd.addCommand("timerStop", timerStop_);
+
+//#ifdef DHT_ENABLED
+// sCmd.addCommand("dhtT", dhtT);
+// sCmd.addCommand("dhtH", dhtH);
+// sCmd.addCommand("dhtPerception", dhtP);
+// sCmd.addCommand("dhtComfort", dhtC);
+// sCmd.addCommand("dhtDewpoint", dhtD);
+//#endif
+
+//#ifdef BMP_ENABLED
+// sCmd.addCommand("bmp280T", bmp280T);
+// sCmd.addCommand("bmp280P", bmp280P);
+//#endif
+//
+//#ifdef BME_ENABLED
+// sCmd.addCommand("bme280T", bme280T);
+// sCmd.addCommand("bme280P", bme280P);
+// sCmd.addCommand("bme280H", bme280H);
+// sCmd.addCommand("bme280A", bme280A);
+//#endif
+//
+//#ifdef STEPPER_ENABLED
+// sCmd.addCommand("stepper", stepper);
+// sCmd.addCommand("stepperSet", stepperSet);
+//#endif
+//
+//#ifdef SERVO_ENABLED
+// sCmd.addCommand("servo", servo_);
+// sCmd.addCommand("servoSet", servoSet);
+//#endif
+//
+//#ifdef SERIAL_ENABLED
+// sCmd.addCommand("serialBegin", serialBegin);
+// sCmd.addCommand("serialWrite", serialWrite);
+// sCmd.addCommand("getData", getData);
+//#endif
+//
+//#ifdef LOGGING_ENABLED
+// sCmd.addCommand("logging", logging);
+//#endif
+//
+// sCmd.addCommand("mqtt", mqttOrderSend);
+// sCmd.addCommand("http", httpOrderSend);
+//
+//#ifdef PUSH_ENABLED
+// sCmd.addCommand("push", pushControl);
+//#endif
+//
+// sCmd.addCommand("firmwareUpdate", firmwareUpdate);
+// sCmd.addCommand("firmwareVersion", firmwareVersion);
+
+//void text() {
+// String number = sCmd.next();
+// String widget_name = sCmd.next();
+// String page_name = sCmd.next();
+// String page_number = sCmd.next();
+//
+// createWidget(widget_name, page_name, page_number, "anydata", "text" + number);
+//}
+//
+//void textSet() {
+// String number = sCmd.next();
+// String text = sCmd.next();
+// text.replace("_", " ");
+//
+// if (text.indexOf("-time") >= 0) {
+// text.replace("-time", "");
+// text.replace("#", " ");
+// text = text + " " + timeNow->getDateTimeDotFormated();
+// }
+//
+// jsonWriteStr(configLiveJson, "text" + number, text);
+// publishStatus("text" + number, text);
+//}
+//=====================================================================================================================================
+////=========================================Модуль шагового мотора======================================================================
+//#ifdef STEPPER_ENABLED
+////stepper 1 12 13
+//void stepper() {
+// String stepper_number = sCmd.next();
+// String pin_step = sCmd.next();
+// String pin_dir = sCmd.next();
+//
+// jsonWriteStr(configOptionJson, "stepper" + stepper_number, pin_step + " " + pin_dir);
+// pinMode(pin_step.toInt(), OUTPUT);
+// pinMode(pin_dir.toInt(), OUTPUT);
+//}
+//
+////stepperSet 1 100 5
+//void stepperSet() {
+// String stepper_number = sCmd.next();
+// String steps = sCmd.next();
+// jsonWriteStr(configOptionJson, "steps" + stepper_number, steps);
+// String stepper_speed = sCmd.next();
+// String pin_step = selectToMarker(jsonReadStr(configOptionJson, "stepper" + stepper_number), " ");
+// String pin_dir = deleteBeforeDelimiter(jsonReadStr(configOptionJson, "stepper" + stepper_number), " ");
+// Serial.println(pin_step);
+// Serial.println(pin_dir);
+// if (steps.toInt() > 0) digitalWrite(pin_dir.toInt(), HIGH);
+// if (steps.toInt() < 0) digitalWrite(pin_dir.toInt(), LOW);
+// if (stepper_number == "1") {
+// ts.add(
+// STEPPER1, stepper_speed.toInt(), [&](void *) {
+// int steps_int = abs(jsonReadInt(configOptionJson, "steps1") * 2);
+// static int count;
+// count++;
+// String pin_step = selectToMarker(jsonReadStr(configOptionJson, "stepper1"), " ");
+// digitalWrite(pin_step.toInt(), !digitalRead(pin_step.toInt()));
+// yield();
+// if (count > steps_int) {
+// digitalWrite(pin_step.toInt(), LOW);
+// ts.remove(STEPPER1);
+// count = 0;
+// }
+// },
+// nullptr, true);
+// }
+// if (stepper_number == "2") {
+// ts.add(
+// STEPPER2, stepper_speed.toInt(), [&](void *) {
+// int steps_int = abs(jsonReadInt(configOptionJson, "steps2") * 2);
+// static int count;
+// count++;
+// String pin_step = selectToMarker(jsonReadStr(configOptionJson, "stepper2"), " ");
+// digitalWrite(pin_step.toInt(), !digitalRead(pin_step.toInt()));
+// yield();
+// if (count > steps_int) {
+// digitalWrite(pin_step.toInt(), LOW);
+// ts.remove(STEPPER2);
+// count = 0;
+// }
+// },
+// nullptr, true);
+// }
+//}
+//#endif
+////====================================================================================================================================================
+////=================================================================Сервоприводы=======================================================================
+//#ifdef SERVO_ENABLED
+////servo 1 13 50 Мой#сервопривод Сервоприводы 0 100 0 180 2
+//void servo_() {
+// String number = sCmd.next();
+// uint8_t pin = String(sCmd.next()).toInt();
+// int value = String(sCmd.next()).toInt();
+//
+// String widget = sCmd.next();
+// String page = sCmd.next();
+//
+// int min_value = String(sCmd.next()).toInt();
+// int max_value = String(sCmd.next()).toInt();
+// int min_deg = String(sCmd.next()).toInt();
+// int max_deg = String(sCmd.next()).toInt();
+//
+// String pageNumber = sCmd.next();
+//
+// jsonWriteStr(configOptionJson, "servo_pin" + number, String(pin, DEC));
+//
+// value = map(value, min_value, max_value, min_deg, max_deg);
+//
+// Servo *servo = myServo.create(number.toInt(), pin);
+// servo->write(value);
+//#ifdef ESP32
+// myServo1.attach(servo_pin.toInt(), 500, 2400);
+// myServo1.write(start_state_int);
+//#endif
+//
+// jsonWriteInt(configOptionJson, "s_min_val" + number, min_value);
+// jsonWriteInt(configOptionJson, "s_max_val" + number, max_value);
+// jsonWriteInt(configOptionJson, "s_min_deg" + number, min_deg);
+// jsonWriteInt(configOptionJson, "s_max_deg" + number, max_deg);
+//
+// jsonWriteInt(configLiveJson, "servo" + number, value);
+//
+// createWidgetParam(widget, page, pageNumber, "range", "servo" + number, "min", String(min_value), "max", String(max_value), "k", "1");
+//}
+//
+//void servoSet() {
+// String number = sCmd.next();
+// int value = String(sCmd.next()).toInt();
+//
+// value = map(value,
+// jsonReadInt(configOptionJson, "s_min_val" + number),
+// jsonReadInt(configOptionJson, "s_max_val" + number),
+// jsonReadInt(configOptionJson, "s_min_deg" + number),
+// jsonReadInt(configOptionJson, "s_max_deg" + number));
+//
+// Servo *servo = myServo.get(number.toInt());
+// if (servo) {
+// servo->write(value);
+// }
+//
+// eventGen("servo", number);
+// jsonWriteInt(configLiveJson, "servo" + number, value);
+// publishStatus("servo" + number, String(value, DEC));
+//}
+//#endif
+////====================================================================================================================================================
+////=============================================================Модуль сериал порта=======================================================================
+//
+//#ifdef SERIAL_ENABLED
+//void serialBegin() {
+// String s_speed = sCmd.next();
+// String rxPin = sCmd.next();
+// String txPin = sCmd.next();
+//
+// if (mySerial) {
+// delete mySerial;
+// }
+//
+//#ifdef ESP8266
+// mySerial = new SoftwareSerial(rxPin.toInt(), txPin.toInt());
+// mySerial->begin(s_speed.toInt());
+//#else
+// mySerial = new HardwareSerial(2);
+// mySerial->begin(rxPin.toInt(), txPin.toInt());
+//#endif
+//
+// term = new Terminal(mySerial);
+// term->setEOL(LF);
+// term->enableColors(false);
+// term->enableControlCodes(false);
+// term->enableEcho(false);
+// term->setOnReadLine([](const char *str) {
+// String line = String(str);
+// loopCmdAdd(line);
+// });
+//}
+//
+//void getData() {
+// String param = sCmd.next();
+// String res = param.length() ? jsonReadStr(configLiveJson, param) : configLiveJson;
+// if (term) {
+// term->println(res.c_str());
+// }
+//}
+//
+//void serialWrite() {
+// String payload = sCmd.next();
+// if (term) {
+// term->println(payload.c_str());
+// }
+//}
+//#endif
+////====================================================================================================================================================
+////=================================================Глобальные команды удаленного управления===========================================================
+//
+//void mqttOrderSend() {
+// String id = sCmd.next();
+// String order = sCmd.next();
+//
+// String all_line = jsonReadStr(configSetupJson, "mqttPrefix") + "/" + id + "/order";
+// mqtt.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);
+//}
+//
+//void firmwareUpdate() {
+// myNotAsincActions->make(do_UPGRADE);
+//}
+//
+//void firmwareVersion() {
+// String widget = sCmd.next();
+// String page = sCmd.next();
+// String pageNumber = sCmd.next();
+//
+// jsonWriteStr(configLiveJson, "firmver", FIRMWARE_VERSION);
+// createWidget(widget, page, pageNumber, "anydata", "firmver");
+//}
diff --git a/src/ItemsList.cpp b/src/ItemsList.cpp
new file mode 100644
index 00000000..4ad89cd6
--- /dev/null
+++ b/src/ItemsList.cpp
@@ -0,0 +1,119 @@
+#include "ItemsList.h"
+
+#include "Class\NotAsinc.h"
+#include "Init.h"
+#include "Utils\StringUtils.h"
+
+static const char* firstLine PROGMEM = "Удалить;Тип элемента;Id;Виджет;Имя вкладки;Имя виджета;Позиция виджета";
+
+void itemsListInit() {
+ myNotAsincActions->add(
+ do_deviceInit, [&](void*) {
+ Device_init();
+ },
+ nullptr);
+
+ myNotAsincActions->add(
+ do_delChoosingItems, [&](void*) {
+ delChoosingItems();
+ },
+ nullptr);
+}
+
+void addItem(String name) {
+ String item = readFile("items/" + name + ".txt", 1024);
+
+ name = deleteToMarkerLast(name, ".");
+
+ item.replace("id", name + "-" + String(getNewElementNumber("id.txt")));
+ item.replace("order", String(getNewElementNumber("order.txt")));
+
+ if (item.indexOf("pin") != -1) { //all cases (random pins from available)
+ item.replace("pin", "pin[" + String(getFreePinAll()) + "]");
+ } else
+
+ if (item.indexOf("gol") != -1) { //analog
+ item.replace("gol", "pin[" + String(getFreePinAnalog()) + "]");
+ } else
+
+ if (item.indexOf("cin") != -1) { //ultrasonic
+ item.replace("cin", "pin[" + String(getFreePinAll()) + "," + String(getFreePinAll()) + "]");
+ } else
+
+ if (item.indexOf("sal") != -1) { //dallas
+ item.replace("sal", "pin[2]");
+ } else
+
+ if (item.indexOf("thd") != -1) { //dht11/22
+ item.replace("thd", "pin[2]");
+ }
+
+ item.replace("\r\n", "");
+ item.replace("\r", "");
+ item.replace("\n", "");
+ addFile(DEVICE_CONFIG_FILE, "\n" + item);
+}
+
+void delAllItems() {
+ removeFile(DEVICE_CONFIG_FILE);
+ addFile(DEVICE_CONFIG_FILE, String(firstLine));
+ removeFile("id.txt");
+ removeFile("order.txt");
+ removeFile("pins.txt");
+}
+
+uint8_t getNewElementNumber(String file) {
+ uint8_t number = readFile(file, 100).toInt();
+ number++;
+ removeFile(file);
+ addFile(file, String(number));
+ return number;
+}
+
+uint8_t getFreePinAll() {
+#ifdef ESP8266
+ uint8_t pins[] = {0, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5};
+#endif
+#ifdef ESP32
+ uint8_t pins[] = {0, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5};
+#endif
+ uint8_t array_sz = sizeof(pins) / sizeof(pins[0]);
+ uint8_t i = getNewElementNumber("pins.txt");
+ if (i < array_sz) {
+ return pins[i];
+ } else {
+ return 0;
+ }
+}
+
+uint8_t getFreePinAnalog() {
+#ifdef ESP8266
+ return 0;
+#endif
+}
+
+void delChoosingItems() {
+ File configFile = LittleFS.open("/" + String(DEVICE_CONFIG_FILE), "r");
+ if (!configFile) {
+ return;
+ }
+ configFile.seek(0, SeekSet);
+ String finalConf;
+ bool firstLine = true;
+ while (configFile.position() != configFile.size()) {
+ String item = configFile.readStringUntil('\n');
+ if (firstLine) {
+ finalConf += item;
+ } else {
+ int checkbox = selectToMarker(item, ";").toInt();
+ if (checkbox == 0) {
+ finalConf += "\n" + item;
+ }
+ }
+ firstLine = false;
+ }
+ removeFile(String(DEVICE_CONFIG_FILE));
+ addFile(String(DEVICE_CONFIG_FILE), finalConf);
+ Serial.println(finalConf);
+ configFile.close();
+}
\ No newline at end of file
diff --git a/src/Logging.cpp b/src/Logging.cpp
index 0abe9fb5..44b323a4 100644
--- a/src/Logging.cpp
+++ b/src/Logging.cpp
@@ -1,11 +1,8 @@
#include "Global.h"
-
-//
#include
void sendLogData(String file, String topic);
-static const char* MODULE = "Log";
#ifdef LOGGING_ENABLED
//===============================================Логирование============================================================
@@ -30,7 +27,7 @@ void logging() {
LOG1, period_min.toInt() * 1000 * 60, [&](void*) {
String tmp_buf_1 = selectFromMarkerToMarker(logging_value_names_list, ",", 0);
deleteOldDate("log." + tmp_buf_1 + ".txt", jsonReadInt(configOptionJson, tmp_buf_1 + "_c"), jsonReadStr(configLiveJson, tmp_buf_1));
- pm.info("logging for " + tmp_buf_1 + " done");
+ SerialPrint("I","module","logging for " + tmp_buf_1 + " done");
},
nullptr, false);
}
@@ -39,7 +36,7 @@ void logging() {
LOG2, period_min.toInt() * 1000 * 60, [&](void*) {
String tmp_buf_2 = selectFromMarkerToMarker(logging_value_names_list, ",", 1);
deleteOldDate("log." + tmp_buf_2 + ".txt", jsonReadInt(configOptionJson, tmp_buf_2 + "_c"), jsonReadStr(configLiveJson, tmp_buf_2));
- pm.info("logging for " + tmp_buf_2 + " done");
+ SerialPrint("I","module","logging for " + tmp_buf_2 + " done");
},
nullptr, false);
}
@@ -48,7 +45,7 @@ void logging() {
LOG3, period_min.toInt() * 1000 * 60, [&](void*) {
String tmp_buf_3 = selectFromMarkerToMarker(logging_value_names_list, ",", 2);
deleteOldDate("log." + tmp_buf_3 + ".txt", jsonReadInt(configOptionJson, tmp_buf_3 + "_c"), jsonReadStr(configLiveJson, tmp_buf_3));
- pm.info("logging for " + tmp_buf_3 + " done");
+ SerialPrint("I","module","logging for " + tmp_buf_3 + " done");
},
nullptr, false);
}
@@ -57,7 +54,7 @@ void logging() {
LOG4, period_min.toInt() * 1000 * 60, [&](void*) {
String tmp_buf_4 = selectFromMarkerToMarker(logging_value_names_list, ",", 3);
deleteOldDate("log." + tmp_buf_4 + ".txt", jsonReadInt(configOptionJson, tmp_buf_4 + "_c"), jsonReadStr(configLiveJson, tmp_buf_4));
- pm.info("logging for " + tmp_buf_4 + " done");
+ SerialPrint("I","module","logging for " + tmp_buf_4 + " done");
},
nullptr, false);
}
@@ -66,7 +63,7 @@ void logging() {
LOG5, period_min.toInt() * 1000 * 60, [&](void*) {
String tmp_buf_5 = selectFromMarkerToMarker(logging_value_names_list, ",", 4);
deleteOldDate("log." + tmp_buf_5 + ".txt", jsonReadInt(configOptionJson, tmp_buf_5 + "_c"), jsonReadStr(configLiveJson, tmp_buf_5));
- pm.info("logging for " + tmp_buf_5 + " done");
+ SerialPrint("I","module","logging for " + tmp_buf_5 + " done");
},
nullptr, false);
}
@@ -79,7 +76,7 @@ void deleteOldDate(const String filename, size_t max_lines_cnt, String payload)
String log_date = readFile(filename, 5120);
size_t lines_cnt = itemsCount(log_date, "\r\n");
- pm.info("log " + filename + " (" + String(lines_cnt, DEC) + ")");
+ SerialPrint("I","module","log " + filename + " (" + String(lines_cnt, DEC) + ")");
if ((lines_cnt > max_lines_cnt + 1) || !lines_cnt) {
removeFile(filename);
@@ -94,7 +91,7 @@ void deleteOldDate(const String filename, size_t max_lines_cnt, String payload)
}
} else {
if (timeNow->hasTimeSynced()) {
- addFile(filename, timeNow->getTimeUnix() + " " + payload);
+ addFileLn(filename, timeNow->getTimeUnix() + " " + payload);
}
}
}
@@ -136,9 +133,9 @@ void sendLogData(String file, String topic) {
value = "";
log_date = "";
json_array = "{\"status\":[" + json_array + "]}";
- pm.info(json_array);
+ SerialPrint("I","module",json_array);
- MqttClient::publishChart(topic, json_array);
+ publishChart(topic, json_array);
}
}
diff --git a/src/MqttClient.cpp b/src/MqttClient.cpp
index 9841fefe..5d726c00 100644
--- a/src/MqttClient.cpp
+++ b/src/MqttClient.cpp
@@ -1,70 +1,63 @@
#include "MqttClient.h"
-#include "Global.h"
-#include "Init.h"
+
#include
-static const char* MODULE = "Mqtt";
+#include "Class/NotAsinc.h"
+#include "Global.h"
+#include "Init.h"
-namespace MqttClient {
-
-// Errors
-int wifi_lost_error = 0;
-int mqtt_lost_error = 0;
-bool connected = false;
-
-// Session params
String mqttPrefix;
String mqttRootDevice;
-void init() {
- mqtt.setCallback(handleSubscribedUpdates);
+void mqttInit() {
+ myNotAsincActions->add(
+ do_MQTTPARAMSCHANGED, [&](void*) {
+ mqttReconnect();
+ },
+ nullptr);
+
+ mqtt.setCallback(mqttCallback);
ts.add(
WIFI_MQTT_CONNECTION_CHECK, MQTT_RECONNECT_INTERVAL,
[&](void*) {
- if (isNetworkActive()) {
+ if (WiFi.status() == WL_CONNECTED) {
+ SerialPrint("I", "WIFI", "OK");
if (mqtt.connected()) {
- if (!connected) {
- pm.info("OK");
- setLedStatus(LED_OFF);
- connected = true;
- }
+ SerialPrint("I", "MQTT", "OK");
+ setLedStatus(LED_OFF);
} else {
- connect();
- if (!just_load) mqtt_lost_error++;
+ SerialPrint("E", "MQTT", "lost connection");
+ mqttConnect();
}
} else {
- if (connected) {
- pm.error("connection lost");
- connected = false;
- }
+ SerialPrint("E", "WIFI", "Lost WiFi connection");
ts.remove(WIFI_MQTT_CONNECTION_CHECK);
- wifi_lost_error++;
startAPMode();
}
},
nullptr, true);
}
-void disconnect() {
- pm.info("disconnect");
+void mqttDisconnect() {
+ SerialPrint("I", "MQTT", "disconnect");
mqtt.disconnect();
}
-void reconnect() {
- disconnect();
- connect();
+void mqttReconnect() {
+ mqttDisconnect();
+ mqttConnect();
}
-void loop() {
+void mqttLoop() {
if (!isNetworkActive() || !mqtt.connected()) {
return;
}
mqtt.loop();
}
-void subscribe() {
- pm.info("subscribe");
+void mqttSubscribe() {
+ SerialPrint("I", "MQTT", "subscribe");
mqtt.subscribe(mqttPrefix.c_str());
mqtt.subscribe((mqttRootDevice + "/+/control").c_str());
mqtt.subscribe((mqttRootDevice + "/order").c_str());
@@ -73,58 +66,50 @@ void subscribe() {
mqtt.subscribe((mqttRootDevice + "/devs").c_str());
}
-boolean connect() {
- pm.info("connect");
-
+boolean mqttConnect() {
+ SerialPrint("I", "MQTT", "start connection");
String addr = jsonReadStr(configSetupJson, "mqttServer");
if (!addr) {
- pm.error("no broker address");
+ SerialPrint("E", "MQTT", "no broker address");
return false;
}
-
int port = jsonReadInt(configSetupJson, "mqttPort");
String user = jsonReadStr(configSetupJson, "mqttUser");
String pass = jsonReadStr(configSetupJson, "mqttPass");
-
- //Session params
mqttPrefix = jsonReadStr(configSetupJson, "mqttPrefix");
mqttRootDevice = mqttPrefix + "/" + chipId;
-
- pm.info("broker " + addr + ":" + String(port, DEC));
- pm.info("topic " + mqttRootDevice);
-
+ SerialPrint("I", "MQTT", "broker " + addr + ":" + String(port, DEC));
+ SerialPrint("I", "MQTT", "topic " + mqttRootDevice);
setLedStatus(LED_FAST);
mqtt.setServer(addr.c_str(), port);
bool res = false;
if (!mqtt.connected()) {
if (mqtt.connect(chipId.c_str(), user.c_str(), pass.c_str())) {
- pm.info("connected");
+ SerialPrint("I", "MQTT", "connected");
setLedStatus(LED_OFF);
- subscribe();
+ mqttSubscribe();
res = true;
} else {
- pm.error("could't connect, retry in " + String(MQTT_RECONNECT_INTERVAL / 1000) + "s");
+ SerialPrint("E", "MQTT", "could't connect, retry in " + String(MQTT_RECONNECT_INTERVAL / 1000) + "s");
setLedStatus(LED_FAST);
}
}
return res;
}
-void handleSubscribedUpdates(char* topic, uint8_t* payload, size_t length) {
+void mqttCallback(char* topic, uint8_t* payload, size_t length) {
String topicStr = String(topic);
- pm.info(topicStr);
-
+ SerialPrint("I", "MQTT", topicStr);
String payloadStr;
-
payloadStr.reserve(length + 1);
for (size_t i = 0; i < length; i++) {
payloadStr += (char)payload[i];
}
- pm.info(payloadStr);
+ SerialPrint("I", "MQTT", payloadStr);
if (payloadStr.startsWith("HELLO")) {
- pm.info("Full update");
+ SerialPrint("I", "MQTT", "Full update");
publishWidgets();
publishState();
#ifdef LOGGING_ENABLED
@@ -132,38 +117,32 @@ void handleSubscribedUpdates(char* topic, uint8_t* payload, size_t length) {
#endif
} else if (topicStr.indexOf("control")) {
-
//iotTeam/12882830-1458415/light 1
String key = selectFromMarkerToMarker(topicStr, "/", 3);
- order_loop += key;
- order_loop += " ";
- order_loop += payloadStr;
- order_loop += ",";
+ orderBuf += key;
+ orderBuf += " ";
+ orderBuf += payloadStr;
+ orderBuf += ",";
} else if (topicStr.indexOf("order")) {
-
payloadStr.replace("_", " ");
- order_loop += payloadStr;
- order_loop += ",";
+ orderBuf += payloadStr;
+ orderBuf += ",";
} else if (topicStr.indexOf("update")) {
-
if (payloadStr == "1") {
- updateFlag = true;
+ myNotAsincActions->make(do_UPGRADE);
}
} else if (topicStr.indexOf("devc")) {
-
writeFile(String(DEVICE_CONFIG_FILE), payloadStr);
Device_init();
} else if (topicStr.indexOf("devs")) {
-
writeFile(String(DEVICE_SCENARIO_FILE), payloadStr);
loadScenario();
-
}
}
@@ -178,7 +157,7 @@ boolean publish(const String& topic, const String& data) {
boolean publishData(const String& topic, const String& data) {
String path = mqttRootDevice + "/" + topic;
if (!publish(path, data)) {
- pm.error("on publish data");
+ SerialPrint("[E]", "MQTT", "on publish data");
return false;
}
return true;
@@ -187,7 +166,7 @@ boolean publishData(const String& topic, const String& data) {
boolean publishChart(const String& topic, const String& data) {
String path = mqttRootDevice + "/" + topic + "/status";
if (!publish(path, data)) {
- pm.error("on publish chart");
+ SerialPrint("[E]", "MQTT", "on publish chart");
return false;
}
return true;
@@ -229,7 +208,7 @@ void publishWidgets() {
Serial.println("[V] " + line);
psn_1 = psn_2 + 1;
} while (psn_2 + 2 < all_widgets.length());
- getMemoryLoad("[I] after send all widgets");
+ getMemoryLoad("I after send all widgets");
}
}
#endif
@@ -238,12 +217,12 @@ void publishWidgets() {
void publishWidgets() {
auto file = seekFile("layout.txt");
if (!file) {
- pm.error("no file layout.txt");
+ SerialPrint("[E]", "MQTT", "no file layout.txt");
return;
}
while (file.available()) {
String payload = file.readStringUntil('\n');
- pm.info("widgets: " + payload);
+ SerialPrint("I", "MQTT", "widgets: " + payload);
publishData("config", payload);
}
file.close();
@@ -313,5 +292,3 @@ const String getStateStr() {
break;
}
}
-
-} // namespace MqttClient
\ No newline at end of file
diff --git a/src/PushingBox.cpp b/src/PushingBox.cpp
index c5c37a79..5c2f91e4 100644
--- a/src/PushingBox.cpp
+++ b/src/PushingBox.cpp
@@ -23,15 +23,15 @@ void pushControl() {
const char* logServer = "api.pushingbox.com";
String deviceId = jsonReadStr(configSetupJson, "pushingbox_id");
- Serial.println("- starting client");
+ //Serial.println("- starting client");
WiFiClient client_push;
- Serial.println("- connecting to pushing server: " + String(logServer));
+ //Serial.println("- connecting to pushing server: " + String(logServer));
if (!client_push.connect(logServer, 80)) {
- Serial.println("- not connected");
+ //Serial.println("- not connected");
} else {
- Serial.println("- succesfully connected");
+ //Serial.println("- succesfully connected");
String postStr = "devid=";
postStr += String(deviceId);
@@ -44,17 +44,17 @@ void pushControl() {
postStr += "\r\n\r\n";
- Serial.println("- sending data...");
+ //Serial.println("- sending data...");
- client_push.print("POST /pushingbox HTTP/1.1\n");
- client_push.print("Host: api.pushingbox.com\n");
- client_push.print("Connection: close\n");
- client_push.print("Content-Type: application/x-www-form-urlencoded\n");
- client_push.print("Content-Length: ");
+ client_push.print(F("POST /pushingbox HTTP/1.1\n"));
+ client_push.print(F("Host: api.pushingbox.com\n"));
+ client_push.print(F("Connection: close\n"));
+ client_push.print(F("Content-Type: application/x-www-form-urlencoded\n"));
+ client_push.print(F("Content-Length: "));
client_push.print(postStr.length());
client_push.print("\n\n");
client_push.print(postStr);
}
client_push.stop();
- Serial.println("- stopping the client");
+ //Serial.println("- stopping the client");
}
diff --git a/src/RemoteOrdersUdp.cpp b/src/RemoteOrdersUdp.cpp
new file mode 100644
index 00000000..e09693b0
--- /dev/null
+++ b/src/RemoteOrdersUdp.cpp
@@ -0,0 +1,71 @@
+//#include "RemoteOrdersUdp.h"
+//
+//#include
+//
+//#include "Global.h"
+//
+//AsyncUDP asyncUdp;
+//
+//void asyncUdpInit() {
+// //if (asyncUdp.listen(1234)) {
+// if (asyncUdp.listenMulticast(IPAddress(239, 255, 255, 255), 1234)) {
+// asyncUdp.onPacket([](AsyncUDPPacket packet) {
+//
+// //Serial.print("UDP Packet Type: ");
+// //Serial.print(packet.isBroadcast() ? "Broadcast" : packet.isMulticast() ? "Multicast" : "Unicast");
+// //
+// //Serial.print(", From: ");
+// //Serial.print(packet.remoteIP());
+// //Serial.print(":");
+// //Serial.print(packet.remotePort());
+// //
+// //Serial.print(", To: ");
+// //Serial.print(packet.localIP());
+// //Serial.print(":");
+// //Serial.print(packet.localPort());
+// //
+// //Serial.print(", Length: ");
+// //Serial.print(packet.length());
+// //
+// //Serial.print(", Data: ");
+// //Serial.write(packet.data(), packet.length());
+//
+// String data = uint8tToString(packet.data(), packet.length());
+// Serial.print("[i] [udp] Packet received: '");
+// Serial.print(data);
+// if (udpPacketValidation(data)) {
+// udpPacketParse(data);
+// //Serial.println("', Packet valid");
+// } else {
+// //Serial.println("', Packet invalid");
+// }
+//
+// //reply to the client
+//
+// packet.printf("Got %u bytes of data", packet.length());
+// });
+// }
+//}
+//
+//String uint8tToString(uint8_t* data, size_t len) {
+// String ret;
+// while (len--) {
+// ret += (char)*data++;
+// }
+// return ret;
+//}
+//
+//bool udpPacketValidation(String& data) {
+// if (data.indexOf("iotm;") != -1 && data.indexOf(getChipId()) != -1) {
+// return true;
+// } else {
+// return false;
+// }
+//}
+//
+////iotm;chipid;button-out-1_1
+//void udpPacketParse(String& data) {
+// data = selectFromMarkerToMarker(data, ";", 2);
+// data.replace("_", " ");
+// orderBuf += data + ",";
+//}
\ No newline at end of file
diff --git a/src/SSDP.cpp b/src/SSDP.cpp
new file mode 100644
index 00000000..108bef62
--- /dev/null
+++ b/src/SSDP.cpp
@@ -0,0 +1,58 @@
+
+#include
+#include "Global.h"
+#ifdef SSDP_EN
+#ifdef ESP8266
+ #include
+#endif
+#ifdef ESP32
+ #include
+#endif
+//39164
+//457684
+void SsdpInit() {
+ server.on("/description.xml", HTTP_GET, [](AsyncWebServerRequest* request) {
+ String ssdpSend = F("");
+ String ssdpHeder = xmlNode(F("major"), "1");
+ ssdpHeder += xmlNode(F("minor"), "0");
+ ssdpHeder = xmlNode(F("specVersion"), ssdpHeder);
+ ssdpHeder += xmlNode(F("URLBase"), "http://" + WiFi.localIP().toString());
+ String ssdpDescription = xmlNode(F("deviceType"), F("upnp:rootdevice"));
+ ssdpDescription += xmlNode(F("friendlyName"), jsonReadStr(configSetupJson, F("name")));
+ ssdpDescription += xmlNode(F("presentationURL"), "/");
+ ssdpDescription += xmlNode(F("serialNumber"), getChipId());
+#ifdef ESP8266
+ ssdpDescription += xmlNode(F("modelName"), F("ESP8266"));
+#endif
+#ifdef ESP32
+ ssdpDescription += xmlNode(F("modelName"), F("ESP32"));
+#endif
+ ssdpDescription += xmlNode(F("modelNumber"), getChipId());
+ ssdpDescription += xmlNode(F("modelURL"), F("https://github.com/IoTManagerProject/IoTManager/wiki"));
+ ssdpDescription += xmlNode(F("manufacturer"), F("Borisenko Dmitry"));
+ ssdpDescription += xmlNode(F("manufacturerURL"), F("https://github.com/IoTManagerProject/IoTManager"));
+ ssdpDescription += xmlNode(F("UDN"), "uuid:38323636-4558-4dda-9188-cda0e6" + decToHex(ESP.getChipId(), 6));
+ ssdpDescription = xmlNode("device", ssdpDescription);
+ ssdpHeder += ssdpDescription;
+ ssdpSend += ssdpHeder;
+ ssdpSend += "";
+ Serial.println("->!!!SSDP Get request received");
+ request->send(200, "text/xml", ssdpSend);
+ });
+ //Если версия 2.0.0 закаментируйте следующую строчку
+ SSDP.setDeviceType(F("upnp:rootdevice"));
+ SSDP.setSchemaURL(F("description.xml"));
+ SSDP.begin();
+}
+
+String xmlNode(String tags, String data) {
+ String temp = "<" + tags + ">" + data + "" + tags + ">";
+ return temp;
+}
+
+String decToHex(uint32_t decValue, byte desiredStringLength) {
+ String hexString = String(decValue, HEX);
+ while (hexString.length() < desiredStringLength) hexString = "0" + hexString;
+ return hexString;
+}
+#endif
\ No newline at end of file
diff --git a/src/Scenario.cpp b/src/Scenario.cpp
index c7304422..2399d178 100644
--- a/src/Scenario.cpp
+++ b/src/Scenario.cpp
@@ -1,88 +1,81 @@
-#include "Global.h"
#include "Cmd.h"
+#include "Global.h"
+#include "Class/ScenarioClass.h"
+
-static const char* MODULE = "Scen";
boolean isScenarioEnabled() {
- return jsonReadBool(configSetupJson, "scen") && jsonReadStr(configOptionJson, "scenario_status") != "";
+ return jsonReadBool(configSetupJson, "scen") && eventBuf != "";
}
void loopScenario() {
if (!isScenarioEnabled()) {
return;
}
- String str = scenario;
- str += "\n";
- str.replace("\r\n", "\n");
- str.replace("\r", "\n");
+ String scenarioTmp = scenario;
+ scenarioTmp += "\n";
+ scenarioTmp.replace("\r\n", "\n");
+ scenarioTmp.replace("\r", "\n");
- size_t i = 0;
- while (str.length()) {
- String block = selectToMarker(str, "end");
- if (!block.length()) {
+ while (scenarioTmp.length()) {
+ String scenBlok = selectToMarker(scenarioTmp, "end"); //выделяем первый сценарий
+ if (!scenBlok.length()) {
return;
}
+
+ size_t i = 0;
i++;
if (scenario_line_status[i] == 1) {
- //выделяем первую строку самого сценария button1 = 1 (условие)
- String condition = selectToMarker(block, "\n");
- String param_name = selectFromMarkerToMarker(condition, " ", 0);
- String order = jsonReadStr(configOptionJson, "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("digit") != -1) {
- // value = add_set(value);
- value = jsonReadStr(configLiveJson, value);
- }
- if (value.indexOf("time") != -1) {
- // value = add_set(value);
- value = jsonReadStr(configLiveJson, value);
- }
- // если условие выполнилось, тогда начинаем выполнять комнады
+ String condition = selectToMarker(scenBlok, "\n"); //выделяем условие
+
+ String conditionParam = selectFromMarkerToMarker(condition, " ", 0); //выделяем параметр условия
+ String order = eventBuf;
+ String eventParam = selectToMarker(order, ","); //выделяем параметр события
+
+ if (conditionParam == eventParam) { //если поступившее событие равно событию заданному buttonSet1 в файле начинаем его обработку
+
+ String conditionSign = selectFromMarkerToMarker(condition, " ", 1); //выделяем знак (=)
+
+ String conditionValue = selectFromMarkerToMarker(condition, " ", 2); //выделяем значение (1)
+
boolean flag = false;
- String param = jsonReadStr(configLiveJson, param_name);
- if (sign == "=") {
- flag = param == value;
- } else if (sign == "!=") {
- flag = param != value;
- } else if (sign == "<") {
- flag = param.toInt() < value.toInt();
- } else if (sign == ">") {
- flag = param.toInt() > value.toInt();
- } else if (sign == ">=") {
- flag = param.toInt() >= value.toInt();
- } else if (sign == "<=") {
- flag = param.toInt() <= value.toInt();
+
+ String eventParam = jsonReadStr(configLiveJson, conditionParam); //получаем значение этого параметра события из json
+
+ if (conditionSign == "=") {
+ flag = eventParam == conditionValue;
+ } else if (conditionSign == "!=") {
+ flag = eventParam != conditionValue;
+ } else if (conditionSign == "<") {
+ flag = eventParam.toInt() < conditionValue.toInt();
+ } else if (conditionSign == ">") {
+ flag = eventParam.toInt() > conditionValue.toInt();
+ } else if (conditionSign == ">=") {
+ flag = eventParam.toInt() >= conditionValue.toInt();
+ } else if (conditionSign == "<=") {
+ flag = eventParam.toInt() <= conditionValue.toInt();
}
if (flag) {
- // удаляем строку самого сценария оставляя только команды
- block = deleteBeforeDelimiter(block, "\n");
- pm.info("do: " + block);
- // выполняем все команды
- stringExecute(block);
+ scenBlok = deleteBeforeDelimiter(scenBlok, "\n"); // удаляем строку самого сценария оставляя только команды
+ SerialPrint("I","module","do: " + scenBlok);
+ spaceCmdExecute(scenBlok); // выполняем все команды
}
}
}
- str = deleteBeforeDelimiter(str, "end\n"); //удаляем первый сценарий
- //-----------------------------------------------------------------------------------------------------------------------
+ scenarioTmp = deleteBeforeDelimiter(scenarioTmp, "end\n"); //удаляем первый сценарий
}
- String tmp2 = jsonReadStr(configOptionJson, "scenario_status"); //читаем файл событий
- tmp2 = deleteBeforeDelimiter(tmp2, ","); //удаляем выполненное событие
- jsonWriteStr(configOptionJson, "scenario_status", tmp2); //записываем обновленный файл событий
+
+ String eventBufTmp = eventBuf; //читаем файл событий
+ eventBufTmp = deleteBeforeDelimiter(eventBufTmp, ","); //удаляем выполненное событие
+ eventBuf = eventBufTmp; //записываем обновленный файл событий
}
-// событие: имя + Set + номер
-// button+Set+1
void eventGen(String event_name, String number) {
if (!jsonReadBool(configSetupJson, "scen")) {
return;
}
- // генерирование события
- String tmp = jsonReadStr(configOptionJson, "scenario_status");
- jsonWriteStr(configOptionJson, "scenario_status", tmp + event_name + number + ",");
+ eventBuf = event_name + number + ",";
}
String add_set(String str) {
@@ -96,4 +89,9 @@ String add_set(String str) {
}
}
return str;
-}
\ No newline at end of file
+}
+
+//button-out1 = 1
+//button-out2 1
+//button-out3 1
+//end
\ No newline at end of file
diff --git a/src/Sensors.cpp b/src/Sensors.cpp
index a23b5d3e..a4fe9bf1 100644
--- a/src/Sensors.cpp
+++ b/src/Sensors.cpp
@@ -1,651 +1,405 @@
-#include "Global.h"
+//#include "Cmd.h"
+//#include "Global.h"
-GMedian<10, int> medianFilter;
-DHTesp dht;
+//GMedian<10, int> medianFilter;
+//
+//Adafruit_BMP280 bmp;
+//Adafruit_Sensor *bmp_temp = bmp.getTemperatureSensor();
+//Adafruit_Sensor *bmp_pressure = bmp.getPressureSensor();
+//
+//Adafruit_BME280 bme;
+//Adafruit_Sensor *bme_temp = bme.getTemperatureSensor();
+//Adafruit_Sensor *bme_pressure = bme.getPressureSensor();
+//Adafruit_Sensor *bme_humidity = bme.getHumiditySensor();
-Adafruit_BMP280 bmp;
-Adafruit_Sensor *bmp_temp = bmp.getTemperatureSensor();
-Adafruit_Sensor *bmp_pressure = bmp.getPressureSensor();
+///const String perceptionStr(byte value);
+///const String comfortStr(ComfortState value);
-Adafruit_BME280 bme;
-Adafruit_Sensor *bme_temp = bme.getTemperatureSensor();
-Adafruit_Sensor *bme_pressure = bme.getPressureSensor();
-Adafruit_Sensor *bme_humidity = bme.getHumiditySensor();
+//void bmp280T_reading();
-const String perceptionStr(byte value);
-const String comfortStr(ComfortState value);
-void bmp280T_reading();
-void sensors_init() {
- ts.add(
- SENSORS, 1000, [&](void *) {
- static int counter;
- counter++;
-#ifdef LEVEL_ENABLED
- if (sensors_reading_map[0] == 1)
- ultrasonic_reading();
-#endif
- if (counter > 10) {
- counter = 0;
-
-#ifdef ANALOG_ENABLED
- if (sensors_reading_map[1] == 1)
- analog_reading1();
- if (sensors_reading_map[2] == 1)
- analog_reading2();
-#endif
-
-#ifdef DALLAS_ENABLED
- if (sensors_reading_map[3] == 1)
- dallas_reading();
-#endif
-
-#ifdef DHT_ENABLED
- if (sensors_reading_map[4] == 1)
- dhtT_reading();
- if (sensors_reading_map[5] == 1)
- dhtH_reading();
- if (sensors_reading_map[6] == 1)
- dhtP_reading();
- if (sensors_reading_map[7] == 1)
- dhtC_reading();
- if (sensors_reading_map[8] == 1)
- dhtD_reading();
-#endif
-
-#ifdef BMP_ENABLED
- if (sensors_reading_map[9] == 1)
- bmp280T_reading();
- if (sensors_reading_map[10] == 1)
- bmp280P_reading();
-#endif
-
-#ifdef BME_ENABLED
- if (sensors_reading_map[11] == 1)
- bme280T_reading();
- if (sensors_reading_map[12] == 1)
- bme280P_reading();
- if (sensors_reading_map[13] == 1)
- bme280H_reading();
- if (sensors_reading_map[14] == 1)
- bme280A_reading();
-#endif
- }
- },
- nullptr, true);
-}
-
-//=========================================================================================================================================
-//=========================================Модуль измерения уровня в баке==================================================================
-#ifdef LEVEL_ENABLED
-//levelPr p 14 12 Вода#в#баке,#% Датчики fillgauge 125 20 1
-void levelPr() {
- String value_name = sCmd.next();
- String trig = sCmd.next();
- String echo = sCmd.next();
- String widget_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();
- levelPr_value_name = value_name;
- jsonWriteStr(configOptionJson, "e_lev", empty_level);
- jsonWriteStr(configOptionJson, "f_lev", full_level);
- jsonWriteStr(configOptionJson, "trig", trig);
- jsonWriteStr(configOptionJson, "echo", echo);
- pinMode(trig.toInt(), OUTPUT);
- pinMode(echo.toInt(), INPUT);
- createWidgetByType(widget_name, page_name, page_number, type, value_name);
- sensors_reading_map[0] = 1;
-}
-//ultrasonicCm cm 14 12 Дистанция,#см Датчики fillgauge 1
-void ultrasonicCm() {
- String value_name = sCmd.next();
- String trig = sCmd.next();
- String echo = sCmd.next();
- String widget_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();
- ultrasonicCm_value_name = value_name;
- jsonWriteStr(configOptionJson, "trig", trig);
- jsonWriteStr(configOptionJson, "echo", echo);
- pinMode(trig.toInt(), OUTPUT);
- pinMode(echo.toInt(), INPUT);
- createWidgetByType(widget_name, page_name, page_number, type, value_name);
- sensors_reading_map[0] = 1;
-}
-
-void ultrasonic_reading() {
- long duration_;
- int distance_cm;
- int level;
- static int counter;
- int trig = jsonReadInt(configOptionJson, "trig");
- int echo = jsonReadInt(configOptionJson, "echo");
- digitalWrite(trig, LOW);
- delayMicroseconds(2);
- digitalWrite(trig, HIGH);
- delayMicroseconds(10);
- digitalWrite(trig, LOW);
- duration_ = pulseIn(echo, 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_SAMPLES) {
- counter = 0;
- level = map(distance_cm,
- jsonReadInt(configOptionJson, "e_lev"),
- jsonReadInt(configOptionJson, "f_lev"), 0, 100);
-
- jsonWriteInt(configLiveJson, levelPr_value_name, level);
- eventGen(levelPr_value_name, "");
-
- MqttClient::publishStatus(levelPr_value_name, String(level));
-
- Serial.println("[I] sensor '" + levelPr_value_name + "' data: " + String(level));
-
- jsonWriteInt(configLiveJson, ultrasonicCm_value_name, distance_cm);
- eventGen(ultrasonicCm_value_name, "");
-
- MqttClient::publishStatus(ultrasonicCm_value_name, String(distance_cm));
-
- Serial.println("[I] sensor '" + ultrasonicCm_value_name + "' data: " + String(distance_cm));
- }
-}
-#endif
-//=========================================================================================================================================
-//=========================================Модуль аналогового сенсора======================================================================
-#ifdef ANALOG_ENABLED
-//analog adc 0 Аналоговый#вход,#% Датчики any-data 1 1023 1 100 1
-void analog() {
- String value_name = sCmd.next();
- String pin = sCmd.next();
- String widget_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();
- analog_value_names_list += value_name + ",";
- enter_to_analog_counter++;
- jsonWriteStr(configOptionJson, value_name + "_st", analog_start);
- jsonWriteStr(configOptionJson, value_name + "_end", analog_end);
- jsonWriteStr(configOptionJson, value_name + "_st_out", analog_start_out);
- jsonWriteStr(configOptionJson, value_name + "_end_out", analog_end_out);
- createWidgetByType(widget_name, page_name, page_number, type, value_name);
- if (enter_to_analog_counter == 1) {
- sensors_reading_map[1] = 1;
- }
- if (enter_to_analog_counter == 2) {
- sensors_reading_map[2] = 1;
- }
-}
-
-void analog_reading1() {
- String value_name = selectFromMarkerToMarker(analog_value_names_list, ",", 0);
-#ifdef ESP32
- int analog_in = analogRead(34);
-#endif
-#ifdef ESP8266
- int analog_in = analogRead(A0);
-#endif
- int analog = map(analog_in,
- jsonReadInt(configOptionJson, value_name + "_st"),
- jsonReadInt(configOptionJson, value_name + "_end"),
- jsonReadInt(configOptionJson, value_name + "_st_out"),
- jsonReadInt(configOptionJson, value_name + "_end_out"));
- jsonWriteInt(configLiveJson, value_name, analog);
- eventGen(value_name, "");
- MqttClient::publishStatus(value_name, String(analog));
- Serial.println("[I] sensor '" + value_name + "' data: " + String(analog));
-}
-
-void analog_reading2() {
- String value_name = selectFromMarkerToMarker(analog_value_names_list, ",", 1);
-#ifdef ESP32
- int analog_in = analogRead(35);
-#endif
-#ifdef ESP8266
- int analog_in = analogRead(A0);
-#endif
- int analog = map(analog_in,
- jsonReadInt(configOptionJson, value_name + "_st"),
- jsonReadInt(configOptionJson, value_name + "_end"),
- jsonReadInt(configOptionJson, value_name + "_st_out"),
- jsonReadInt(configOptionJson, value_name + "_end_out"));
- jsonWriteInt(configLiveJson, value_name, analog);
- eventGen(value_name, "");
- MqttClient::publishStatus(value_name, String(analog));
- Serial.println("[I] sensor '" + value_name + "' data: " + String(analog));
-}
-#endif
-//=========================================================================================================================================
-//=========================================Модуль температурного сенсора ds18b20===========================================================
-#ifdef DALLAS_ENABLED
-//dallas temp1 2 1 Температура Датчики anydata 1
-//dallas temp2 2 2 Температура Датчики anydata 2
-void dallas() {
- String value_name = sCmd.next();
- String pin = sCmd.next();
- String address = sCmd.next();
- jsonWriteStr(configOptionJson, value_name + "_ds", address);
- String widget_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);
- dallas_value_name += value_name + ";";
- createWidgetByType(widget_name, page_name, page_number, type, value_name);
- sensors_reading_map[3] = 1;
-}
-
-void dallas_reading() {
- float temp = 0;
- byte num = sensors.getDS18Count();
- String dallas_value_name_tmp_buf = dallas_value_name;
- sensors.requestTemperatures();
- for (byte i = 0; i < num; i++) {
- temp = sensors.getTempCByIndex(i);
- String buf = selectToMarker(dallas_value_name_tmp_buf, ";");
- dallas_value_name_tmp_buf = deleteBeforeDelimiter(dallas_value_name_tmp_buf, ";");
- jsonWriteStr(configLiveJson, buf, String(temp));
- eventGen(buf, "");
- MqttClient::publishStatus(buf, String(temp));
- Serial.println("[I] sensor '" + buf + "' send date " + String(temp));
- }
-}
-#endif
-//=========================================================================================================================================
-//=========================================Модуль сенсоров DHT=============================================================================
-#ifdef DHT_ENABLED
-//dhtT t 2 dht11 Температура#DHT,#t°C Датчики any-data 1
-void dhtT() {
- String value_name = sCmd.next();
- String pin = sCmd.next();
- String sensor_type = sCmd.next();
- String widget_name = sCmd.next();
- String page_name = sCmd.next();
- String type = sCmd.next();
- String page_number = sCmd.next();
- dhtT_value_name = value_name;
- if (sensor_type == "dht11") {
- dht.setup(pin.toInt(), DHTesp::DHT11);
- }
- if (sensor_type == "dht22") {
- dht.setup(pin.toInt(), DHTesp::DHT22);
- }
- createWidgetByType(widget_name, page_name, page_number, type, value_name);
- sensors_reading_map[4] = 1;
-}
-
-void dhtT_reading() {
- float value = 0;
- static int counter;
- if (dht.getStatus() != 0 && counter < 5) {
- MqttClient::publishStatus(dhtT_value_name, String(dht.getStatusString()));
- counter++;
- } else {
- counter = 0;
- value = dht.getTemperature();
- if (String(value) != "nan") {
- eventGen(dhtT_value_name, "");
- jsonWriteStr(configLiveJson, dhtT_value_name, String(value));
- MqttClient::publishStatus(dhtT_value_name, String(value));
- Serial.println("[I] sensor '" + dhtT_value_name + "' data: " + String(value));
- }
- }
-}
-
-//dhtH h 2 dht11 Влажность#DHT,#t°C Датчики any-data 1
-void dhtH() {
- String value_name = sCmd.next();
- String pin = sCmd.next();
- String sensor_type = sCmd.next();
- String widget_name = sCmd.next();
- String page_name = sCmd.next();
- String type = sCmd.next();
- String page_number = sCmd.next();
- dhtH_value_name = value_name;
- if (sensor_type == "dht11") {
- dht.setup(pin.toInt(), DHTesp::DHT11);
- }
- if (sensor_type == "dht22") {
- dht.setup(pin.toInt(), DHTesp::DHT22);
- }
- createWidgetByType(widget_name, page_name, page_number, type, value_name);
- sensors_reading_map[5] = 1;
-}
-
-void dhtH_reading() {
- float value = 0;
- static int counter;
- if (dht.getStatus() != 0 && counter < 5) {
- MqttClient::publishStatus(dhtH_value_name, String(dht.getStatusString()));
- counter++;
- } else {
- counter = 0;
- value = dht.getHumidity();
- if (String(value) != "nan") {
- eventGen(dhtH_value_name, "");
- jsonWriteStr(configLiveJson, dhtH_value_name, String(value));
- MqttClient::publishStatus(dhtH_value_name, String(value));
- Serial.println("[I] sensor '" + dhtH_value_name + "' data: " + String(value));
- }
- }
-}
-
-//dhtPerception Восприятие: Датчики 4
-void dhtP() {
- String widget_name = sCmd.next();
- String page_name = sCmd.next();
- String page_number = sCmd.next();
- createWidgetByType(widget_name, page_name, page_number, "any-data", "dhtPerception");
- sensors_reading_map[6] = 1;
-}
-
-void dhtP_reading() {
- byte value;
- if (dht.getStatus() != 0) {
- MqttClient::publishStatus("dhtPerception", String(dht.getStatusString()));
- } else {
- value = dht.computePerception(jsonReadStr(configLiveJson, dhtT_value_name).toFloat(), jsonReadStr(configLiveJson, dhtH_value_name).toFloat(), false);
- String final_line = perceptionStr(value);
- jsonWriteStr(configLiveJson, "dhtPerception", final_line);
- eventGen("dhtPerception", "");
- MqttClient::publishStatus("dhtPerception", final_line);
- if (mqtt.connected()) {
- Serial.println("[I] sensor 'dhtPerception' data: " + final_line);
- }
- }
-}
-
-//dhtComfort Степень#комфорта: Датчики 3
-void dhtC() {
- String widget_name = sCmd.next();
- String page_name = sCmd.next();
- String page_number = sCmd.next();
- createWidgetByType(widget_name, page_name, page_number, "anydata", "dhtComfort");
- sensors_reading_map[7] = 1;
-}
-
-void dhtC_reading() {
- ComfortState cf;
- if (dht.getStatus() != 0) {
- MqttClient::publishStatus("dhtComfort", String(dht.getStatusString()));
- } else {
- dht.getComfortRatio(cf, jsonReadStr(configLiveJson, dhtT_value_name).toFloat(), jsonReadStr(configLiveJson, dhtH_value_name).toFloat(), false);
- String final_line = comfortStr(cf);
- jsonWriteStr(configLiveJson, "dhtComfort", final_line);
- eventGen("dhtComfort", "");
- MqttClient::publishStatus("dhtComfort", final_line);
- Serial.println("[I] sensor 'dhtComfort' send date " + final_line);
- }
-}
-
-const String perceptionStr(byte value) {
- String res;
- switch (value) {
- case 0:
- res = F("Сухой воздух");
- break;
- case 1:
- res = F("Комфортно");
- break;
- case 2:
- res = F("Уютно");
- break;
- case 3:
- res = F("Хорошо");
- break;
- case 4:
- res = F("Неудобно");
- break;
- case 5:
- res = F("Довольно неудобно");
- break;
- case 6:
- res = F("Очень неудобно");
- break;
- case 7:
- res = F("Невыносимо");
- default:
- res = F("Unknown");
- break;
- }
- return res;
-}
-
-const String comfortStr(ComfortState value) {
- String res;
- switch (value) {
- case Comfort_OK:
- res = F("Отлично");
- break;
- case Comfort_TooHot:
- res = F("Очень жарко");
- break;
- case Comfort_TooCold:
- res = F("Очень холодно");
- break;
- case Comfort_TooDry:
- res = F("Очень сухо");
- break;
- case Comfort_TooHumid:
- res = F("Очень влажно");
- break;
- case Comfort_HotAndHumid:
- res = F("Жарко и влажно");
- break;
- case Comfort_HotAndDry:
- res = F("Жарко и сухо");
- break;
- case Comfort_ColdAndHumid:
- res = F("Холодно и влажно");
- break;
- case Comfort_ColdAndDry:
- res = F("Холодно и сухо");
- break;
- default:
- res = F("Неизвестно");
- break;
- };
- return res;
-}
-
-//dhtDewpoint Точка#росы: Датчики 5
-void dhtD() {
- String widget_name = sCmd.next();
- String page_name = sCmd.next();
- String page_number = sCmd.next();
- createWidgetByType(widget_name, page_name, page_number, "anydata", "dhtDewpoint");
- sensors_reading_map[8] = 1;
-}
-
-void dhtD_reading() {
- float value;
- if (dht.getStatus() != 0) {
- MqttClient::publishStatus("dhtDewpoint", String(dht.getStatusString()));
- } else {
- value = dht.computeDewPoint(jsonReadStr(configLiveJson, dhtT_value_name).toFloat(), jsonReadStr(configLiveJson, dhtH_value_name).toFloat(), false);
- jsonWriteInt(configLiveJson, "dhtDewpoint", value);
- eventGen("dhtDewpoint", "");
- MqttClient::publishStatus("dhtDewpoint", String(value));
- Serial.println("[I] sensor 'dhtDewpoint' data: " + String(value));
- }
-}
-#endif
+////=========================================================================================================================================
+////=========================================Модуль сенсоров DHT=============================================================================
+//#ifdef DHT_ENABLED
+////dhtT t 2 dht11 Температура#DHT,#t°C Датчики any-data 1
+//void dhtT() {
+// String value_name = sCmd.next();
+// String pin = sCmd.next();
+// String sensor_type = sCmd.next();
+// String widget_name = sCmd.next();
+// String page_name = sCmd.next();
+// String type = sCmd.next();
+// String page_number = sCmd.next();
+// //dhtT_value_name = value_name;
+// if (sensor_type == "dht11") {
+// dht.setup(pin.toInt(), DHTesp::DHT11);
+// }
+// if (sensor_type == "dht22") {
+// dht.setup(pin.toInt(), DHTesp::DHT22);
+// }
+// createWidgetByType(widget_name, page_name, page_number, type, value_name);
+// //sensors_reading_map[4] = 1;
+//}
+//
+//void dhtT_reading() {
+// float value = 0;
+// static int counter;
+// if (dht.getStatus() != 0 && counter < 5) {
+// // publishStatus(dhtT_value_name, String(dht.getStatusString()));
+// counter++;
+// } else {
+// counter = 0;
+// value = dht.getTemperature();
+// if (String(value) != "nan") {
+// //eventGen(dhtT_value_name, "");
+// //jsonWriteStr(configLiveJson, dhtT_value_name, String(value));
+// // publishStatus(dhtT_value_name, String(value));
+// //Serial.println("I sensor '" + dhtT_value_name + "' data: " + String(value));
+// }
+// }
+//}
+//
+////dhtH h 2 dht11 Влажность#DHT,#t°C Датчики any-data 1
+//void dhtH() {
+// String value_name = sCmd.next();
+// String pin = sCmd.next();
+// String sensor_type = sCmd.next();
+// String widget_name = sCmd.next();
+// String page_name = sCmd.next();
+// String type = sCmd.next();
+// String page_number = sCmd.next();
+// //dhtH_value_name = value_name;
+// if (sensor_type == "dht11") {
+// dht.setup(pin.toInt(), DHTesp::DHT11);
+// }
+// if (sensor_type == "dht22") {
+// dht.setup(pin.toInt(), DHTesp::DHT22);
+// }
+// createWidgetByType(widget_name, page_name, page_number, type, value_name);
+// //sensors_reading_map[5] = 1;
+//}
+//
+//void dhtH_reading() {
+// float value = 0;
+// static int counter;
+// if (dht.getStatus() != 0 && counter < 5) {
+// // publishStatus(dhtH_value_name, String(dht.getStatusString()));
+// counter++;
+// } else {
+// counter = 0;
+// value = dht.getHumidity();
+// if (String(value) != "nan") {
+// //eventGen(dhtH_value_name, "");
+// //jsonWriteStr(configLiveJson, dhtH_value_name, String(value));
+// // publishStatus(dhtH_value_name, String(value));
+// //Serial.println("I sensor '" + dhtH_value_name + "' data: " + String(value));
+// }
+// }
+//}
+//
+////dhtPerception Восприятие: Датчики 4
+//void dhtP() {
+// String widget_name = sCmd.next();
+// String page_name = sCmd.next();
+// String page_number = sCmd.next();
+// createWidgetByType(widget_name, page_name, page_number, "any-data", "dhtPerception");
+// //sensors_reading_map[6] = 1;
+//}
+//
+//void dhtP_reading() {
+// byte value;
+// if (dht.getStatus() != 0) {
+// publishStatus("dhtPerception", String(dht.getStatusString()));
+// } else {
+// //value = dht.computePerception(jsonReadStr(configLiveJson, dhtT_value_name).toFloat(), jsonReadStr(configLiveJson, dhtH_value_name).toFloat(), false);
+// String final_line = perceptionStr(value);
+// jsonWriteStr(configLiveJson, "dhtPerception", final_line);
+// eventGen("dhtPerception", "");
+// publishStatus("dhtPerception", final_line);
+// if (mqtt.connected()) {
+// Serial.println("I sensor 'dhtPerception' data: " + final_line);
+// }
+// }
+//}
+//
+////dhtComfort Степень#комфорта: Датчики 3
+//void dhtC() {
+// String widget_name = sCmd.next();
+// String page_name = sCmd.next();
+// String page_number = sCmd.next();
+// createWidgetByType(widget_name, page_name, page_number, "anydata", "dhtComfort");
+// //sensors_reading_map[7] = 1;
+//}
+//
+//void dhtC_reading() {
+// ComfortState cf;
+// if (dht.getStatus() != 0) {
+// publishStatus("dhtComfort", String(dht.getStatusString()));
+// } else {
+// //dht.getComfortRatio(cf, jsonReadStr(configLiveJson, dhtT_value_name).toFloat(), jsonReadStr(configLiveJson, dhtH_value_name).toFloat(), false);
+// String final_line = comfortStr(cf);
+// jsonWriteStr(configLiveJson, "dhtComfort", final_line);
+// eventGen("dhtComfort", "");
+// publishStatus("dhtComfort", final_line);
+// Serial.println("I sensor 'dhtComfort' send date " + final_line);
+// }
+//}
+//
+//const String perceptionStr(byte value) {
+// String res;
+// switch (value) {
+// case 0:
+// res = F("Сухой воздух");
+// break;
+// case 1:
+// res = F("Комфортно");
+// break;
+// case 2:
+// res = F("Уютно");
+// break;
+// case 3:
+// res = F("Хорошо");
+// break;
+// case 4:
+// res = F("Неудобно");
+// break;
+// case 5:
+// res = F("Довольно неудобно");
+// break;
+// case 6:
+// res = F("Очень неудобно");
+// break;
+// case 7:
+// res = F("Невыносимо");
+// default:
+// res = F("Unknown");
+// break;
+// }
+// return res;
+//}
+//
+//const String comfortStr(ComfortState value) {
+// String res;
+// switch (value) {
+// case Comfort_OK:
+// res = F("Отлично");
+// break;
+// case Comfort_TooHot:
+// res = F("Очень жарко");
+// break;
+// case Comfort_TooCold:
+// res = F("Очень холодно");
+// break;
+// case Comfort_TooDry:
+// res = F("Очень сухо");
+// break;
+// case Comfort_TooHumid:
+// res = F("Очень влажно");
+// break;
+// case Comfort_HotAndHumid:
+// res = F("Жарко и влажно");
+// break;
+// case Comfort_HotAndDry:
+// res = F("Жарко и сухо");
+// break;
+// case Comfort_ColdAndHumid:
+// res = F("Холодно и влажно");
+// break;
+// case Comfort_ColdAndDry:
+// res = F("Холодно и сухо");
+// break;
+// default:
+// res = F("Неизвестно");
+// break;
+// };
+// return res;
+//}
+//
+////dhtDewpoint Точка#росы: Датчики 5
+//void dhtD() {
+// String widget_name = sCmd.next();
+// String page_name = sCmd.next();
+// String page_number = sCmd.next();
+// createWidgetByType(widget_name, page_name, page_number, "anydata", "dhtDewpoint");
+// //sensors_reading_map[8] = 1;
+//}
+//
+//void dhtD_reading() {
+// float value;
+// if (dht.getStatus() != 0) {
+// publishStatus("dhtDewpoint", String(dht.getStatusString()));
+// } else {
+// //value = dht.computeDewPoint(jsonReadStr(configLiveJson, dhtT_value_name).toFloat(), jsonReadStr(configLiveJson, dhtH_value_name).toFloat(), false);
+// jsonWriteInt(configLiveJson, "dhtDewpoint", value);
+// eventGen("dhtDewpoint", "");
+// publishStatus("dhtDewpoint", String(value));
+// Serial.println("I sensor 'dhtDewpoint' data: " + String(value));
+// }
+//}
+//#endif
//=========================================i2c bus esp8266 scl-4 sda-5 ====================================================================
//=========================================================================================================================================
//=========================================Модуль сенсоров bmp280==========================================================================
-//bmp280T temp1 0x76 Температура#bmp280 Датчики any-data 1
-void bmp280T() {
- String value_name = sCmd.next();
- String address = sCmd.next();
- String widget_name = sCmd.next();
- String page_name = sCmd.next();
- String type = sCmd.next();
- String page_number = sCmd.next();
- bmp280T_value_name = value_name;
- createWidgetByType(widget_name, page_name, page_number, type, value_name);
- bmp.begin(hexStringToUint8(address));
- bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */
- Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */
- Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */
- Adafruit_BMP280::FILTER_X16, /* Filtering. */
- Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */
- //bmp_temp->printSensorDetails();
- sensors_reading_map[9] = 1;
-}
-
-void bmp280T_reading() {
- float value = 0;
- sensors_event_t temp_event;
- bmp_temp->getEvent(&temp_event);
- value = temp_event.temperature;
- jsonWriteStr(configLiveJson, bmp280T_value_name, String(value));
- eventGen(bmp280T_value_name, "");
- MqttClient::publishStatus(bmp280T_value_name, String(value));
- Serial.println("[I] sensor '" + bmp280T_value_name + "' data: " + String(value));
-}
-
-//bmp280P press1 0x76 Давление#bmp280 Датчики any-data 2
-void bmp280P() {
- String value_name = sCmd.next();
- String address = sCmd.next();
- String widget_name = sCmd.next();
- String page_name = sCmd.next();
- String type = sCmd.next();
- String page_number = sCmd.next();
- bmp280P_value_name = value_name;
- createWidgetByType(widget_name, page_name, page_number, type, value_name);
- bmp.begin(hexStringToUint8(address));
- bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */
- Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */
- Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */
- Adafruit_BMP280::FILTER_X16, /* Filtering. */
- Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */
- //bmp_temp->printSensorDetails();
- sensors_reading_map[10] = 1;
-}
-
-void bmp280P_reading() {
- float value = 0;
- sensors_event_t pressure_event;
- bmp_pressure->getEvent(&pressure_event);
- value = pressure_event.pressure;
- value = value / 1.333224;
- jsonWriteStr(configLiveJson, bmp280P_value_name, String(value));
- eventGen(bmp280P_value_name, "");
- MqttClient::publishStatus(bmp280P_value_name, String(value));
- Serial.println("[I] sensor '" + bmp280P_value_name + "' data: " + String(value));
-}
-
-//=========================================================================================================================================
-//=============================================Модуль сенсоров bme280======================================================================
-//bme280T temp1 0x76 Температура#bmp280 Датчики any-data 1
-void bme280T() {
- String value_name = sCmd.next();
- String address = sCmd.next();
- String widget_name = sCmd.next();
- String page_name = sCmd.next();
- String type = sCmd.next();
- String page_number = sCmd.next();
- bme280T_value_name = value_name;
- createWidgetByType(widget_name, page_name, page_number, type, value_name);
- bme.begin(hexStringToUint8(address));
- sensors_reading_map[11] = 1;
-}
-
-void bme280T_reading() {
- float value = 0;
- value = bme.readTemperature();
- jsonWriteStr(configLiveJson, bme280T_value_name, String(value));
- eventGen(bme280T_value_name, "");
- MqttClient::publishStatus(bme280T_value_name, String(value));
- Serial.println("[I] sensor '" + bme280T_value_name + "' data: " + String(value));
-}
-
-//bme280P pres1 0x76 Давление#bmp280 Датчики any-data 1
-void bme280P() {
- String value_name = sCmd.next();
- String address = sCmd.next();
- String widget_name = sCmd.next();
- String page_name = sCmd.next();
- String type = sCmd.next();
- String page_number = sCmd.next();
- bme280P_value_name = value_name;
- createWidgetByType(widget_name, page_name, page_number, type, value_name);
- bme.begin(hexStringToUint8(address));
- sensors_reading_map[12] = 1;
-}
-
-void bme280P_reading() {
- float value = 0;
- value = bme.readPressure();
- value = value / 1.333224 / 100;
- jsonWriteStr(configLiveJson, bme280P_value_name, String(value));
- eventGen(bme280P_value_name, "");
- MqttClient::publishStatus(bme280P_value_name, String(value));
- Serial.println("[I] sensor '" + bme280P_value_name + "' data: " + String(value));
-}
-
-//bme280H hum1 0x76 Влажность#bmp280 Датчики any-data 1
-void bme280H() {
- String value_name = sCmd.next();
- String address = sCmd.next();
- String widget_name = sCmd.next();
- String page_name = sCmd.next();
- String type = sCmd.next();
- String page_number = sCmd.next();
- bme280H_value_name = value_name;
- createWidgetByType(widget_name, page_name, page_number, type, value_name);
- bme.begin(hexStringToUint8(address));
- sensors_reading_map[13] = 1;
-}
-
-void bme280H_reading() {
- float value = 0;
- value = bme.readHumidity();
- jsonWriteStr(configLiveJson, bme280H_value_name, String(value));
- eventGen(bme280H_value_name, "");
- MqttClient::publishStatus(bme280H_value_name, String(value));
- Serial.println("[I] sensor '" + bme280H_value_name + "' data: " + String(value));
-}
-
-//bme280A altit1 0x76 Высота#bmp280 Датчики any-data 1
-void bme280A() {
- String value_name = sCmd.next();
- String address = sCmd.next();
- String widget_name = sCmd.next();
- String page_name = sCmd.next();
- String type = sCmd.next();
- String page_number = sCmd.next();
- bme280A_value_name = value_name;
- createWidgetByType(widget_name, page_name, page_number, type, value_name);
- bme.begin(hexStringToUint8(address));
- sensors_reading_map[14] = 1;
-}
-
-void bme280A_reading() {
- float value = bme.readAltitude(1013.25);
- jsonWriteStr(configLiveJson, bme280A_value_name, String(value, 2));
-
- eventGen(bme280A_value_name, "");
-
- MqttClient::publishStatus(bme280A_value_name, String(value));
-
- Serial.println("[I] sensor '" + bme280A_value_name + "' data: " + String(value));
-}
+////bmp280T temp1 0x76 Температура#bmp280 Датчики any-data 1
+//void bmp280T() {
+// String value_name = sCmd.next();
+// String address = sCmd.next();
+// String widget_name = sCmd.next();
+// String page_name = sCmd.next();
+// String type = sCmd.next();
+// String page_number = sCmd.next();
+// //bmp280T_value_name = value_name;
+// createWidgetByType(widget_name, page_name, page_number, type, value_name);
+// bmp.begin(hexStringToUint8(address));
+// bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */
+// Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */
+// Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */
+// Adafruit_BMP280::FILTER_X16, /* Filtering. */
+// Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */
+// //bmp_temp->printSensorDetails();
+// //sensors_reading_map[9] = 1;
+//}
+//
+//void bmp280T_reading() {
+// float value = 0;
+// sensors_event_t temp_event;
+// bmp_temp->getEvent(&temp_event);
+// value = temp_event.temperature;
+// //jsonWriteStr(configLiveJson, bmp280T_value_name, String(value));
+// //eventGen(bmp280T_value_name, "");
+// // publishStatus(bmp280T_value_name, String(value));
+// //Serial.println("I sensor '" + bmp280T_value_name + "' data: " + String(value));
+//}
+//
+////bmp280P press1 0x76 Давление#bmp280 Датчики any-data 2
+//void bmp280P() {
+// String value_name = sCmd.next();
+// String address = sCmd.next();
+// String widget_name = sCmd.next();
+// String page_name = sCmd.next();
+// String type = sCmd.next();
+// String page_number = sCmd.next();
+// //bmp280P_value_name = value_name;
+// createWidgetByType(widget_name, page_name, page_number, type, value_name);
+// bmp.begin(hexStringToUint8(address));
+// bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */
+// Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */
+// Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */
+// Adafruit_BMP280::FILTER_X16, /* Filtering. */
+// Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */
+// //bmp_temp->printSensorDetails();
+// //sensors_reading_map[10] = 1;
+//}
+//
+//void bmp280P_reading() {
+// float value = 0;
+// sensors_event_t pressure_event;
+// bmp_pressure->getEvent(&pressure_event);
+// value = pressure_event.pressure;
+// value = value / 1.333224;
+// //jsonWriteStr(configLiveJson, bmp280P_value_name, String(value));
+// //eventGen(bmp280P_value_name, "");
+// // publishStatus(bmp280P_value_name, String(value));
+// //Serial.println("I sensor '" + bmp280P_value_name + "' data: " + String(value));
+//}
+//
+////=========================================================================================================================================
+////=============================================Модуль сенсоров bme280======================================================================
+////bme280T temp1 0x76 Температура#bmp280 Датчики any-data 1
+//void bme280T() {
+// String value_name = sCmd.next();
+// String address = sCmd.next();
+// String widget_name = sCmd.next();
+// String page_name = sCmd.next();
+// String type = sCmd.next();
+// String page_number = sCmd.next();
+// //bme280T_value_name = value_name;
+// //createWidgetByType(widget_name, page_name, page_number, type, value_name);
+// //bme.begin(hexStringToUint8(address));
+// //sensors_reading_map[11] = 1;
+//}
+//
+//void bme280T_reading() {
+// float value = 0;
+// value = bme.readTemperature();
+// //jsonWriteStr(configLiveJson, bme280T_value_name, String(value));
+// //eventGen(bme280T_value_name, "");
+// // publishStatus(bme280T_value_name, String(value));
+// //Serial.println("I sensor '" + bme280T_value_name + "' data: " + String(value));
+//}
+//
+////bme280P pres1 0x76 Давление#bmp280 Датчики any-data 1
+//void bme280P() {
+// String value_name = sCmd.next();
+// String address = sCmd.next();
+// String widget_name = sCmd.next();
+// String page_name = sCmd.next();
+// String type = sCmd.next();
+// String page_number = sCmd.next();
+// //bme280P_value_name = value_name;
+// //createWidgetByType(widget_name, page_name, page_number, type, value_name);
+// //bme.begin(hexStringToUint8(address));
+// //sensors_reading_map[12] = 1;
+//}
+//
+//void bme280P_reading() {
+// float value = 0;
+// value = bme.readPressure();
+// value = value / 1.333224 / 100;
+// //jsonWriteStr(configLiveJson, bme280P_value_name, String(value));
+// //eventGen(bme280P_value_name, "");
+// // publishStatus(bme280P_value_name, String(value));
+// //Serial.println("I sensor '" + bme280P_value_name + "' data: " + String(value));
+//}
+//
+////bme280H hum1 0x76 Влажность#bmp280 Датчики any-data 1
+//void bme280H() {
+// String value_name = sCmd.next();
+// String address = sCmd.next();
+// String widget_name = sCmd.next();
+// String page_name = sCmd.next();
+// String type = sCmd.next();
+// String page_number = sCmd.next();
+// //bme280H_value_name = value_name;
+// createWidgetByType(widget_name, page_name, page_number, type, value_name);
+// bme.begin(hexStringToUint8(address));
+// //sensors_reading_map[13] = 1;
+//}
+//
+//void bme280H_reading() {
+// float value = 0;
+// value = bme.readHumidity();
+// //jsonWriteStr(configLiveJson, bme280H_value_name, String(value));
+// //eventGen(bme280H_value_name, "");
+// // publishStatus(bme280H_value_name, String(value));
+// //Serial.println("I sensor '" + bme280H_value_name + "' data: " + String(value));
+//}
+//
+////bme280A altit1 0x76 Высота#bmp280 Датчики any-data 1
+//void bme280A() {
+// String value_name = sCmd.next();
+// String address = sCmd.next();
+// String widget_name = sCmd.next();
+// String page_name = sCmd.next();
+// String type = sCmd.next();
+// String page_number = sCmd.next();
+// //bme280A_value_name = value_name;
+// createWidgetByType(widget_name, page_name, page_number, type, value_name);
+// bme.begin(hexStringToUint8(address));
+// //sensors_reading_map[14] = 1;
+//}
+//
+//void bme280A_reading() {
+// float value = bme.readAltitude(1013.25);
+// //jsonWriteStr(configLiveJson, bme280A_value_name, String(value, 2));
+//
+// //eventGen(bme280A_value_name, "");
+//
+// // publishStatus(bme280A_value_name, String(value));
+//
+// //Serial.println("I sensor '" + bme280A_value_name + "' data: " + String(value));
+//}
diff --git a/src/Timers.cpp b/src/Timers.cpp
index dbf451ba..dda1007b 100644
--- a/src/Timers.cpp
+++ b/src/Timers.cpp
@@ -11,8 +11,8 @@ void Timer_countdown_init() {
int i = 0;
do {
String timer = selectFromMarkerToMarker(old_line, ",", i);
- Serial.print("timer no " + String(i) + ": ");
- Serial.println(timer);
+ //Serial.print("timer no " + String(i) + ": ");
+ //Serial.println(timer);
if (timer == "not found" || timer == "") return;
int number = selectToMarker(timer, ":").toInt();
int time = readTimer(number);
@@ -48,10 +48,10 @@ void timerStart_() {
void addTimer(String number, String time) {
String tmp = jsonReadStr(configOptionJson, "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 выделяем таймер который надо заменить
+ 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 + ",";
diff --git a/src/Upgrade.cpp b/src/Upgrade.cpp
deleted file mode 100644
index 0ebfbc6c..00000000
--- a/src/Upgrade.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-#include "Upgrade.h"
-
-#include "Global.h"
-#include "ESP8266.h"
-
-static const char* MODULE = "Update";
-
-static const char* check_update_url PROGMEM = "http://91.204.228.124:1100/update/%s/version.txt";
-
-const String getAvailableUrl(const char* mcu) {
- char buf[128];
- sprintf_P(buf, check_update_url, mcu);
- return buf;
-}
-
-void getLastVersion() {
- if (checkUpdatesFlag) {
- String url;
-#ifdef ESP8266
- url = getAvailableUrl("esp8266");
-#else
- url = getAvailableUrl("esp32");
-#endif
- lastVersion = getURL(url);
- jsonWriteStr(configSetupJson, "last_version", lastVersion);
- checkUpdatesFlag = false;
- }
-}
-
-void initUpdater() {
- if (isNetworkActive()) {
- getLastVersion();
- if (lastVersion.length()) {
- pm.info("available: " + lastVersion);
- }
- };
-}
-
-void upgrade_firmware() {
- String scanerioBackup, configBackup, setupBackup;
-
- scanerioBackup = readFile(String(DEVICE_SCENARIO_FILE), 4096);
- configBackup = readFile(String(DEVICE_CONFIG_FILE), 4096);
- setupBackup = configSetupJson;
-
- pm.info("update data");
- WiFiClient wifiClient;
-#ifdef ESP8266
- ESPhttpUpdate.rebootOnUpdate(false);
- t_httpUpdate_return ret = ESPhttpUpdate.updateSpiffs(wifiClient, "http://91.204.228.124:1100/update/esp8266/esp32-esp8266_iot-manager_modules_firmware.spiffs.bin");
-#else
- httpUpdate.rebootOnUpdate(false);
- t_httpUpdate_return ret = httpUpdate.updateSpiffs(client_for_upgrade, "http://91.204.228.124:1100/update/esp32/esp32-esp8266_iot-manager_modules_firmware.spiffs.bin");
-#endif
- if (ret == HTTP_UPDATE_OK) {
- writeFile(String(DEVICE_SCENARIO_FILE), scanerioBackup);
- writeFile(String(DEVICE_CONFIG_FILE), configBackup);
- writeFile("config.json", setupBackup);
-
- saveConfig();
-
- pm.info("done!");
- } else {
- pm.error("on data");
- return;
- }
-
- Serial.println("update firmware");
-#ifdef ESP8266
- ret = ESPhttpUpdate.update(wifiClient, "http://91.204.228.124:1100/update/esp8266/esp32-esp8266_iot-manager_modules_firmware.ino.bin");
-#else
- ret = httpUpdate.update(client_for_upgrade, "http://91.204.228.124:1100/update/esp32/esp32-esp8266_iot-manager_modules_firmware.ino.bin");
-#endif
- if (ret == HTTP_UPDATE_OK) {
- pm.info("done! restart...");
- ESP.restart();
- } else {
- pm.error("on firmware");
- }
-}
-
-void do_update() {
- if (updateFlag) {
- updateFlag = false;
- upgrade_firmware();
- }
-}
\ No newline at end of file
diff --git a/src/UpgradeFirm.cpp b/src/UpgradeFirm.cpp
new file mode 100644
index 00000000..da099ac1
--- /dev/null
+++ b/src/UpgradeFirm.cpp
@@ -0,0 +1,107 @@
+#include "UpgradeFirm.h"
+
+#include "Class/NotAsinc.h"
+#include "ESP8266.h"
+#include "Global.h"
+
+void upgradeInit() {
+ myNotAsincActions->add(
+ do_UPGRADE, [&](void*) {
+ upgrade_firmware(3);
+ },
+ nullptr);
+
+ myNotAsincActions->add(
+ do_GETLASTVERSION, [&](void*) {
+ getLastVersion();
+ },
+ nullptr);
+
+ if (isNetworkActive()) {
+ getLastVersion();
+ if (lastVersion > 0) {
+ SerialPrint("I", "Update", "available version: " + lastVersion);
+ }
+ };
+}
+
+void getLastVersion() {
+ if ((WiFi.status() == WL_CONNECTED)) {
+ String tmp = getURL(F("http://95.128.182.133/projects/iotmanager/esp8266/esp8266ver/esp8266ver.txt"));
+ if (tmp == "error") {
+ lastVersion = -1;
+ } else {
+ lastVersion = tmp.toInt();
+ }
+ } else {
+ lastVersion = -2;
+ }
+ jsonWriteInt(configSetupJson, "last_version", lastVersion);
+}
+
+void upgrade_firmware(int type) {
+ String scenario_ForUpdate;
+ String devconfig_ForUpdate;
+ String configSetup_ForUpdate;
+
+ scenario_ForUpdate = readFile(String(DEVICE_SCENARIO_FILE), 4000);
+ devconfig_ForUpdate = readFile(String(DEVICE_CONFIG_FILE), 4000);
+ configSetup_ForUpdate = configSetupJson;
+
+ if (type == 1) { //only build
+ if (upgradeBuild()) restartEsp();
+ }
+
+ else if (type == 2) { //only spiffs
+ if (upgradeFS()) {
+ writeFile(String(DEVICE_SCENARIO_FILE), scenario_ForUpdate);
+ writeFile(String(DEVICE_CONFIG_FILE), devconfig_ForUpdate);
+ writeFile("config.json", configSetup_ForUpdate);
+ restartEsp();
+ }
+ }
+
+ else if (type == 3) { //spiffs and build
+ if (upgradeFS()) {
+ writeFile(String(DEVICE_SCENARIO_FILE), scenario_ForUpdate);
+ writeFile(String(DEVICE_CONFIG_FILE), devconfig_ForUpdate);
+ writeFile("config.json", configSetup_ForUpdate);
+ saveConfig();
+ if (upgradeBuild()) {
+ restartEsp();
+ }
+ }
+ }
+}
+
+bool upgradeFS() {
+ WiFiClient wifiClient;
+ bool ret = false;
+ Serial.println("Start upgrade LittleFS, please wait...");
+ ESPhttpUpdate.rebootOnUpdate(false);
+ t_httpUpdate_return retFS = ESPhttpUpdate.updateSpiffs(wifiClient, F("http://95.128.182.133/projects/iotmanager/esp8266/littlefs/littlefs.bin"));
+ if (retFS == HTTP_UPDATE_OK) { //если FS обновилась успешно
+ SerialPrint("I", "Update", "LittleFS upgrade done!");
+ ret = true;
+ }
+ return ret;
+}
+
+bool upgradeBuild() {
+ WiFiClient wifiClient;
+ bool ret = false;
+ Serial.println("Start upgrade BUILD, please wait...");
+ ESPhttpUpdate.rebootOnUpdate(false);
+ t_httpUpdate_return retBuild = ESPhttpUpdate.update(wifiClient, F("http://95.128.182.133/projects/iotmanager/esp8266/firmware/firmware.bin"));
+ if (retBuild == HTTP_UPDATE_OK) { //если BUILD обновился успешно
+ SerialPrint("I", "Update", "BUILD upgrade done!");
+ ret = true;
+ }
+ return ret;
+}
+
+void restartEsp() {
+ Serial.println("Restart ESP....");
+ delay(1000);
+ ESP.restart();
+}
\ No newline at end of file
diff --git a/src/Utils/FileUtils.cpp b/src/Utils/FileUtils.cpp
index be3c4e5a..5d7fe2ba 100644
--- a/src/Utils/FileUtils.cpp
+++ b/src/Utils/FileUtils.cpp
@@ -1,7 +1,7 @@
#include "Utils/FileUtils.h"
#include "Utils/PrintMessage.h"
-static const char* MODULE = "FS";
+
const String filepath(const String& filename) {
return filename.startsWith("/") ? filename : "/" + filename;
@@ -9,7 +9,7 @@ const String filepath(const String& filename) {
bool fileSystemInit() {
if (!LittleFS.begin()) {
- pm.error("init");
+ SerialPrint("[E]","Files","init");
return false;
}
return true;
@@ -19,10 +19,10 @@ void removeFile(const String& filename) {
String path = filepath(filename);
if (LittleFS.exists(path)) {
if (!LittleFS.remove(path)) {
- pm.error("remove " + path);
+ SerialPrint("[E]","Files","remove " + path);
}
} else {
- pm.info("not exist" + path);
+ SerialPrint("I","Files","not exist" + path);
}
}
@@ -30,7 +30,7 @@ File seekFile(const String& filename, size_t position) {
String path = filepath(filename);
auto file = LittleFS.open(path, "r");
if (!file) {
- pm.error("open " + path);
+ SerialPrint("[E]","Files","open " + path);
}
// поставим курсор в начало файла
file.seek(position, SeekSet);
@@ -51,7 +51,7 @@ const String readFileString(const String& filename, const String& to_find) {
return res;
}
-const String addFile(const String& filename, const String& str) {
+const String addFileLn(const String& filename, const String& str) {
String path = filepath(filename);
auto file = LittleFS.open(path, "a");
if (!file) {
@@ -62,17 +62,28 @@ const String addFile(const String& filename, const String& str) {
return "sucсess";
}
+const String addFile(const String& filename, const String& str) {
+ String path = filepath(filename);
+ auto file = LittleFS.open(path, "a");
+ if (!file) {
+ return "failed";
+ }
+ file.print(str);
+ file.close();
+ return "sucсess";
+}
+
bool copyFile(const String& src, const String& dst, bool overwrite) {
String srcPath = filepath(src);
String dstPath = filepath(dst);
- pm.info("copy " + srcPath + " to " + dstPath);
+ SerialPrint("I","Files","copy " + srcPath + " to " + dstPath);
if (!LittleFS.exists(srcPath)) {
- pm.error("not exist: " + srcPath);
+ SerialPrint("[E]","Files","not exist: " + srcPath);
return false;
}
if (LittleFS.exists(dstPath)) {
if (!overwrite) {
- pm.error("already exist: " + dstPath);
+ SerialPrint("[E]","Files","already exist: " + dstPath);
return false;
}
LittleFS.remove(dstPath);
diff --git a/src/Utils/JsonUtils.cpp b/src/Utils/JsonUtils.cpp
index 8bc3de8f..04b4b926 100644
--- a/src/Utils/JsonUtils.cpp
+++ b/src/Utils/JsonUtils.cpp
@@ -1,4 +1,6 @@
#include "Utils\JsonUtils.h"
+#include "Utils/FileUtils.h"
+#include "Global.h"
#include
@@ -49,4 +51,8 @@ String jsonWriteFloat(String& json, String name, float value) {
json = "";
root.printTo(json);
return json;
+}
+
+void saveConfig() {
+ writeFile(String("config.json"), configSetupJson);
}
\ No newline at end of file
diff --git a/src/Utils/SerialPrint.cpp b/src/Utils/SerialPrint.cpp
new file mode 100644
index 00000000..8f57b3dd
--- /dev/null
+++ b/src/Utils/SerialPrint.cpp
@@ -0,0 +1,9 @@
+#include "Utils\SerialPrint.h"
+
+#include "Global.h"
+
+void SerialPrint(String errorLevel, String module, String msg) {
+ //if (module == "Stat" || module == "Update") {
+ Serial.println(prettyMillis(millis()) + " [" + errorLevel + "] [" + module + "] " + msg);
+ //}
+}
\ No newline at end of file
diff --git a/src/Utils/StringUtils.cpp b/src/Utils/StringUtils.cpp
index 64ee047d..7c043f0e 100644
--- a/src/Utils/StringUtils.cpp
+++ b/src/Utils/StringUtils.cpp
@@ -1,5 +1,4 @@
#include "Utils\StringUtils.h"
-
#include "Consts.h"
String selectToMarkerLast(String str, String found) {
diff --git a/src/Utils/SysUtils.cpp b/src/Utils/SysUtils.cpp
index d4eb5039..48704aea 100644
--- a/src/Utils/SysUtils.cpp
+++ b/src/Utils/SysUtils.cpp
@@ -1,6 +1,8 @@
#include "Utils/SysUtils.h"
#include "Global.h"
+#include "Utils/PrintMessage.h"
+
const String getUniqueId(const char* name) {
return String(name) + getMacAddress();
@@ -20,6 +22,11 @@ const String getChipId() {
return res;
}
+void setChipId() {
+ chipId = getChipId();
+ SerialPrint("I","System","id: " + chipId);
+}
+
#ifdef ESP8266
static uint32_t total_memory = 52864;
#else
@@ -69,6 +76,51 @@ const String getMacAddress() {
return String(buf);
}
+#ifdef ESP8266
+void setLedStatus(LedStatus_t status) {
+ if (jsonReadBool(configSetupJson, "blink") == 1) {
+ pinMode(LED_PIN, OUTPUT);
+ switch (status) {
+ case LED_OFF:
+ noTone(LED_PIN);
+ digitalWrite(LED_PIN, HIGH);
+ break;
+ case LED_ON:
+ noTone(LED_PIN);
+ digitalWrite(LED_PIN, LOW);
+ break;
+ case LED_SLOW:
+ tone(LED_PIN, 1);
+ break;
+ case LED_FAST:
+ tone(LED_PIN, 20);
+ break;
+ default:
+ break;
+ }
+ }
+}
+#else
+void setLedStatus(LedStatus_t status) {
+ if (jsonReadBool(configSetupJson, "blink") == 1) {
+ pinMode(LED_PIN, OUTPUT);
+ switch (status) {
+ case LED_OFF:
+ digitalWrite(LED_PIN, HIGH);
+ break;
+ case LED_ON:
+ digitalWrite(LED_PIN, LOW);
+ break;
+ case LED_SLOW:
+ break;
+ case LED_FAST:
+ break;
+ default:
+ break;
+ }
+ }
+}
+#endif
//===================================================================
/*
void web_print (String text) {
diff --git a/src/Utils/TimeUtils.cpp b/src/Utils/TimeUtils.cpp
index 04e53d1f..1464a245 100644
--- a/src/Utils/TimeUtils.cpp
+++ b/src/Utils/TimeUtils.cpp
@@ -1,4 +1,5 @@
#include "Utils\TimeUtils.h"
+
#include "Utils\StringUtils.h"
static const uint8_t days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
diff --git a/src/Utils/WebUtils.cpp b/src/Utils/WebUtils.cpp
new file mode 100644
index 00000000..fa0da202
--- /dev/null
+++ b/src/Utils/WebUtils.cpp
@@ -0,0 +1,90 @@
+#include "Utils\WebUtils.h"
+#include "ESPAsyncWebServer.h"
+
+String getURL(const String& urls) {
+ String res = "";
+ HTTPClient http;
+ http.begin(urls);
+ int httpCode = http.GET();
+ if (httpCode == HTTP_CODE_OK) {
+ res = http.getString();
+ } else {
+ res = "error";
+ }
+ http.end();
+ return res;
+}
+
+
+
+
+
+const String getMethodName(AsyncWebServerRequest* request) {
+ String res = F("UNKNOWN");
+ if (request->method() == HTTP_GET)
+ res = F("GET");
+ else if (request->method() == HTTP_POST)
+ res = F("POST");
+ else if (request->method() == HTTP_DELETE)
+ res = F("DELETE");
+ else if (request->method() == HTTP_PUT)
+ res = F("PUT");
+ else if (request->method() == HTTP_PATCH)
+ res = F("PATCH");
+ else if (request->method() == HTTP_HEAD)
+ res = F("HEAD");
+ else if (request->method() == HTTP_OPTIONS)
+ res = F("OPTIONS");
+ return res;
+}
+
+const String getRequestInfo(AsyncWebServerRequest* request) {
+ String res = getMethodName(request);
+ res += ' ';
+ res += "http://";
+ res += request->host();
+ res += request->url();
+ res += '\n';
+ if (request->contentLength()) {
+ res += "content-type: ";
+ res += request->contentType();
+ res += " content-lenght: ";
+ res += prettyBytes(request->contentLength());
+ res += '\n';
+ }
+
+ if (request->headers()) {
+ res += "headers:\n";
+ for (size_t i = 0; i < request->headers(); i++) {
+ AsyncWebHeader* h = request->getHeader(i);
+ res += h->name();
+ res += '=';
+ res += h->value();
+ res += '\n';
+ }
+ }
+
+ if (request->params()) {
+ res += "params:\n";
+ for (size_t i = 0; i < request->params(); i++) {
+ AsyncWebParameter* p = request->getParam(i);
+ if (p->isFile()) {
+ res += "FILE";
+ } else if (p->isPost()) {
+ res += "POST";
+ } else {
+ res += "GET";
+ }
+ res += ' ';
+ res += p->name();
+ res += ':';
+ res += p->value();
+ if (p->isFile()) {
+ res += " size:";
+ res += p->size();
+ }
+ res += '\n';
+ }
+ }
+ return res;
+}
diff --git a/src/Utils/WiFiUtils.cpp b/src/Utils/WiFiUtils.cpp
index 950ec1f2..f0c66eae 100644
--- a/src/Utils/WiFiUtils.cpp
+++ b/src/Utils/WiFiUtils.cpp
@@ -1,115 +1,106 @@
#include "Utils/WiFiUtils.h"
-static const char* MODULE = "WiFi";
-
-void startSTAMode() {
+void routerConnect() {
setLedStatus(LED_SLOW);
- pm.info("STA Mode");
-
- String ssid = jsonReadStr(configSetupJson, "routerssid");
- String passwd = jsonReadStr(configSetupJson, "routerpass");
-
WiFi.mode(WIFI_STA);
- if (ssid == "" && passwd == "") {
+ byte tries = 20;
+
+ String _ssid = jsonReadStr(configSetupJson, "routerssid");
+ String _password = jsonReadStr(configSetupJson, "routerpass");
+ //WiFi.persistent(false);
+
+ if (_ssid == "" && _password == "") {
WiFi.begin();
} else {
- if (WiFi.begin(ssid.c_str(), passwd.c_str()) == WL_CONNECT_FAILED) {
- pm.error("failed on start");
- }
+ WiFi.begin(_ssid.c_str(), _password.c_str());
+ SerialPrint("I", "WIFI", "ssid: " + _ssid);
}
- bool keepConnecting = true;
- uint8_t tries = 20;
- sint8_t connRes;
- do {
-#ifdef ESP8266
- connRes = WiFi.waitForConnectResult(1000);
-#else
- byte connRes = WiFi.waitForConnectResult();
-#endif
- switch (connRes) {
- case WL_NO_SSID_AVAIL: {
- pm.error("no network");
- keepConnecting = false;
- } break;
- case WL_CONNECTED: {
- String hostIpStr = WiFi.localIP().toString();
- pm.info("http://" + hostIpStr);
- jsonWriteStr(configSetupJson, "ip", hostIpStr);
- keepConnecting = false;
- } break;
- case WL_CONNECT_FAILED: {
- pm.error("check credentials");
- jsonWriteInt(configOptionJson, "pass_status", 1);
- keepConnecting = false;
- } break;
- default:
- break;
+ while (--tries && WiFi.status() != WL_CONNECTED) {
+ if (WiFi.status() == WL_CONNECT_FAILED) {
+ SerialPrint("E", "WIFI", "password is not correct");
+ tries = 1;
+ jsonWriteInt(configOptionJson, "pass_status", 1);
}
- } while (keepConnecting && tries--);
+ Serial.print(".");
+ delay(1000);
+ }
- if (isNetworkActive()) {
- MqttClient::init();
- setLedStatus(LED_OFF);
- } else {
- pm.error("failed: " + String(connRes, DEC));
+ if (WiFi.status() != WL_CONNECTED) {
+ Serial.println("");
startAPMode();
- };
+ } else {
+ Serial.println("");
+ SerialPrint("I", "WIFI", "http://" + WiFi.localIP().toString());
+ jsonWriteStr(configSetupJson, "ip", WiFi.localIP().toString());
+ setLedStatus(LED_OFF);
+ mqttInit();
+ }
}
bool startAPMode() {
setLedStatus(LED_ON);
- pm.info("AP Mode");
-
- String ssid = jsonReadStr(configSetupJson, "apssid");
- String passwd = jsonReadStr(configSetupJson, "appass");
+ SerialPrint("I", "WIFI", "AP Mode");
+ WiFi.disconnect();
WiFi.mode(WIFI_AP);
- WiFi.softAP(ssid.c_str(), passwd.c_str());
- String hostIpStr = WiFi.softAPIP().toString();
- pm.info("Host IP: " + hostIpStr);
- jsonWriteStr(configSetupJson, "ip", hostIpStr);
+ String _ssidAP = jsonReadStr(configSetupJson, "apssid");
+ String _passwordAP = jsonReadStr(configSetupJson, "appass");
+ WiFi.softAP(_ssidAP.c_str(), _passwordAP.c_str());
+ IPAddress myIP = WiFi.softAPIP();
+
+ SerialPrint("I", "WIFI", "AP IP: " + myIP.toString());
+ jsonWriteStr(configSetupJson, "ip", myIP.toString());
+
+ //if (jsonReadInt(configOptionJson, "pass_status") != 1) {
ts.add(
- WIFI_SCAN, 10 * 1000,
- [&](void*) {
+ WIFI_SCAN, 10 * 1000, [&](void*) {
String sta_ssid = jsonReadStr(configSetupJson, "routerssid");
- pm.info("scanning for " + sta_ssid);
- if (scanWiFi(sta_ssid)) {
+
+ SerialPrint("I", "WIFI", "scanning for " + sta_ssid);
+
+ if (RouterFind(sta_ssid)) {
ts.remove(WIFI_SCAN);
- startSTAMode();
+ WiFi.scanDelete();
+ routerConnect();
}
},
nullptr, true);
-
+ //}
return true;
}
-boolean scanWiFi(String ssid) {
+
+boolean RouterFind(String ssid) {
bool res = false;
- int8_t n = WiFi.scanComplete();
- pm.info("scan result: " + String(n, DEC));
- if (n == -2) {
- // не было запущено, запускаем
- pm.info("start scanning");
- // async, show_hidden
+ int n = WiFi.scanComplete();
+ SerialPrint("I", "WIFI", "scan result: " + String(n, DEC));
+
+ if (n == -2) { //Сканирование не было запущено, запускаем
+ SerialPrint("I", "WIFI", "start scanning");
+ WiFi.scanNetworks(true, false); //async, show_hidden
+ }
+
+ else if (n == -1) { //Сканирование все еще выполняется
+ SerialPrint("I", "WIFI", "scanning in progress");
+ }
+
+ else if (n == 0) { //ни одна сеть не найдена
+ SerialPrint("I", "WIFI", "no networks found");
WiFi.scanNetworks(true, false);
- } else if (n == -1) {
- // все еще выполняется
- pm.info("scanning in progress");
- } else if (n == 0) {
- // не найдена ни одна сеть
- pm.info("no networks found");
- WiFi.scanNetworks(true, false);
- } else if (n > 0) {
+ }
+
+ else if (n > 0) {
for (int8_t i = 0; i < n; i++) {
if (WiFi.SSID(i) == ssid) {
res = true;
}
- pm.info((res ? "*" : "") + String(i, DEC) + ") " + WiFi.SSID(i));
+ SerialPrint("I", "WIFI", (res ? "*" : "") + String(i, DEC) + ") " + WiFi.SSID(i));
}
}
+ WiFi.scanDelete();
return res;
}
diff --git a/src/Utils/statUtils.cpp b/src/Utils/statUtils.cpp
new file mode 100644
index 00000000..25529ca6
--- /dev/null
+++ b/src/Utils/statUtils.cpp
@@ -0,0 +1,249 @@
+#include "Utils/StatUtils.h"
+
+#include
+#include
+
+#include "Global.h"
+#include "ItemsList.h"
+
+
+void initSt() {
+ addNewDevice();
+ decide();
+ if (TELEMETRY_UPDATE_INTERVAL_MIN) {
+ ts.add(
+ STATISTICS, TELEMETRY_UPDATE_INTERVAL_MIN * 60000, [&](void*) {
+ static bool secondTime = false;
+ if (secondTime) getNextNumber("totalhrs.txt");
+ secondTime = true;
+ updateDeviceStatus();
+ },
+ nullptr, true);
+ }
+}
+
+void decide() {
+ if ((WiFi.status() == WL_CONNECTED)) {
+ uint8_t cnt = getNextNumber("stat.txt");
+ SerialPrint("I","Stat","Total resets number: " + String(cnt));
+ if (cnt <= 3) {
+ //Serial.println("(get)");
+ getPsn();
+ } else {
+ if (cnt % 5) {
+ //Serial.println("(skip)");
+ } else {
+ //Serial.println("(get)");
+ getPsn();
+ }
+ }
+ }
+}
+
+void getPsn() {
+ String res = getURL(F("http://ipinfo.io/?token=c60f88583ad1a4"));
+ if (res != "") {
+ String line = jsonReadStr(res, "loc");
+ String lat = selectToMarker(line, ",");
+ String lon = deleteBeforeDelimiter(line, ",");
+ //String city = jsonReadStr(res, "city");
+ //String country = jsonReadStr(res, "country");
+ //String region = jsonReadStr(res, "region");
+ updateDevicePsn(lat, lon, "1000");
+ }
+}
+
+String addNewDevice() {
+ String ret;
+ if ((WiFi.status() == WL_CONNECTED)) {
+ WiFiClient client;
+ HTTPClient http;
+ String json = "{}";
+ String mac = WiFi.macAddress().c_str();
+ //==============================================
+ jsonWriteStr(json, "uniqueId", mac);
+ jsonWriteStr(json, "name", FIRMWARE_NAME);
+ jsonWriteInt(json, "model", FIRMWARE_VERSION);
+ //==============================================
+ http.begin(client, F("http://95.128.182.133:8082/api/devices/"));
+ http.setAuthorization("admin", "admin");
+ http.addHeader("Content-Type", "application/json");
+ int httpCode = http.POST(json);
+ if (httpCode > 0) {
+ ret = httpCode;
+ if (httpCode == HTTP_CODE_OK) {
+ String payload = http.getString();
+ ret += " " + payload;
+ //saveId("statid.txt", jsonReadInt(payload, "id"));
+ }
+ } else {
+ ret = http.errorToString(httpCode).c_str();
+ }
+ http.end();
+ }
+ SerialPrint("I","Stat","New device registaration: " + ret);
+ return ret;
+}
+
+String updateDevicePsn(String lat, String lon, String accur) {
+ String ret;
+ if ((WiFi.status() == WL_CONNECTED)) {
+ WiFiClient client;
+ HTTPClient http;
+ http.begin(client, F("http://95.128.182.133:5055/"));
+ http.setAuthorization("admin", "admin");
+ http.addHeader("Content-Type", "application/json");
+ String mac = WiFi.macAddress().c_str();
+ int httpCode = http.POST("?id=" + mac +
+ "&resetReason=" + ESP.getResetReason() +
+ "&lat=" + lat +
+ "&lon=" + lon +
+ "&accuracy=" + accur + "");
+ if (httpCode > 0) {
+ ret = httpCode;
+ if (httpCode == HTTP_CODE_OK) {
+ String payload = http.getString();
+ ret += " " + payload;
+ }
+ } else {
+ ret = http.errorToString(httpCode).c_str();
+ }
+ http.end();
+ }
+ SerialPrint("I","Stat","Update device psn: " + ret);
+ return ret;
+}
+
+String updateDeviceStatus() {
+ String ret;
+ if ((WiFi.status() == WL_CONNECTED)) {
+ WiFiClient client;
+ HTTPClient http;
+ http.begin(client, F("http://95.128.182.133:5055/"));
+ http.setAuthorization("admin", "admin");
+ http.addHeader("Content-Type", "application/json");
+ String mac = WiFi.macAddress().c_str();
+ int httpCode = http.POST("?id=" + mac +
+ "&resetReason=" + ESP.getResetReason() +
+ "&uptime=" + timeNow->getUptime() +
+ "&uptimeTotal=" + getUptimeTotal() +
+ "&version=" + FIRMWARE_VERSION +
+ "&resetsTotal=" + String(getCurrentNumber("stat.txt")) + "");
+ if (httpCode > 0) {
+ ret = httpCode;
+ if (httpCode == HTTP_CODE_OK) {
+ String payload = http.getString();
+ ret += " " + payload;
+ }
+ } else {
+ ret = http.errorToString(httpCode).c_str();
+ }
+ http.end();
+ }
+ SerialPrint("I","Stat","Update device data: " + ret);
+ return ret;
+}
+
+String getUptimeTotal() {
+ uint8_t hrs = getCurrentNumber("totalhrs.txt");
+ String hrsStr = prettySeconds(hrs * 60 * 60);
+ SerialPrint("I","Stat","Total running time: " + hrsStr);
+ return hrsStr;
+}
+
+uint8_t getNextNumber(String file) {
+ uint8_t number = readFile(file, 100).toInt();
+ number++;
+ removeFile(file);
+ addFile(file, String(number));
+ return number;
+}
+
+uint8_t getCurrentNumber(String file) {
+ uint8_t number = readFile(file, 100).toInt();
+ return number;
+}
+
+
+//String getUptimeTotal() {
+// static int hrs;
+// EEPROM.begin(512);
+// hrs = eeGetInt(0);
+// SerialPrint("I","Stat","Total running hrs: " + String(hrs));
+// String hrsStr = prettySeconds(hrs * 60 * 60);
+// SerialPrint("I","Stat","Total running hrs (f): " + hrsStr);
+// return hrsStr;
+//}
+//int plusOneHour() {
+// static int hrs;
+// EEPROM.begin(512);
+// hrs = eeGetInt(0);
+// hrs++;
+// eeWriteInt(0, hrs);
+// return hrs;
+//}
+//
+//void eeWriteInt(int pos, int val) {
+// byte* p = (byte*)&val;
+// EEPROM.write(pos, *p);
+// EEPROM.write(pos + 1, *(p + 1));
+// EEPROM.write(pos + 2, *(p + 2));
+// EEPROM.write(pos + 3, *(p + 3));
+// EEPROM.commit();
+//}
+//
+//int eeGetInt(int pos) {
+// int val;
+// byte* p = (byte*)&val;
+// *p = EEPROM.read(pos);
+// *(p + 1) = EEPROM.read(pos + 1);
+// *(p + 2) = EEPROM.read(pos + 2);
+// *(p + 3) = EEPROM.read(pos + 3);
+// if (val < 0) {
+// return 0;
+// } else {
+// return val;
+// }
+//}
+//========for updating list of device=================
+/*
+void updateDeviceList() {
+ if ((WiFi.status() == WL_CONNECTED)) {
+ WiFiClient client;
+ HTTPClient http;
+ String json = "{}";
+ String mac = WiFi.macAddress().c_str();
+ //===============================================
+ jsonWriteStr(json, "uniqueId", mac);
+ jsonWriteStr(json, "name", FIRMWARE_NAME);
+ jsonWriteStr(json, "model", FIRMWARE_VERSION);
+ jsonWriteInt(json, "id", getId("statid.txt"));
+ //===============================================
+ http.begin(client, "http://95.128.182.133:8082/api/devices/" + mac + "/");
+ http.setAuthorization("admin", "admin");
+ http.addHeader("Content-Type", "application/json");
+ int httpCode = http.PUT(json);
+ if (httpCode > 0) {
+ Serial.printf("update Device List... code: %d\n", httpCode);
+ if (httpCode == HTTP_CODE_OK) {
+ const String& payload = http.getString();
+ Serial.println("received payload:\n<<");
+ Serial.println(payload);
+ Serial.println(">>");
+ }
+ } else {
+ Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str());
+ }
+ http.end();
+ }
+}
+
+void saveId(String file, int id) {
+ removeFile(file);
+ addFile(file, String(id));
+}
+
+int getId(String file) {
+ return readFile(file, 100).toInt();
+}
+*/
\ No newline at end of file
diff --git a/src/Web.cpp b/src/Web.cpp
index f3813638..07c8d914 100644
--- a/src/Web.cpp
+++ b/src/Web.cpp
@@ -1,7 +1,9 @@
+#include "Web.h"
+
+#include "Class/NotAsinc.h"
#include "Global.h"
#include "Init.h"
-
-static const char* MODULE = "Web";
+#include "ItemsList.h"
bool parseRequestForPreset(AsyncWebServerRequest* request, uint8_t& preset) {
if (request->hasArg("preset")) {
@@ -12,37 +14,29 @@ bool parseRequestForPreset(AsyncWebServerRequest* request, uint8_t& preset) {
}
void web_init() {
- // dnsServer.start(53, "*", WiFi.softAPIP());
- // server.addHandler(new CaptiveRequestHandler(jsonReadStr(configSetupJson, "name").c_str())).setFilter(ON_AP_FILTER);
-
- server.on("/restart", HTTP_GET, [](AsyncWebServerRequest* request) {
- if (request->hasArg("device")) {
- if (request->getParam("device")->value() == "ok") {
- ESP.restart();
- }
- request->send(200);
- };
- });
-
server.on("/set", HTTP_GET, [](AsyncWebServerRequest* request) {
- uint8_t preset;
- if (parseRequestForPreset(request, preset)) {
- pm.info("activate #" + String(preset, DEC));
- String configFile = DEVICE_CONFIG_FILE;
- String scenarioFile = DEVICE_SCENARIO_FILE;
- copyFile(getConfigFile(preset, CT_CONFIG), configFile);
- copyFile(getConfigFile(preset, CT_SCENARIO), scenarioFile);
- Device_init();
- loadScenario();
+ //==============================set.device.json====================================================================================================
+ if (request->hasArg("addItem")) {
+ String name = request->getParam("addItem")->value();
+ addItem(name);
request->redirect("/?set.device");
}
- //--------------------------------------------------------------------------------
- if (request->hasArg("devinit")) {
- Device_init();
+ if (request->hasArg("delChoosingItems")) {
+ myNotAsincActions->make(do_delChoosingItems);
request->send(200);
}
- //--------------------------------------------------------------------------------
+
+ if (request->hasArg("delAllItems")) {
+ delAllItems();
+ request->redirect("/?set.device");
+ }
+
+ if (request->hasArg("saveItems")) {
+ myNotAsincActions->make(do_deviceInit);
+ request->send(200);
+ }
+
if (request->hasArg("scen")) {
bool value = request->getParam("scen")->value().toInt();
jsonWriteBool(configSetupJson, "scen", value);
@@ -50,76 +44,62 @@ void web_init() {
loadScenario();
request->send(200);
}
- //--------------------------------------------------------------------------------
+
if (request->hasArg("sceninit")) {
loadScenario();
request->send(200);
}
- //--------------------------------------------------------------------------------
+
#ifdef LOGGING_ENABLED
if (request->hasArg("cleanlog")) {
clean_log_date();
request->send(200);
}
#endif
- //==============================udp settings=============================================
- if (request->hasArg("udponoff")) {
- bool value = request->getParam("udponoff")->value().toInt();
- jsonWriteBool(configSetupJson, "udponoff", value);
- saveConfig();
- loadScenario();
- request->send(200);
- }
- //--------------------------------------------------------------------------------
- if (request->hasArg("updatelist")) {
- removeFile("/dev.csv");
- addFile("dev.csv", "device id;device name;ip address");
- request->redirect("/?set.udp");
- }
- //--------------------------------------------------------------------------------
- if (request->hasArg("updatepage")) {
- request->redirect("/?set.udp");
- }
- //--------------------------------------------------------------------------------
+
+ //==============================wifi settings=============================================
if (request->hasArg("devname")) {
jsonWriteStr(configSetupJson, "name", request->getParam("devname")->value());
saveConfig();
request->send(200);
}
- //==============================wifi settings=============================================
+
if (request->hasArg("routerssid")) {
jsonWriteStr(configSetupJson, "routerssid", request->getParam("routerssid")->value());
saveConfig();
request->send(200);
}
+
if (request->hasArg("routerpass")) {
jsonWriteStr(configSetupJson, "routerpass", request->getParam("routerpass")->value());
saveConfig();
request->send(200);
}
- //--------------------------------------------------------------------------------
+
if (request->hasArg("apssid")) {
jsonWriteStr(configSetupJson, "apssid", request->getParam("apssid")->value());
saveConfig();
request->send(200, "text/text", "OK");
}
+
if (request->hasArg("appass")) {
jsonWriteStr(configSetupJson, "appass", request->getParam("appass")->value());
saveConfig();
request->send(200);
}
- //--------------------------------------------------------------------------------
+
if (request->hasArg("weblogin")) {
jsonWriteStr(configSetupJson, "weblogin", request->getParam("weblogin")->value());
saveConfig();
request->send(200);
}
+
if (request->hasArg("webpass")) {
jsonWriteStr(configSetupJson, "webpass", request->getParam("webpass")->value());
saveConfig();
request->send(200);
}
- //--------------------------------------------------------------------------------
+
if (request->hasArg("timezone")) {
String timezoneStr = request->getParam("timezone")->value();
jsonWriteStr(configSetupJson, "timezone", timezoneStr);
@@ -127,6 +107,7 @@ void web_init() {
timeNow->setTimezone(timezoneStr.toInt());
request->send(200);
}
+
if (request->hasArg("ntp")) {
String ntpStr = request->getParam("ntp")->value();
jsonWriteStr(configSetupJson, "ntp", ntpStr);
@@ -134,54 +115,69 @@ void web_init() {
timeNow->setNtpPool(ntpStr);
request->send(200);
}
- //--------------------------------------------------------------------------------
+
if (request->hasArg("blink")) {
bool value = request->getParam("blink")->value().toInt();
jsonWriteBool(configSetupJson, "blink", value);
saveConfig();
request->send(200);
}
+
+ if (request->hasArg("device")) {
+ if (request->getParam("device")->value() == "ok") {
+ ESP.restart();
+ }
+ request->send(200);
+ }
+
+ if (request->hasArg("test")) {
+ if (request->getParam("test")->value() == "ok") {
+ Serial.println("test pass");
+ }
+ request->send(200);
+ }
+
//==============================mqtt settings=============================================
+
if (request->hasArg("mqttServer")) {
jsonWriteStr(configSetupJson, "mqttServer", request->getParam("mqttServer")->value());
saveConfig();
- mqttParamsChanged = true;
+ myNotAsincActions->make(do_MQTTPARAMSCHANGED);
request->send(200);
}
if (request->hasArg("mqttPort")) {
int port = (request->getParam("mqttPort")->value()).toInt();
jsonWriteInt(configSetupJson, "mqttPort", port);
saveConfig();
- mqttParamsChanged = true;
+ myNotAsincActions->make(do_MQTTPARAMSCHANGED);
request->send(200);
}
if (request->hasArg("mqttPrefix")) {
jsonWriteStr(configSetupJson, "mqttPrefix", request->getParam("mqttPrefix")->value());
saveConfig();
- mqttParamsChanged = true;
+ myNotAsincActions->make(do_MQTTPARAMSCHANGED);
request->send(200);
}
if (request->hasArg("mqttUser")) {
jsonWriteStr(configSetupJson, "mqttUser", request->getParam("mqttUser")->value());
saveConfig();
- mqttParamsChanged = true;
+ myNotAsincActions->make(do_MQTTPARAMSCHANGED);
request->send(200);
}
if (request->hasArg("mqttPass")) {
jsonWriteStr(configSetupJson, "mqttPass", request->getParam("mqttPass")->value());
saveConfig();
- mqttParamsChanged = true;
- request->send(200);
- }
- //--------------------------------------------------------------------------------
- if (request->hasArg("mqttsend")) {
- mqtt_send_settings_to_udp = true;
+ myNotAsincActions->make(do_MQTTPARAMSCHANGED);
+ request->send(200);
+ }
+
+ if (request->hasArg("mqttsend")) {
+ myNotAsincActions->make(do_MQTTUDP);
request->send(200);
}
- //--------------------------------------------------------------------------------
if (request->hasArg("mqttcheck")) {
- String buf = "" + MqttClient::getStateStr();
+ String buf = "" + getStateStr();
String payload = "{}";
jsonWriteStr(payload, "title", buf);
@@ -190,62 +186,61 @@ void web_init() {
request->send(200, "text/html", payload);
}
- //==============================push settings=============================================
-#ifdef PUSH_ENABLED
- if (request->hasArg("pushingboxid")) {
- jsonWriteStr(configSetupJson, "pushingboxid", request->getParam("pushingboxid")->value());
- saveConfig();
- request->send(200);
- }
-#endif
+ // //==============================push settings=============================================
+ //#ifdef PUSH_ENABLED
+ // if (request->hasArg("pushingboxid")) {
+ // jsonWriteStr(configSetupJson, "pushingboxid", request->getParam("pushingboxid")->value());
+ // saveConfig();
+ // request->send(200);
+ // }
+ //#endif
//==============================utilities settings=============================================
- if (request->hasArg(TAG_I2C)) {
- busScanFlag = true;
- busToScan = BS_I2C;
+ if (request->hasArg("i2c")) {
+ myNotAsincActions->make(do_BUSSCAN);
request->redirect("/?set.utilities");
- } else if (request->hasArg(TAG_ONE_WIRE)) {
- busScanFlag = true;
- busToScan = BS_ONE_WIRE;
- if (request->hasParam(TAG_ONE_WIRE_PIN)) {
- setConfigParam(TAG_ONE_WIRE_PIN, request->getParam(TAG_ONE_WIRE_PIN)->value());
- }
- request->redirect("/?set.utilities");
- } else if (request->hasArg(TAG_ONE_WIRE_PIN)) {
- setConfigParam(TAG_ONE_WIRE_PIN, request->getParam(TAG_ONE_WIRE_PIN)->value());
- request->send(200);
}
});
+ //==============================list of items=====================================================
+ //server.on("/del", HTTP_GET, [](AsyncWebServerRequest* request) {
+ // if (request->hasArg("file")) {
+ // itemsFile = request->getParam("file")->value();
+ // }
+ // if (request->hasArg("line")) {
+ // itemsLine = request->getParam("line")->value();
+ // }
+ // delElementFlag = true;
+ // Device_init();
+ // request->redirect("/?setn.device");
+ //});
+
/*
* Check
*/
server.on("/check", HTTP_GET, [](AsyncWebServerRequest* request) {
- checkUpdatesFlag = true;
- pm.info("firmware version: " + lastVersion);
-
- if (!FLASH_4MB) {
- lastVersion = "less";
- } else if (isNetworkActive()) {
- lastVersion = "nowifi";
- }
+ myNotAsincActions->make(do_GETLASTVERSION);
+ SerialPrint("I", "Update", "firmware version: " + String(lastVersion));
String msg = "";
if (lastVersion == FIRMWARE_VERSION) {
msg = F("Актуальная версия прошивки уже установлена.");
- } else if (lastVersion != FIRMWARE_VERSION) {
- msg = F("Новая версия прошивкиИдет обновление прошивки, после обновления страница перезагрузится автоматически...')\">Установить");
- } else if (lastVersion == "error") {
+ } else if (lastVersion > FIRMWARE_VERSION) {
+ msg = F("Новая версия прошивкиИдет обновление прошивки, после обновления страница перезагрузится автоматически...')\">Установить");
+ } else if (lastVersion == -1) {
msg = F("Cервер не найден. Попробуйте повторить позже...");
- } else if (lastVersion == "") {
- msg = F("Нажмите на кнопку \"обновить прошивку\" повторно...");
- } else if (lastVersion == "less") {
- msg = F("Обновление \"по воздуху\" не поддерживается!");
- } else if (lastVersion == "nowifi") {
+ } else if (lastVersion == -2) {
msg = F("Устройство не подключено к роутеру!");
- } else if (lastVersion == "notsupported") {
- msg = F("Обновление возможно только через usb!");
}
+
+ // else if (lastVersion == "") {
+ //msg = F("Нажмите на кнопку \"обновить прошивку\" повторно...");
+ //} else if (lastVersion == "less") {
+ //msg = F("Обновление \"по воздуху\" не поддерживается!");
+ //} else if (lastVersion == "notsupported") {
+ // msg = F("Обновление возможно только через usb!");
+ //}
+
String tmp = "{}";
jsonWriteStr(tmp, "title", "" + msg);
jsonWriteStr(tmp, "class", "pop-up");
@@ -256,7 +251,13 @@ void web_init() {
* Upgrade
*/
server.on("/upgrade", HTTP_GET, [](AsyncWebServerRequest* request) {
- updateFlag = true;
+ myNotAsincActions->make(do_UPGRADE);
request->send(200, "text/html");
});
+}
+
+void setConfigParam(const char* param, const String& value) {
+ SerialPrint("I", "Web", "set " + String(param) + ": " + value);
+ jsonWriteStr(configSetupJson, param, value);
+ saveConfig();
}
\ No newline at end of file
diff --git a/src/WebServer.cpp b/src/WebServer.cpp
index 78e898a4..810a1add 100644
--- a/src/WebServer.cpp
+++ b/src/WebServer.cpp
@@ -1,11 +1,12 @@
#include "HttpServer.h"
-
+#include "BufferExecute.h"
#include "Utils/FileUtils.h"
#include "Utils/WebUtils.h"
+#include "FSEditor.h"
namespace HttpServer {
-static const char *MODULE = "Http";
+
/* Forward declaration */
void initOta();
void initMDNS();
@@ -15,9 +16,9 @@ void init() {
String login = jsonReadStr(configSetupJson, "weblogin");
String pass = jsonReadStr(configSetupJson, "webpass");
#ifdef ESP32
- server.addHandler(new SPIFFSEditor(LittleFS, login, pass));
+ server.addHandler(new FSEditor(LittleFS, login, pass));
#else
- server.addHandler(new SPIFFSEditor(login, pass));
+ server.addHandler(new FSEditor(login, pass));
#endif
server.serveStatic("/css/", LittleFS, "/css/").setCacheControl("max-age=600");
@@ -28,17 +29,17 @@ void init() {
server.serveStatic("/", LittleFS, "/").setDefaultFile("index.htm").setAuthentication(login.c_str(), pass.c_str());
server.onNotFound([](AsyncWebServerRequest *request) {
- pm.error("not found:\n" + getRequestInfo(request));
+ SerialPrint("[E]","WebServer","not found:\n" + getRequestInfo(request));
request->send(404);
});
server.onFileUpload([](AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final) {
// TODO
if (!index) {
- pm.info("start upload " + filename);
+ SerialPrint("I","WebServer","start upload " + filename);
}
if (final) {
- pm.info("finish upload: " + prettyBytes(index + len));
+ SerialPrint("I","WebServer","finish upload: " + prettyBytes(index + len));
}
});
@@ -59,8 +60,8 @@ void init() {
server.on("/cmd", HTTP_GET, [](AsyncWebServerRequest *request) {
String cmdStr = request->getParam("command")->value();
- pm.info("do: " + cmdStr);
- addCommandLoop(cmdStr);
+ SerialPrint("I","WebServer","do: " + cmdStr);
+ loopCmdAdd(cmdStr);
request->send(200, "text/html", "OK");
});
diff --git a/src/Widgets.cpp b/src/Widgets.cpp
index e05bafbb..13c58db1 100644
--- a/src/Widgets.cpp
+++ b/src/Widgets.cpp
@@ -1,6 +1,5 @@
#include "Global.h"
-static const char* MODULE = "Widget";
const String getWidgetFile(const String& name);
@@ -8,7 +7,7 @@ bool loadWidget(const String& filename, String& buf) {
buf = readFile(getWidgetFile(filename), 2048);
bool res = !(buf == "Failed" || buf == "Large");
if (!res) {
- pm.error("on load" + filename);
+ SerialPrint("[E]","Widgets","on load" + filename);
}
return res;
}
@@ -29,7 +28,7 @@ void createWidget(String descr, String page, String order, String filename, Stri
#ifdef LAYOUT_IN_RAM
all_widgets += widget + "\r\n";
#else
- addFile("layout.txt", buf);
+ addFileLn("layout.txt", buf);
#endif
}
@@ -56,7 +55,7 @@ void createWidgetParam(String widget, String page, String pageNumber, String fil
#ifdef LAYOUT_IN_RAM
all_widgets += widget + "\r\n";
#else
- addFile("layout.txt", buf);
+ addFileLn("layout.txt", buf);
#endif
}
@@ -80,7 +79,7 @@ void createChart(String widget, String page, String pageNumber, String filename,
#ifdef LAYOUT_IN_RAM
all_widgets += widget + "\r\n";
#else
- addFile("layout.txt", buf);
+ addFileLn("layout.txt", buf);
#endif
}
diff --git a/src/items/ButtonInClass.cpp b/src/items/ButtonInClass.cpp
new file mode 100644
index 00000000..6f48a834
--- /dev/null
+++ b/src/items/ButtonInClass.cpp
@@ -0,0 +1,21 @@
+#include "ItemsCmd.h"
+#include "items/ButtonInClass.h"
+//==========================================Модуль физических кнопок========================================
+//button-in switch1 toggle Кнопки Свет 1 pin[2] db[20]
+//==========================================================================================================
+ButtonInClass myButtonIn;
+void buttonIn() {
+ myButtonIn.update();
+ String key = myButtonIn.gkey();
+ String pin = myButtonIn.gpin();
+ sCmd.addCommand(key.c_str(), buttonInSet);
+ myButtonIn.init();
+ myButtonIn.switchStateSetDefault();
+ myButtonIn.clear();
+}
+
+void buttonInSet() {
+ String key = sCmd.order();
+ String state = sCmd.next();
+ myButtonIn.switchChangeVirtual(key, state);
+}
\ No newline at end of file
diff --git a/src/items/ButtonOutClass.cpp b/src/items/ButtonOutClass.cpp
new file mode 100644
index 00000000..6f2b5d03
--- /dev/null
+++ b/src/items/ButtonOutClass.cpp
@@ -0,0 +1,23 @@
+#include "items/ButtonOutClass.h"
+
+#include "ItemsCmd.h"
+//==========================================Модуль кнопок===================================================
+//button-out light toggle Кнопки Свет 1 pin[12] inv[1] st[1]
+//==========================================================================================================
+ButtonOutClass myButtonOut;
+void buttonOut() {
+ myButtonOut.update();
+ String key = myButtonOut.gkey();
+ String pin = myButtonOut.gpin();
+ String inv = myButtonOut.ginv();
+ sCmd.addCommand(key.c_str(), buttonOutSet);
+ myButtonOut.init();
+ myButtonOut.pinStateSetDefault();
+ myButtonOut.clear();
+}
+
+void buttonOutSet() {
+ String key = sCmd.order();
+ String state = sCmd.next();
+ myButtonOut.pinChange(key, state);
+}
diff --git a/src/items/InputDigitClass.cpp b/src/items/InputDigitClass.cpp
new file mode 100644
index 00000000..ff221740
--- /dev/null
+++ b/src/items/InputDigitClass.cpp
@@ -0,0 +1,19 @@
+#include "ItemsCmd.h"
+#include "items/InputClass.h"
+//==========================================Модуль ввода цифровых значений==================================
+//input-digit digit1 inputDigit Ввод Введите.цифру 4 st[60]
+//==========================================================================================================
+InputClass myInputDigit;
+void inputDigit() {
+ myInputDigit.update();
+ String key = myInputDigit.gkey();
+ sCmd.addCommand(key.c_str(), inputDigitSet);
+ myInputDigit.inputSetDefaultFloat();
+ myInputDigit.clear();
+}
+
+void inputDigitSet() {
+ String key = sCmd.order();
+ String state = sCmd.next();
+ myInputDigit.inputSetFloat(key, state);
+}
\ No newline at end of file
diff --git a/src/items/InputTimeClass.cpp b/src/items/InputTimeClass.cpp
new file mode 100644
index 00000000..fa98061e
--- /dev/null
+++ b/src/items/InputTimeClass.cpp
@@ -0,0 +1,29 @@
+#include "ItemsCmd.h"
+#include "items/InputClass.h"
+//==========================================Модуль ввода времени============================================
+//input-time time1 inputTime Ввод Введите.время 4 st[10-00-00]
+//==========================================================================================================
+InputClass myInputTime;
+void inputTime() {
+ myInputTime.update();
+ String key = myInputTime.gkey();
+ sCmd.addCommand(key.c_str(), inputTimeSet);
+ myInputTime.inputSetDefaultStr();
+ myInputTime.clear();
+}
+
+void inputTimeSet() {
+ String key = sCmd.order();
+ String state = sCmd.next();
+ myInputTime.inputSetStr(key, state);
+}
+
+void handle_time_init() {
+ ts.add(
+ TIME, 1000, [&](void *) {
+ jsonWriteStr(configLiveJson, "time", timeNow->getTime());
+ jsonWriteStr(configLiveJson, "timenow", timeNow->getTimeJson());
+ eventGen("timenow", "");
+ },
+ nullptr, true);
+}
\ No newline at end of file
diff --git a/src/items/OutputTextClass.cpp b/src/items/OutputTextClass.cpp
new file mode 100644
index 00000000..89c6d322
--- /dev/null
+++ b/src/items/OutputTextClass.cpp
@@ -0,0 +1,19 @@
+#include "ItemsCmd.h"
+#include "items/OutputTextClass.h"
+//===============================================Модуль вывода текста============================================
+//output-text;id;anydata;Вывод;Сигнализация;order;st[Обнаружено.движение]
+//===============================================================================================================
+OutputTextClass myOutputText;
+void textOut() {
+ myOutputText.update();
+ String key = myOutputText.gkey();
+ sCmd.addCommand(key.c_str(), textOutSet);
+ myOutputText.OutputModuleStateSetDefault();
+ myOutputText.clear();
+}
+
+void textOutSet() {
+ String key = sCmd.order();
+ String state = sCmd.next();
+ myOutputText.OutputModuleChange(key, state);
+}
\ No newline at end of file
diff --git a/src/items/PwmOutClass.cpp b/src/items/PwmOutClass.cpp
new file mode 100644
index 00000000..42d63d6f
--- /dev/null
+++ b/src/items/PwmOutClass.cpp
@@ -0,0 +1,24 @@
+#include "ItemsCmd.h"
+#include "items/PwmOutClass.h"
+//==========================================Модуль управления ШИМ===================================================
+//pwm-out volume range Кнопки Свет 1 pin[12] st[500]
+//==================================================================================================================
+PwmOutClass myPwmOut;
+void pwmOut() {
+ myPwmOut.update();
+ String key = myPwmOut.gkey();
+ String pin = myPwmOut.gpin();
+ String inv = myPwmOut.ginv();
+ sCmd.addCommand(key.c_str(), pwmOutSet);
+ jsonWriteStr(configOptionJson, key + "_pin", pin);
+ myPwmOut.pwmModeSet();
+ myPwmOut.pwmStateSetDefault();
+ myPwmOut.clear();
+}
+
+void pwmOutSet() {
+ String key = sCmd.order();
+ String state = sCmd.next();
+ String pin = jsonReadStr(configOptionJson, key + "_pin");
+ myPwmOut.pwmChange(key, pin, state);
+}
\ No newline at end of file
diff --git a/src/items/SensorAnalogClass.cpp b/src/items/SensorAnalogClass.cpp
new file mode 100644
index 00000000..f7368ce6
--- /dev/null
+++ b/src/items/SensorAnalogClass.cpp
@@ -0,0 +1,22 @@
+#include "ItemsCmd.h"
+#include "items/SensorAnalogClass.h"
+#ifdef ANALOG_ENABLED
+//==============================================Модуль аналогового сенсора===========================================================================================
+//analog-adc;id;anydata;Сенсоры;Аналоговый;order;pin-adc;map[1,1024,1,100];c[1]
+//===================================================================================================================================================================
+SensorAnalogClass mySensorAnalog;
+void analogAdc() {
+ mySensorAnalog.update();
+ String key = mySensorAnalog.gkey();
+ sCmd.addCommand(key.c_str(), analogReading);
+ sensorReadingMap += key + ",";
+ mySensorAnalog.SensorAnalogInit();
+ mySensorAnalog.clear();
+}
+
+void analogReading() {
+ String key = sCmd.order();
+ String pin = jsonReadStr(configOptionJson, key + "_pin");
+ mySensorAnalog.SensorAnalogRead(key, pin);
+}
+#endif
\ No newline at end of file
diff --git a/src/items/SensorBme280Class.cpp b/src/items/SensorBme280Class.cpp
new file mode 100644
index 00000000..f07ae77e
--- /dev/null
+++ b/src/items/SensorBme280Class.cpp
@@ -0,0 +1,47 @@
+#include "items/SensorBme280Class.h"
+
+#include "ItemsCmd.h"
+//#ifdef SensorBme280Enabled
+//=========================================Модуль ультрозвукового дальномера==================================================================
+//bme280-temp;id;anydata;Сенсоры;Температура;order;c[1]
+//bme280-hum;id;anydata;Сенсоры;Температура;order;c[1]
+//bme280-press;id;anydata;Сенсоры;Температура;order;c[1]
+//=========================================================================================================================================
+SensorBme280Class mySensorBme280;
+
+void bme280Temp() {
+ mySensorBme280.update();
+ String key = mySensorBme280.gkey();
+ sCmd.addCommand(key.c_str(), bme280ReadingTemp);
+ mySensorBme280.SensorBme280Init();
+ mySensorBme280.clear();
+}
+void bme280ReadingTemp() {
+ String key = sCmd.order();
+ mySensorBme280.SensorBme280ReadTmp(key);
+}
+
+void bme280Hum() {
+ mySensorBme280.update();
+ String key = mySensorBme280.gkey();
+ sCmd.addCommand(key.c_str(), bme280ReadingHum);
+ mySensorBme280.SensorBme280Init();
+ mySensorBme280.clear();
+}
+void bme280ReadingHum() {
+ String key = sCmd.order();
+ mySensorBme280.SensorBme280ReadHum(key);
+}
+
+void bme280Press() {
+ mySensorBme280.update();
+ String key = mySensorBme280.gkey();
+ sCmd.addCommand(key.c_str(), bme280ReadingPress);
+ mySensorBme280.SensorBme280Init();
+ mySensorBme280.clear();
+}
+void bme280ReadingPress() {
+ String key = sCmd.order();
+ mySensorBme280.SensorBme280ReadPress(key);
+}
+//#endif
\ No newline at end of file
diff --git a/src/items/SensorBmp280Class.cpp b/src/items/SensorBmp280Class.cpp
new file mode 100644
index 00000000..1dbfbd5d
--- /dev/null
+++ b/src/items/SensorBmp280Class.cpp
@@ -0,0 +1,35 @@
+#include "items/SensorBmp280Class.h"
+
+#include "ItemsCmd.h"
+//#ifdef SensorBmp280Enabled
+//=========================================Модуль ультрозвукового дальномера==================================================================
+//bmp280-temp;id;anydata;Сенсоры;Температура;order;c[1]
+//bmp280-hum;id;anydata;Сенсоры;Температура;order;c[1]
+//bmp280-press;id;anydata;Сенсоры;Температура;order;c[1]
+//=========================================================================================================================================
+SensorBmp280Class mySensorBmp280;
+
+void bmp280Temp() {
+ mySensorBmp280.update();
+ String key = mySensorBmp280.gkey();
+ sCmd.addCommand(key.c_str(), bmp280ReadingTemp);
+ mySensorBmp280.SensorBmp280Init();
+ mySensorBmp280.clear();
+}
+void bmp280ReadingTemp() {
+ String key = sCmd.order();
+ mySensorBmp280.SensorBmp280ReadTmp(key);
+}
+
+void bmp280Press() {
+ mySensorBmp280.update();
+ String key = mySensorBmp280.gkey();
+ sCmd.addCommand(key.c_str(), bmp280ReadingPress);
+ mySensorBmp280.SensorBmp280Init();
+ mySensorBmp280.clear();
+}
+void bmp280ReadingPress() {
+ String key = sCmd.order();
+ mySensorBmp280.SensorBmp280ReadPress(key);
+}
+//#endif
\ No newline at end of file
diff --git a/src/items/SensorDallasClass.cpp b/src/items/SensorDallasClass.cpp
new file mode 100644
index 00000000..f0fe6dba
--- /dev/null
+++ b/src/items/SensorDallasClass.cpp
@@ -0,0 +1,20 @@
+#include "ItemsCmd.h"
+#include "items/SensorDallasClass.h"
+//#ifdef SensorDallasEnabled
+//=========================================Модуль ультрозвукового дальномера==================================================================
+//dallas-temp;id;anydata;Сенсоры;Температура;order;pin;c[1]
+//=========================================================================================================================================
+SensorDallasClass mySensorDallas;
+void dallasTemp() {
+ mySensorDallas.update();
+ String key = mySensorDallas.gkey();
+ sCmd.addCommand(key.c_str(), dallasReading);
+ mySensorDallas.SensorDallasInit();
+ mySensorDallas.clear();
+}
+
+void dallasReading() {
+ String key = sCmd.order();
+ mySensorDallas.SensorDallasRead(key);
+}
+//#endif
\ No newline at end of file
diff --git a/src/items/SensorDhtClass.cpp b/src/items/SensorDhtClass.cpp
new file mode 100644
index 00000000..38363a8b
--- /dev/null
+++ b/src/items/SensorDhtClass.cpp
@@ -0,0 +1,35 @@
+#include "items/SensorDhtClass.h"
+
+#include "ItemsCmd.h"
+//#ifdef SensorDhtEnabled
+//=========================================DHT Sensor==================================================================
+//dht-temp;id;anydata;Сенсоры;Температура;order;pin;type[dht11];c[1]
+//dht-hum;id;anydata;Сенсоры;Влажность;order;pin;type[dht11];c[1]
+//=========================================================================================================================================
+SensorDhtClass mySensorDht;
+void dhtTemp() {
+ mySensorDht.update();
+ String key = mySensorDht.gkey();
+ sCmd.addCommand(key.c_str(), dhtReadingTemp);
+ mySensorDht.SensorDhtInit();
+ mySensorDht.clear();
+}
+void dhtReadingTemp() {
+ String key = sCmd.order();
+ mySensorDht.SensorDhtReadTemp(key);
+}
+
+
+
+void dhtHum() {
+ mySensorDht.update();
+ String key = mySensorDht.gkey();
+ sCmd.addCommand(key.c_str(), dhtReadingHum);
+ mySensorDht.SensorDhtInit();
+ mySensorDht.clear();
+}
+void dhtReadingHum() {
+ String key = sCmd.order();
+ mySensorDht.SensorDhtReadHum(key);
+}
+//#endif
\ No newline at end of file
diff --git a/src/items/SensorModbusClass.cpp b/src/items/SensorModbusClass.cpp
new file mode 100644
index 00000000..2683256a
--- /dev/null
+++ b/src/items/SensorModbusClass.cpp
@@ -0,0 +1,23 @@
+//#include "items/SensorModbusClass.h"
+//
+//#include "ItemsCmd.h"
+////#ifdef SensorModbusEnabled
+////=========================================Модуль modbus===================================================================================
+////modbus;id;anydata;Сенсоры;Температура;order;addr[1];regaddr[0];c[1]
+////=========================================================================================================================================
+//SensorModbusClass mySensorModbus;
+//
+//void modbus() {
+// mySensorModbus.update();
+// String key = mySensorModbus.gkey();
+// sCmd.addCommand(key.c_str(), modbusReading);
+// mySensorModbus.SensorModbusInit();
+// mySensorModbus.clear();
+//}
+//void modbusReading() {
+// String key = sCmd.order();
+// String addr = sCmd.next();
+// String regaddr = sCmd.next();
+// mySensorModbus.SensorModbusRead(key, addr.toInt(), regaddr.toInt());
+//}
+////#endif
\ No newline at end of file
diff --git a/src/items/SensorUltrasonicClass.cpp b/src/items/SensorUltrasonicClass.cpp
new file mode 100644
index 00000000..6de999eb
--- /dev/null
+++ b/src/items/SensorUltrasonicClass.cpp
@@ -0,0 +1,20 @@
+#include "ItemsCmd.h"
+#include "items/SensorUltrasonicClass.h"
+//#ifdef SensorUltrasonicEnabled
+//=========================================Модуль ультрозвукового дальномера==================================================================
+//ultrasonic-cm;id;anydata;Сенсоры;Расстояние;order;pin[12,13];map[1,100,1,100];c[1]
+//=========================================================================================================================================
+SensorUltrasonic mySensorUltrasonic;
+void ultrasonicCm() {
+ mySensorUltrasonic.update();
+ String key = mySensorUltrasonic.gkey();
+ sCmd.addCommand(key.c_str(), ultrasonicReading);
+ mySensorUltrasonic.init();
+ mySensorUltrasonic.clear();
+}
+
+void ultrasonicReading() {
+ String key = sCmd.order();
+ mySensorUltrasonic.SensorUltrasonicRead(key);
+}
+//#endif
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index 9b2eeaf2..c86c10b9 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,15 +1,23 @@
+
+#include
+
+#include "BufferExecute.h"
+#include "Class/CallBackTest.h"
+#include "Class/NotAsinc.h"
+#include "Class/ScenarioClass.h"
+#include "Cmd.h"
#include "Global.h"
#include "Init.h"
-#include "Cmd.h"
-#include "HttpServer.h"
-#include "Bus/BusScannerFactory.h"
+#include "ItemsList.h"
+#include "Utils/StatUtils.h"
#include "Utils/Timings.h"
-#include "Class/Switch.h"
+#include "Utils\WebUtils.h"
+#include "items/ButtonInClass.h"
+//#include "RemoteOrdersUdp.h"
+#include "Bus.h"
void not_async_actions();
-static const char* MODULE = "Main";
-
Timings metric;
boolean initialized = false;
@@ -24,179 +32,90 @@ void setup() {
setChipId();
- pm.info("FS");
+ myNotAsincActions = new NotAsinc(do_LAST);
+ myScenario = new Scenario();
+
+ SerialPrint("I", "FS", "FS Init");
fileSystemInit();
- pm.info("Config");
+ SerialPrint("I", "Conf", "Config Init");
loadConfig();
- pm.info("Clock");
+ SerialPrint("I", "Time", "Clock Init");
clock_init();
- pm.info("Commands");
+ SerialPrint("I", "CMD", "Commands Init");
cmd_init();
- pm.info("Sensors");
- sensors_init();
+ SerialPrint("I", "Sensors", "Sensors Init");
+ sensorsInit();
- pm.info("Init");
+ SerialPrint("I", "Items", "Items Init");
+ itemsListInit();
+
+ SerialPrint("I", "Init", "Init Init");
all_init();
- pm.info("Network");
- startSTAMode();
+ SerialPrint("I", "WIFI", "Network Init");
+ routerConnect();
- pm.info("Uptime");
+ SerialPrint("I", "Uptime", "Uptime Init");
uptime_init();
- if (!TELEMETRY_UPDATE_INTERVAL) {
- pm.info("Telemetry: Disabled");
- }
- telemetry_init();
+ SerialPrint("I", "Update", "Updater Init");
+ upgradeInit();
- pm.info("Updater");
- initUpdater();
-
- pm.info("HttpServer");
+ SerialPrint("I", "HTTP", "HttpServer Init");
HttpServer::init();
- pm.info("WebAdmin");
+ SerialPrint("I", "Web", "WebAdmin Init");
web_init();
-#ifdef UDP_ENABLED
- pm.info("Broadcast UDP");
- udp_init();
+ SerialPrint("I", "Stat", "Stat Init");
+ initSt();
+
+ //SerialPrint("I","UDP","Udp Init");
+ //asyncUdpInit();
+
+ SerialPrint("I", "Bus", "Bus Init");
+ busInit();
+
+#ifdef SSDP_EN
+ SerialPrint("I", "SSDP", "Ssdp Init");
+ SsdpInit();
#endif
+
ts.add(
TEST, 1000 * 60, [&](void*) {
- pm.info(printMemoryStatus());
+ SerialPrint("I", "System", printMemoryStatus());
},
nullptr, true);
just_load = false;
-
- initialized = true;
+ initialized = true; //this second POST makes the data to be processed (you don't need to connect as "keep-alive" for that to work)
}
void loop() {
if (!initialized) {
return;
}
- timeNow->loop();
-
#ifdef OTA_UPDATES_ENABLED
ArduinoOTA.handle();
#endif
#ifdef WS_enable
ws.cleanupClients();
#endif
- not_async_actions();
-
- MqttClient::loop();
-
- loopCmd();
-
- mySwitch->loop();
-
- loopScenario();
-
-#ifdef UDP_ENABLED
- loopUdp();
-#endif
-
- loopSerial();
+ timeNow->loop();
+ mqttLoop();
+ myButtonIn.loop();
+ myScenario->loop();
+ loopCmdExecute();
+ //loopSerial();
+ myNotAsincActions->loop();
ts.update();
}
-void not_async_actions() {
- if (mqttParamsChanged) {
- MqttClient::reconnect();
- mqttParamsChanged = false;
- }
-
- getLastVersion();
-
- do_update();
-
-#ifdef UDP_ENABLED
- do_udp_data_parse();
- do_mqtt_send_settings_to_udp();
-#endif
-
- do_scan_bus();
-}
-
-String getURL(const String& urls) {
- String res = "";
- HTTPClient http;
- http.begin(urls);
- int httpCode = http.GET();
- if (httpCode == HTTP_CODE_OK) {
- res = http.getString();
- } else {
- res = "error";
- }
- http.end();
- return res;
-}
-
-void setChipId() {
- chipId = getChipId();
- pm.info("id: " + chipId);
-}
-
-void saveConfig() {
- writeFile(String("config.json"), configSetupJson);
-}
-
-void setConfigParam(const char* param, const String& value) {
- pm.info("set " + String(param) + ": " + value);
- jsonWriteStr(configSetupJson, param, value);
- saveConfig();
-}
-
-#ifdef ESP8266
-void setLedStatus(LedStatus_t status) {
- pinMode(LED_PIN, OUTPUT);
- switch (status) {
- case LED_OFF:
- noTone(LED_PIN);
- digitalWrite(LED_PIN, HIGH);
- break;
- case LED_ON:
- noTone(LED_PIN);
- digitalWrite(LED_PIN, LOW);
- break;
- case LED_SLOW:
- tone(LED_PIN, 1);
- break;
- case LED_FAST:
- tone(LED_PIN, 20);
- break;
- default:
- break;
- }
-}
-#else
-void setLedStatus(LedStatus_t status) {
- pinMode(LED_PIN, OUTPUT);
- switch (status) {
- case LED_OFF:
- digitalWrite(LED_PIN, HIGH);
- break;
- case LED_ON:
- digitalWrite(LED_PIN, LOW);
- break;
- case LED_SLOW:
- break;
- case LED_FAST:
- break;
- default:
- break;
- }
-}
-#endif
-
void clock_init() {
timeNow = new Clock();
timeNow->setNtpPool(jsonReadStr(configSetupJson, "ntp"));
@@ -208,13 +127,3 @@ void clock_init() {
},
nullptr, true);
}
-
-void do_scan_bus() {
- if (busScanFlag) {
- String res = "";
- BusScanner* scanner = BusScannerFactory::get(configSetupJson, busToScan, res);
- scanner->scan();
- jsonWriteStr(configLiveJson, String(scanner->tag()), res);
- busScanFlag = false;
- }
-}
diff --git a/src/udp.cpp b/src/udp.cpp
deleted file mode 100644
index 5b9dc977..00000000
--- a/src/udp.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-#include "Global.h"
-
-static const char* MODULE = "Udp";
-
-#ifdef ESP8266
-IPAddress udp_multicastIP(255, 255, 255, 255);
-WiFiUDP udp;
-#endif
-#ifdef ESP32
-IPAddress udp_multicastIP(239, 255, 255, 255);
-AsyncUDP udp;
-#endif
-String remote_ip;
-String received;
-int udp_period;
-boolean udp_busy = false;
-unsigned int udp_port = 4210;
-
-//TODO Помомему тут ошибка в define'ах
-void handleUdp_esp32();
-
-void add_dev_in_list(String fileName, String id, String dev_name, String ip);
-
-#ifdef UDP_ENABLED
-void udp_init() {
- removeFile("dev.csv");
- addFile("dev.csv", "device id;device name;ip address");
-
-#ifdef ESP8266
- udp.begin(udp_port);
-#endif
-
- handleUdp_esp32();
-
- randomSeed(micros());
- udp_period = random(50000, 60000);
-
- ts.add(
- UDP, udp_period, [&](void*) {
- if (jsonReadBool(configSetupJson, "udponoff") && isNetworkActive() && !udp_busy) {
- pm.info("send info");
- String payload = "iotm;";
- payload += chipId;
- payload += ";";
- payload += jsonReadStr(configSetupJson, "name");
-#ifdef ESP8266
- udp.beginPacketMulticast(udp_multicastIP, udp_port, WiFi.localIP());
- udp.write(payload.c_str());
- udp.endPacket();
-#endif
-#ifdef ESP32
- udp.broadcast(line_to_send.c_str());
-#endif
- }
- },
- nullptr, false);
-}
-
-bool isUdpEnabled() {
- return jsonReadBool(configSetupJson, "udponoff") && isNetworkActive();
-}
-
-void loopUdp() {
-#ifdef ESP8266
- if (!isUdpEnabled()) {
- return;
- }
-
- int packetSize = udp.parsePacket();
- if (!packetSize) {
- return;
- }
-
- char udp_packet[255];
- remote_ip = udp.remoteIP().toString();
-
- pm.info(prettyBytes(packetSize) + " from " + remote_ip + ":" + udp.remotePort());
-
- int len = udp.read(udp_packet, 255);
- if (len) {
- udp_packet[len] = '\x00';
- }
- received = String(udp_packet);
- if (received.indexOf("iotm;") >= 0 || received.indexOf("mqttServer") >= 0) {
- udp_data_parse = true;
- }
-#endif
- ;
-}
-
-void handleUdp_esp32() {
-#ifdef ESP32
- if (udp.listenMulticast(udp_multicastIP, udp_port)) {
- udp.onPacket([](AsyncUDPPacket packet) {
- received = (char*)packet.data();
- remote_ip = packet.remoteIP().toString();
- if (jsonReadStr(configSetupJson, "udponoff") == "1") {
- if (received.indexOf("iotm;") >= 0) {
- udp_data_parse = true;
- }
- if (received.indexOf("mqttServer") >= 0) {
- udp_data_parse = true;
- }
- }
- });
- }
-#endif
-}
-
-void do_udp_data_parse() {
- if (!udp_data_parse) {
- return;
- }
- if (received.indexOf("mqttServer") >= 0) {
- pm.info("received setting");
- jsonWriteStr(configSetupJson, "mqttServer", jsonReadStr(received, "mqttServer"));
- jsonWriteInt(configSetupJson, "mqttPort", jsonReadInt(received, "mqttPort"));
- jsonWriteStr(configSetupJson, "mqttPrefix", jsonReadStr(received, "mqttPrefix"));
- jsonWriteStr(configSetupJson, "mqttUser", jsonReadStr(received, "mqttUser"));
- jsonWriteStr(configSetupJson, "mqttPass", jsonReadStr(received, "mqttPass"));
- saveConfig();
- mqttParamsChanged = true;
- }
- if (received.indexOf("iotm;") >= 0) {
- add_dev_in_list("dev.csv", selectFromMarkerToMarker(received, ";", 1), selectFromMarkerToMarker(received, ";", 2), received);
- }
- udp_data_parse = false;
-}
-
-void add_dev_in_list(String filename, String id, String dev_name, String ip) {
- auto file = seekFile("/" + filename);
- if (!file.find(id.c_str())) {
- addFile(filename, id + ";" + dev_name + "; " + ip + "");
- }
-}
-
-void send_mqtt_to_udp() {
- if (!isUdpEnabled()) {
- return;
- }
- udp_busy = true;
- String data = "{}";
- jsonWriteStr(data, "mqttServer", jsonReadStr(configSetupJson, "mqttServer"));
- jsonWriteInt(data, "mqttPort", jsonReadInt(configSetupJson, "mqttPort"));
- jsonWriteStr(data, "mqttPrefix", jsonReadStr(configSetupJson, "mqttPrefix"));
- jsonWriteStr(data, "mqttUser", jsonReadStr(configSetupJson, "mqttUser"));
- jsonWriteStr(data, "mqttPass", jsonReadStr(configSetupJson, "mqttPass"));
-#ifdef ESP8266
- udp.beginPacketMulticast(udp_multicastIP, udp_port, WiFi.localIP());
- udp.write(data.c_str());
- udp.endPacket();
-#endif
-#ifdef ESP32
- udp.broadcast(mqtt_data.c_str());
-#endif
- pm.info("sent info");
- udp_busy = false;
-}
-
-void do_mqtt_send_settings_to_udp() {
- if (mqtt_send_settings_to_udp) {
- mqtt_send_settings_to_udp = false;
- send_mqtt_to_udp();
- }
-}
-#endif
\ No newline at end of file