Merge branch 'ver4dev' of https://github.com/biveraxe/IoTManager into ver4dev

This commit is contained in:
2022-12-22 08:57:21 +03:00
333 changed files with 68380 additions and 629 deletions

View File

@@ -0,0 +1,429 @@
#include "Global.h"
#include "classes/IoTItem.h"
#include "Arduino.h"
#include "MySensorsGate.h"
#ifdef MYSENSORS
// callback библиотеки mysensors
void receive(const MyMessage& message) {
String inMsg = String(message.getSender()) + "," + // node-id
String(message.getSensor()) + "," + // child-sensor-id
String(message.getType()) + "," + // type of var
String(message.getCommand()) + "," + // command
parseToString(message) + ";"; // value
// Serial.println("=>" + inMsg);
mysensorBuf += inMsg;
}
String parseToString(const MyMessage& message) {
String value = "error";
switch (message.getPayloadType()) {
case 0: // Payload type is string
value = message.getString();
return value;
case 1: // Payload type is byte
value = String(message.getByte());
return value;
case 2: // Payload type is INT16
value = String(message.getInt());
return value;
case 3: // Payload type is UINT16
value = String(message.getUInt());
return value;
case 4: // Payload type is INT32
value = String(message.getInt());
return value;
case 5: // Payload type is UINT32
value = String(message.getUInt());
return value;
case 6: // Payload type is binary
value = String(message.getBool());
return value;
case 7: // Payload type is float32
value = String(message.getFloat());
return value;
default:
return value;
}
}
#endif
class MySensorsGate : public IoTItem {
private:
public:
MySensorsGate(String parameters) : IoTItem(parameters) {
SerialPrint("i", "MySensors", "Gate initialized");
}
void doByInterval() {
}
void loop() {
loopMySensorsExecute();
}
~MySensorsGate(){};
void loopMySensorsExecute() {
if (mysensorBuf.length()) {
String tmp = selectToMarker(mysensorBuf, ";");
String nodeId = selectFromMarkerToMarker(tmp, ",", 0); // node-id
String childSensorId = selectFromMarkerToMarker(tmp, ",", 1); // child-sensor-id
String type = selectFromMarkerToMarker(tmp, ",", 2); // type of var
String command = selectFromMarkerToMarker(tmp, ",", 3); // command
String value = selectFromMarkerToMarker(tmp, ",", 4); // value
static bool presentBeenStarted = false;
String ID = "n" + nodeId + "s" + childSensorId;
static String infoJson = "{}";
if (childSensorId == "255") {
if (command == "3") { // это особое внутреннее сообщение
if (type == "11") { // название ноды
SerialPrint("i", "MySensors", "===================== " + value + " =====================");
}
if (type == "12") { // версия ноды
SerialPrint("i", "MySensors", "Node version: " + value);
}
}
} else {
if (command == "0") { // это презентация
presentBeenStarted = true;
int num;
String widget;
String descr;
sensorType(type.toInt(), num, widget, descr);
descr.replace("#", " ");
SerialPrint("i", "MySensors", "Presentation: " + ID + ": " + descr);
}
if (command == "1") { // это данные
if (value != "") {
if (presentBeenStarted) {
presentBeenStarted = false;
SerialPrint("i", "MySensors", "===================== " + nodeId + " =====================");
}
bool found = false;
for (std::list<IoTItem*>::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) {
if ((*it)->getID() == ID) {
found = true;
(*it)->setValue(value, true);
}
}
SerialPrint("i", "MySensors", "node: " + nodeId + ", sensor: " + childSensorId + ", command: " + command + ", type: " + type + ", val: " + value + ", found: " + String(found));
}
}
if (command == "2") { // это запрос значения переменной
SerialPrint("i", "MySensors", "Request a variable value");
}
}
mysensorBuf = deleteBeforeDelimiter(mysensorBuf, ";");
}
}
void sensorType(int index, int& num, String& widget, String& descr) {
switch (index) {
case 0:
descr = F("Door#and#window#sensors");
widget = F("alarm");
num = 1;
break;
case 1:
descr = F("Motion#sensors");
widget = F("alarm");
num = 1;
break;
case 2:
descr = F("Smoke#sensor");
widget = F("fillgauge");
num = 1;
break;
case 3:
descr = F("Binary#device#(on/off)");
widget = F("toggleBtn");
num = 2;
break;
case 4:
descr = F("Dimmable#device");
// to do
// widget = F("range");
// num = 2;
break;
case 5:
descr = F("Window#covers#or#shades");
// to do
// widget = F("range");
// num = 2;
break;
case 6:
descr = F("Temperature#sensor");
widget = F("anydataTemp");
num = 1;
break;
case 7:
descr = F("Humidity#sensor");
widget = F("anydataHum");
num = 1;
break;
case 8:
descr = F("Pressure#sensor");
widget = F("anydataPress");
num = 1;
break;
case 9:
descr = F("Wind#sensor");
widget = F("anydataTime");
num = 1;
break;
case 10:
descr = F("Rain#sensor");
widget = F("anydataTime");
num = 1;
break;
case 11:
descr = F("UV#sensor");
widget = F("anydataTime");
num = 1;
break;
case 12:
descr = F("Weight#sensor");
widget = F("anydataTime");
num = 1;
break;
case 13:
descr = F("Power#measuring#device");
widget = F("anydataWtt");
num = 1;
break;
case 14:
descr = F("Heater#device");
widget = F("anydataTemp");
num = 1;
break;
case 15:
descr = F("Distance#sensor");
widget = F("anydata");
num = 1;
break;
case 16:
descr = F("Light#sensor");
widget = F("anydataTime");
num = 1;
break;
case 17:
descr = F("Arduino#node#device");
widget = F("anydata");
num = 1;
break;
case 18:
descr = F("Arduino#repeating#node#device");
widget = F("anydata");
num = 1;
break;
case 19:
descr = F("Lock#device");
widget = F("toggleBtn");
num = 2;
break;
case 20:
descr = F("Ir#sender/receiver#device");
widget = F("toggleBtn");
num = 2;
break;
case 21:
descr = F("Water#meter");
widget = F("anydata");
num = 1;
break;
case 22:
descr = F("Air#quality#sensor");
widget = F("anydata");
num = 1;
break;
case 23:
descr = F("Custom#sensor");
widget = F("anydata");
num = 1;
break;
case 24:
descr = F("Dust#level#sensor");
widget = F("anydata");
num = 1;
break;
case 25:
descr = F("Scene#controller#device");
widget = F("anydata");
num = 1;
break;
case 26:
descr = F("RGB#light");
widget = F("anydata");
num = 1;
break;
case 27:
descr = F("RGBW#light#(with#separate#white#component)");
widget = F("anydata");
num = 1;
break;
case 28:
descr = F("Color#sensor");
widget = F("anydata");
num = 1;
break;
case 29:
descr = F("Thermostat/HVAC#device");
widget = F("anydata");
num = 1;
break;
case 30:
descr = F("Multimeter#device");
widget = F("anydataVlt");
num = 1;
break;
case 31:
descr = F("Sprinkler#device");
widget = F("anydata");
num = 1;
break;
case 32:
descr = F("Water#leak#sensor");
widget = F("alarm");
num = 1;
break;
case 33:
descr = F("Sound#sensor");
widget = F("anydata");
num = 1;
break;
case 34:
descr = F("Vibration#sensor");
widget = F("anydata");
num = 1;
break;
case 35:
descr = F("Moisture#sensor");
widget = F("anydata");
num = 1;
break;
case 36:
descr = F("LCD#text#device");
widget = F("anydata");
num = 1;
break;
case 37:
descr = F("Gas#meter");
widget = F("anydata");
num = 1;
break;
case 38:
descr = F("GPS#Sensor");
widget = F("anydata");
num = 1;
break;
case 39:
descr = F("Water#quality#sensor");
widget = F("anydata");
num = 1;
break;
default:
descr = F("Unknown");
widget = F("anydata");
num = 1;
break;
}
}
};
class MySensorsNode : public IoTItem {
private:
String id = "";
int orange = 0;
int red = 0;
int offline = 0;
int _minutesPassed = 0;
String json = "{}";
bool dataFromNode = false;
public:
MySensorsNode(String parameters) : IoTItem(parameters) {
jsonRead(parameters, F("id"), id);
jsonRead(parameters, F("orange"), orange);
jsonRead(parameters, F("red"), red);
jsonRead(parameters, F("offline"), offline);
dataFromNode = false;
SerialPrint("i", "MySensors", "Node initialized");
}
void setValue(const IoTValue& Value, bool genEvent = true) {
value = Value;
regEvent(value.valD, "MySensorsNode", false, genEvent);
_minutesPassed = 0;
prevMillis = millis();
dataFromNode = true;
setNewWidgetAttributes();
}
void doByInterval() {
_minutesPassed++;
setNewWidgetAttributes();
}
void loop() {
currentMillis = millis();
difference = currentMillis - prevMillis;
if (difference > 60000) {
prevMillis = millis();
this->doByInterval();
}
}
// событие когда пользователь подключается приложением или веб интерфейсом к усройству
void onMqttWsAppConnectEvent() {
setNewWidgetAttributes();
}
void setNewWidgetAttributes() {
if (dataFromNode) {
jsonWriteStr(json, F("info"), prettyMinutsTimeout(_minutesPassed));
if (orange != 0 && red != 0 && offline != 0) {
if (_minutesPassed < orange) {
jsonWriteStr(json, F("color"), "");
}
if (_minutesPassed >= orange && _minutesPassed < red) {
jsonWriteStr(json, F("color"), F("orange")); // сделаем виджет оранжевым
}
if (_minutesPassed >= red && _minutesPassed < offline) {
jsonWriteStr(json, F("color"), F("red")); // сделаем виджет красным
}
if (_minutesPassed >= offline) {
jsonWriteStr(json, F("info"), F("offline"));
}
}
} else {
jsonWriteStr(json, F("info"), F("awaiting"));
}
sendSubWidgetsValues(id, json);
}
~MySensorsNode(){};
};
void* getAPI_MySensorsGate(String subtype, String param) {
if (subtype == F("MySensorsGate")) {
return new MySensorsGate(param);
} else if (subtype == F("MySensorsNode")) {
return new MySensorsNode(param);
} else {
return nullptr;
}
}

View File

@@ -0,0 +1,54 @@
#pragma once
#include "Const.h"
#ifdef MYSENSORS
/*
* DESCRIPTION
* The ESP32 gateway sends data received from sensors to the WiFi link.
* The gateway also accepts input on ethernet interface, which is then sent out to the radio network.
* ----------- PINOUT --------------
* | IO | RF24 | RFM69 | RFM95 |
|------|------|-------|-------|
| MOSI | 23 | 23 | 23 |
| MISO | 19 | 19 | 19 |
| SCK | 18 | 18 | 18 |
| CSN | 5 | 5 | 5 |
| CE | 17 | - | - |
| RST | - | 17 | 17 |
| IRQ | 16* | 16 | 16 |
*/
// Enable debug prints to serial monitor
//#define MY_DEBUG
//#define MY_RF24_CE_PIN 26 // Двигать пин CE на D4 чтобы освободить I2C
//#define MY_RF24_CS_PIN 9
// Use a bit lower baudrate for serial prints on ESP8266 than default in MyConfig.h
#define MY_BAUD_RATE 115200
// Enables and select radio type (if attached)
#define MY_RADIO_RF24
//#define MY_RADIO_RFM69
//#define MY_RADIO_RFM95
//#define MY_RF24_DATARATE RF24_1MBPS // Для платы KeyWish скорость 1 мегабит
// How many clients should be able to connect to this gateway (default 1)
#define MY_GATEWAY_MAX_CLIENTS 10
// Set LOW transmit power level as default, if you have an amplified NRF-module and
// power your radio separately with a good regulator you can turn up PA level.
#define MY_RF24_PA_LEVEL RF24_PA_MAX
// используем гейт в режиме serial хотя нам этот режим не нужен, поэтому в библиотеки отключаем MY_SERIALDEVICE.print
// в файле MyGatewayTransportSerial.cpp в строчке 35
#define MY_GATEWAY_SERIAL
//#define CHILD_ID 1
#include <MySensors.h>
extern String parseToString(const MyMessage& message);
#endif

View File

@@ -0,0 +1,54 @@
{
"menuSection": "Исполнительные устройства",
"configItem": [
{
"global": 0,
"name": "MySensorsGate",
"type": "Reading",
"subtype": "MySensorsGate",
"id": "gt",
"widget": "nil",
"page": "",
"descr": ""
},
{
"global": 0,
"name": "MySensorsNode",
"type": "Reading",
"subtype": "MySensorsNode",
"id": "n",
"widget": "anydataTmp",
"page": "MySensors",
"descr": "Температура",
"orange": 60,
"red": 120,
"offline": 180,
"round": 1
}
],
"about": {
"authorName": "Dmitry Borisenko",
"authorContact": "https://t.me/Dmitry_Borisenko",
"authorGit": "https://github.com/DmitryBorisenko33",
"specialThanks": "",
"moduleName": "MySensorsGate",
"moduleVersion": "1.0",
"usedRam": {
"esp32_4mb": 15,
"esp8266_4mb": 0
},
"title": "Гейт MySensors",
"moduleDesc": "Устройство состоит из esp32 и подключенному к нему радиомодулю NRF24L01. Вместе в связке они образуют гейт, способный принимать данные датчиков. Датчики способны работать до нескольких лет на батарейках. Датчики делаются на базе nrf52832 от holyiot. Батарейки подключаются напрямик к nrf52832",
"retInfo": "",
"propInfo": {
"id": "Для настройки следует выбрать один раз MySensorsGate и выбрать сколько необходимо раз MySensorsNode. Вместо ID нужно указать например - n100s1. Это значит что мы будем получать данные с ноды 100 и с сенсора этой ноды под номером 1",
"orange": "количество минут после которого окрасить виджет в оранжевый цвет",
"red": "количество минут после которого окрасить виджет в красный цвет",
"offline": "количество минут после которого отобразить что устройство offline, если все три orange red и offline поставить в ноль - то функция окраски выключится"
}
},
"defActive": false,
"usedLibs": {
"esp32_4mb": []
}
}

View File

@@ -1,24 +1,19 @@
#include "Global.h"
#include "classes/IoTItem.h"
class TelegramLT : public IoTItem
{
public:
class TelegramLT : public IoTItem {
public:
String _prevMsg = "";
String _token;
String _chatID;
TelegramLT(String parameters) : IoTItem(parameters)
{
TelegramLT(String parameters) : IoTItem(parameters) {
jsonRead(parameters, "token", _token);
jsonRead(parameters, "chatID", _chatID);
}
void sendTelegramMsg(bool often, String msg)
{
if (WiFi.status() == WL_CONNECTED && (often || !often && _prevMsg != msg))
{
void sendTelegramMsg(bool often, String msg) {
if (WiFi.status() == WL_CONNECTED && (often || !often && _prevMsg != msg)) {
WiFiClient client;
HTTPClient http;
http.begin(client, "http://live-control.com/iotm/telegram.php");
@@ -29,14 +24,11 @@ public:
SerialPrint("<-", F("Telegram"), "chat ID: " + _chatID + ", msg: " + msg);
SerialPrint("->", F("Telegram"), "chat ID: " + _chatID + ", server: " + httpResponseCode);
if (!strstr(payload.c_str(), "{\"ok\":true"))
{
if (!strstr(payload.c_str(), "{\"ok\":true")) {
value.valD = 0;
Serial.printf("Telegram error, msg from server: %s\n", payload.c_str());
regEvent(value.valD, payload);
}
else
{
} else {
value.valD = 1;
regEvent(value.valD, payload);
}
@@ -45,27 +37,20 @@ public:
}
}
IoTValue execute(String command, std::vector<IoTValue> &param)
{
if (param.size() == 1)
{
IoTValue execute(String command, std::vector<IoTValue> &param) {
if (param.size() == 1) {
String strTmp;
if (param[0].isDecimal && param[0].valS == "")
strTmp = param[0].valD;
else
strTmp = param[0].valS;
if (command == "sendMsg")
{
if (param.size())
{
if (command == "sendMsg") {
if (param.size()) {
sendTelegramMsg(false, strTmp);
}
}
else if (command == "sendOftenMsg")
{
if (param.size())
{
} else if (command == "sendOftenMsg") {
if (param.size()) {
sendTelegramMsg(true, strTmp);
}
}
@@ -76,14 +61,10 @@ public:
~TelegramLT(){};
};
void *getAPI_TelegramLT(String subtype, String param)
{
if (subtype == F("TelegramLT"))
{
void *getAPI_TelegramLT(String subtype, String param) {
if (subtype == F("TelegramLT")) {
return new TelegramLT(param);
}
else
{
} else {
return nullptr;
}
}

View File

@@ -1,24 +1,24 @@
{
{
"menuSection": "Сенсоры",
"configItem": [{
"global": 0,
"name": "Аналоговый сенсор",
"type": "Reading",
"subtype": "AnalogAdc",
"id": "t",
"widget": "anydataTmp",
"page": "Сенсоры",
"descr": "Температура",
"map": "1,1024,1,100",
"plus": 0,
"multiply": 1,
"round": 1,
"pin": 0,
"int": 15,
"avgSteps": 1
}],
"configItem": [
{
"global": 0,
"name": "Аналоговый сенсор",
"type": "Reading",
"subtype": "AnalogAdc",
"id": "t",
"widget": "anydataTmp",
"page": "Сенсоры",
"descr": "Температура",
"map": "1,1024,1,100",
"plus": 0,
"multiply": 1,
"round": 1,
"pin": 0,
"int": 15,
"avgSteps": 1
}
],
"about": {
"authorName": "Ilya Belyakov",
"authorContact": "https://t.me/Biveraxe",
@@ -39,13 +39,13 @@
"int": "Количество секунд между опросами датчика."
}
},
"defActive": true,
"usedLibs": {
"esp32_4mb": [],
"esp8266_4mb": []
"esp8266_4mb": [],
"esp8266_1mb": [],
"esp8266_1mb_ota": [],
"esp8285_1mb": [],
"esp8285_1mb_ota": []
}
}

View File

@@ -71,6 +71,18 @@
],
"esp8266_4mb": [
"adafruit/Adafruit BME280 Library"
],
"esp8266_1mb": [
"adafruit/Adafruit BME280 Library"
],
"esp8266_1mb_ota": [
"adafruit/Adafruit BME280 Library"
],
"esp8285_1mb": [
"adafruit/Adafruit BME280 Library"
],
"esp8285_1mb_ota": [
"adafruit/Adafruit BME280 Library"
]
}
}

View File

@@ -57,6 +57,18 @@
],
"esp8266_4mb": [
"adafruit/Adafruit BMP280 Library"
],
"esp8266_1mb": [
"adafruit/Adafruit BMP280 Library"
],
"esp8266_1mb_ota": [
"adafruit/Adafruit BMP280 Library"
],
"esp8285_1mb": [
"adafruit/Adafruit BMP280 Library"
],
"esp8285_1mb_ota": [
"adafruit/Adafruit BMP280 Library"
]
}
}

View File

@@ -15,6 +15,8 @@ class Pzem004v : public IoTItem {
addr = jsonReadStr(parameters, "addr");
if (myUART) {
pzem = new PZEMSensor(myUART, hexStringToUint8(addr));
// раскомментируйте эту строку если нужно поменять адрес pzem
// SerialPrint("i", "Pzem", String(pzem->setAddress(0x03)));
}
}
@@ -179,6 +181,48 @@ class Pzem004pf : public IoTItem {
~Pzem004pf(){};
};
class Pzem004cmd : public IoTItem {
private:
String addr;
int changeaddr;
String setaddr;
int reset;
PZEMSensor* pzem;
public:
Pzem004cmd(String parameters) : IoTItem(parameters) {
jsonRead(parameters, F("addr"), addr);
jsonRead(parameters, F("changeaddr"), changeaddr);
jsonRead(parameters, F("setaddr"), setaddr);
jsonRead(parameters, F("reset"), reset);
if (myUART) {
pzem = new PZEMSensor(myUART, hexStringToUint8(addr));
if (changeaddr == 1) {
if (pzem->setAddress(hexStringToUint8(setaddr))) {
SerialPrint("i", "Pzem", "address set: " + setaddr);
} else {
SerialPrint("i", "Pzem", "set adress error");
}
}
if (reset == 1) {
if (pzem->reset()) {
SerialPrint("i", "Pzem", "reset done");
} else {
SerialPrint("i", "Pzem", "reset error");
}
}
}
}
void doByInterval() {
if (pzem) {
}
}
~Pzem004cmd(){};
};
void* getAPI_Pzem004(String subtype, String param) {
if (subtype == F("Pzem004v")) {
return new Pzem004v(param);
@@ -191,7 +235,9 @@ void* getAPI_Pzem004(String subtype, String param) {
} else if (subtype == F("Pzem004hz")) {
return new Pzem004hz(param);
} else if (subtype == F("Pzem004pf")) {
return new Pzem004pf(param);
return new Pzem004pf(param);
} else if (subtype == F("Pzem004cmd")) {
return new Pzem004cmd(param);
} else {
return nullptr;
}

View File

@@ -78,6 +78,21 @@
"int": 15,
"addr": "0xF8",
"round": 1
},
{
"global": 0,
"name": "PZEM настройка",
"type": "Reading",
"subtype": "Pzem004cmd",
"id": "set",
"widget": "nil",
"page": "",
"descr": "",
"int": 15,
"addr": "0xF8",
"changeaddr": 0,
"setaddr": "0x01",
"reset": 0
}
],
"about": {
@@ -86,7 +101,7 @@
"authorGit": "https://github.com/DmitryBorisenko33",
"specialThanks": "Serghei Crasnicov @Serghei63",
"moduleName": "Pzem004",
"moduleVersion": "1.0",
"moduleVersion": "1.1",
"usedRam": {
"esp32_4mb": 15,
"esp8266_4mb": 15
@@ -97,13 +112,17 @@
"Pzem004w",
"Pzem004wh",
"Pzem004hz",
"Pzem004pf"
"Pzem004pf",
"Pzem004cmd"
],
"title": "Счетчик электроэнергии PZEM 004 t версии 3.0 (с модбасом). Возможно подключение трех счетчиков к одной esp для трехфазных сетей. Для этого нужно настроить разные адреса modbus в платах pzem",
"moduleDesc": "Считает потраченную электроэнергию, измеряет напряжение, частоту, силу тока и прочие параметры",
"propInfo": {
"addr": "Адрес modbus",
"int": "Количество секунд между опросами датчика. Желателно устанавливать разные интервалы для параметров что бы опросы происходили в разное время."
"int": "Количество секунд между опросами датчика. Желателно устанавливать разные интервалы для параметров что бы опросы происходили в разное время.",
"changeaddr": "Поставьте этот параметр равным 1 и перезагрузите esp - будет установлен адрес указанный в setaddr. Смотрите в логе результат: [i] Pzem address set: 0x01",
"setaddr": "Новый адрес который нужно назначить",
"reset": "Поставьте этот параметр равным 1 и pzem будет сброшен к нулю. Смотрите в логе результат: [i] Pzem reset done"
}
},
"defActive": true,

View File

@@ -54,6 +54,18 @@
],
"esp8266_4mb": [
"robtillaart/SHT2x@^0.1.1"
],
"esp8266_1mb": [
"robtillaart/SHT2x@^0.1.1"
],
"esp8266_1mb_ota": [
"robtillaart/SHT2x@^0.1.1"
],
"esp8285_1mb": [
"robtillaart/SHT2x@^0.1.1"
],
"esp8285_1mb_ota": [
"robtillaart/SHT2x@^0.1.1"
]
}
}

View File

@@ -54,6 +54,18 @@
],
"esp8266_4mb": [
"WEMOS SHT3x@1.0.0"
],
"esp8266_1mb": [
"WEMOS SHT3x@1.0.0"
],
"esp8266_1mb_ota": [
"WEMOS SHT3x@1.0.0"
],
"esp8285_1mb": [
"WEMOS SHT3x@1.0.0"
],
"esp8285_1mb_ota": [
"WEMOS SHT3x@1.0.0"
]
}
}

View File

@@ -21,7 +21,7 @@ class Loging : public IoTItem {
IoTItem *dateIoTItem;
String prevDate = "";
bool firstTimeDate = true;
bool firstTimeInit = true;
long interval;
@@ -35,30 +35,30 @@ class Loging : public IoTItem {
SerialPrint("E", F("Loging"), "'" + id + "' user set more points than allowed, value reset to 300");
}
jsonRead(parameters, F("int"), interval);
interval = interval * 1000 * 60; //приводим к милисекундам
interval = interval * 1000 * 60; // приводим к милисекундам
jsonRead(parameters, F("keepdays"), keepdays);
//создадим экземпляр класса даты
// создадим экземпляр класса даты
dateIoTItem = (IoTItem *)getAPI_Date("{\"id\": \"" + id + "-date\",\"int\":\"20\",\"subtype\":\"date\"}");
IoTItems.push_back(dateIoTItem);
SerialPrint("E", F("Loging"), "created date instance " + id);
}
void doByInterval() {
//если объект логгирования не был создан
// если объект логгирования не был создан
if (!isItemExist(logid)) {
SerialPrint("E", F("Loging"), "'" + id + "' loging object not exist, return");
return;
}
String value = getItemValue(logid);
//если значение логгирования пустое
// если значение логгирования пустое
if (value == "") {
SerialPrint("E", F("Loging"), "'" + id + "' loging value is empty, return");
return;
}
//если время не было получено из интернета
// если время не было получено из интернета
if (!isTimeSynch) {
SerialPrint("E", F("Loging"), "'" + id + "' Сant loging - time not synchronized, return");
return;
@@ -71,16 +71,16 @@ class Loging : public IoTItem {
jsonWriteInt(logData, "x", unixTime);
jsonWriteFloat(logData, "y1", value.toFloat());
//прочитаем путь к файлу последнего сохранения
// прочитаем путь к файлу последнего сохранения
String filePath = readDataDB(id);
//если данные о файле отсутствуют, создадим новый
// если данные о файле отсутствуют, создадим новый
if (filePath == "failed" || filePath == "") {
SerialPrint("E", F("Loging"), "'" + id + "' file path not found, start create new file");
createNewFileWithData(logData);
return;
} else {
//если файл все же есть но был создан не сегодня, то создаем сегодняшний
// если файл все же есть но был создан не сегодня, то создаем сегодняшний
if (getTodayDateDotFormated() != getDateDotFormatedFromUnix(getFileUnixLocalTime(filePath))) {
SerialPrint("E", F("Loging"), "'" + id + "' file too old, start create new file");
createNewFileWithData(logData);
@@ -88,30 +88,31 @@ class Loging : public IoTItem {
}
}
//считаем количество строк и определяем размер файла
// считаем количество строк и определяем размер файла
size_t size = 0;
int lines = countJsonObj(filePath, size);
SerialPrint("i", F("Loging"), "'" + id + "' " + "lines = " + String(lines) + ", size = " + String(size));
//если количество строк до заданной величины и дата не менялась
// если количество строк до заданной величины и дата не менялась
if (lines <= points && !hasDayChanged()) {
//просто добавим в существующий файл новые данные
// просто добавим в существующий файл новые данные
addNewDataToExistingFile(filePath, logData);
//если больше или поменялась дата то создадим следующий файл
// если больше или поменялась дата то создадим следующий файл
} else {
createNewFileWithData(logData);
}
//запускаем процедуру удаления старых файлов если память переполняется
// запускаем процедуру удаления старых файлов если память переполняется
deleteLastFile();
}
void SetDoByInterval(String valse) {
void SetDoByInterval(String valse) {
String value = valse;
//если значение логгирования пустое
// если значение логгирования пустое
if (value == "") {
SerialPrint("E", F("LogingEvent"), "'" + id + "' loging value is empty, return");
return;
}
//если время не было получено из интернета
// если время не было получено из интернета
if (!isTimeSynch) {
SerialPrint("E", F("LogingEvent"), "'" + id + "' Сant loging - time not synchronized, return");
return;
@@ -120,16 +121,16 @@ void SetDoByInterval(String valse) {
String logData;
jsonWriteInt(logData, "x", unixTime);
jsonWriteFloat(logData, "y1", value.toFloat());
//прочитаем путь к файлу последнего сохранения
// прочитаем путь к файлу последнего сохранения
String filePath = readDataDB(id);
//если данные о файле отсутствуют, создадим новый
// если данные о файле отсутствуют, создадим новый
if (filePath == "failed" || filePath == "") {
SerialPrint("E", F("LogingEvent"), "'" + id + "' file path not found, start create new file");
createNewFileWithData(logData);
return;
} else {
//если файл все же есть но был создан не сегодня, то создаем сегодняшний
// если файл все же есть но был создан не сегодня, то создаем сегодняшний
if (getTodayDateDotFormated() != getDateDotFormatedFromUnix(getFileUnixLocalTime(filePath))) {
SerialPrint("E", F("LogingEvent"), "'" + id + "' file too old, start create new file");
createNewFileWithData(logData);
@@ -137,39 +138,38 @@ void SetDoByInterval(String valse) {
}
}
//считаем количество строк и определяем размер файла
// считаем количество строк и определяем размер файла
size_t size = 0;
int lines = countJsonObj(filePath, size);
SerialPrint("i", F("LogingEvent"), "'" + id + "' " + "lines = " + String(lines) + ", size = " + String(size));
//если количество строк до заданной величины и дата не менялась
// если количество строк до заданной величины и дата не менялась
if (lines <= points && !hasDayChanged()) {
//просто добавим в существующий файл новые данные
// просто добавим в существующий файл новые данные
addNewDataToExistingFile(filePath, logData);
//если больше или поменялась дата то создадим следующий файл
// если больше или поменялась дата то создадим следующий файл
} else {
createNewFileWithData(logData);
}
//запускаем процедуру удаления старых файлов если память переполняется
// запускаем процедуру удаления старых файлов если память переполняется
deleteLastFile();
}
void createNewFileWithData(String &logData) {
logData = logData + ",";
String path = "/lg/" + id + "/" + String(unixTimeShort) + ".txt"; //создадим путь вида /lg/id/133256622333.txt
//создадим пустой файл
if (writeEmptyFile(path) != "sucсess") {
String path = "/lg/" + id + "/" + String(unixTimeShort) + ".txt"; // создадим путь вида /lg/id/133256622333.txt
// создадим пустой файл
if (writeEmptyFile(path) != "success") {
SerialPrint("E", F("Loging"), "'" + id + "' file writing error, return");
return;
}
//запишем в него данные
if (addFile(path, logData) != "sucсess") {
// запишем в него данные
if (addFile(path, logData) != "success") {
SerialPrint("E", F("Loging"), "'" + id + "' data writing error, return");
return;
}
//запишем путь к нему в базу данных
if (saveDataDB(id, path) != "sucсess") {
// запишем путь к нему в базу данных
if (saveDataDB(id, path) != "success") {
SerialPrint("E", F("Loging"), "'" + id + "' db file writing error, return");
return;
}
@@ -178,20 +178,21 @@ void SetDoByInterval(String valse) {
void addNewDataToExistingFile(String &path, String &logData) {
logData = logData + ",";
if (addFile(path, logData) != "sucсess") {
if (addFile(path, logData) != "success") {
SerialPrint("i", F("Loging"), "'" + id + "' file writing error, return");
return;
};
SerialPrint("i", F("Loging"), "'" + id + "' loging in file http://" + WiFi.localIP().toString() + path);
}
// данная функция уже перенесена в ядро и будет удалена в последствии
bool hasDayChanged() {
bool changed = false;
String currentDate = getTodayDateDotFormated();
if (!firstTimeDate) {
if (!firstTimeInit) {
if (prevDate != currentDate) {
changed = true;
SerialPrint("i", F("NTP"), "Change day event");
SerialPrint("i", F("NTP"), F("Change day event"));
#if defined(ESP8266)
FileFS.gc();
#endif
@@ -199,7 +200,7 @@ void SetDoByInterval(String valse) {
#endif
}
}
firstTimeDate = false;
firstTimeInit = false;
prevDate = currentDate;
return changed;
}
@@ -242,7 +243,7 @@ void SetDoByInterval(String valse) {
filesList = deleteBeforeDelimiter(filesList, ";");
}
//если данных нет отправляем пустой грфик
// если данных нет отправляем пустой грфик
if (noData) {
clearValue();
}
@@ -308,17 +309,17 @@ void SetDoByInterval(String valse) {
difference = currentMillis - prevMillis;
if (difference >= interval) {
prevMillis = millis();
if(interval != 0){
if (interval != 0) {
this->doByInterval();
}
}
}
}
void regEvent(const String& value, const String& consoleInfo, bool error = false, bool genEvent = true) {
void regEvent(const String &value, const String &consoleInfo, bool error = false, bool genEvent = true) {
String userDate = getItemValue(id + "-date");
String currentDate = getTodayDateDotFormated();
//отправляем в график данные только когда выбран сегодняшний день
// отправляем в график данные только когда выбран сегодняшний день
if (userDate == currentDate) {
// generateEvent(_id, value);
// publishStatusMqtt(_id, value);
@@ -328,16 +329,16 @@ void SetDoByInterval(String valse) {
}
}
//просто максимальное количество точек
// просто максимальное количество точек
int calculateMaxCount() {
return 86400;
}
//путь вида: /lg/log/1231231.txt
// путь вида: /lg/log/1231231.txt
unsigned long getFileUnixLocalTime(String path) {
return gmtTimeToLocal(selectToMarkerLast(deleteToMarkerLast(path, "."), "/").toInt() + START_DATETIME);
}
void setValue(const IoTValue& Value, bool genEvent = true){
void setValue(const IoTValue &Value, bool genEvent = true) {
value = Value;
this->SetDoByInterval(String(value.valD));
SerialPrint("i", "Loging", "setValue:" + String(value.valD));
@@ -364,15 +365,15 @@ class Date : public IoTItem {
value.isDecimal = false;
}
void setValue(const String& valStr, bool genEvent = true) {
void setValue(const String &valStr, bool genEvent = true) {
value.valS = valStr;
setValue(value, genEvent);
}
void setValue(const IoTValue& Value, bool genEvent = true) {
void setValue(const IoTValue &Value, bool genEvent = true) {
value = Value;
regEvent(value.valS, "", false, genEvent);
//отправка данных при изменении даты
// отправка данных при изменении даты
for (std::list<IoTItem *>::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) {
if ((*it)->getSubtype() == "Loging") {
if ((*it)->getID() == selectToMarker(id, "-")) {

View File

@@ -9,6 +9,8 @@ class LogingDaily : public IoTItem {
String id;
String filesList = "";
String descr;
int _publishType = -2;
int _wsNum = -1;
@@ -16,10 +18,12 @@ class LogingDaily : public IoTItem {
int testMode;
int telegram;
IoTItem *dateIoTItem;
String prevDate = "";
bool firstTimeDate = true;
bool firstTimeInit = true;
long interval;
@@ -29,13 +33,15 @@ class LogingDaily : public IoTItem {
jsonRead(parameters, F("id"), id);
jsonRead(parameters, F("points"), points);
jsonRead(parameters, F("test"), testMode);
jsonRead(parameters, F("telegram"), telegram);
jsonRead(parameters, F("descr"), descr);
if (points > 365) {
points = 365;
SerialPrint("E", F("LogingDaily"), "'" + id + "' user set more points than allowed, value reset to 365");
}
jsonRead(parameters, F("int"), interval);
interval = interval * 1000 * 60; //приводим к милисекундам
interval = interval * 1000 * 60; // приводим к милисекундам
}
void doByInterval() {
@@ -45,7 +51,7 @@ class LogingDaily : public IoTItem {
}
void execute() {
//если объект логгирования не был создан
// если объект логгирования не был создан
if (!isItemExist(logid)) {
SerialPrint("E", F("LogingDaily"), "'" + id + "' LogingDaily object not exist, return");
return;
@@ -53,51 +59,60 @@ class LogingDaily : public IoTItem {
String value = getItemValue(logid);
//если значение логгирования пустое
// если значение логгирования пустое
if (value == "") {
SerialPrint("E", F("LogingDaily"), "'" + id + "' LogingDaily value is empty, return");
return;
}
//если время не было получено из интернета
// если время не было получено из интернета
if (!isTimeSynch) {
SerialPrint("E", F("LogingDaily"), "'" + id + "' Сant LogingDaily - time not synchronized, return");
SerialPrint("E", F("LogingDaily"), "'" + id + "' Cant LogingDaily - time not synchronized, return");
return;
}
String logData;
float currentValue = value.toFloat();
//прочитаем предудущее значение
// прочитаем предудущее значение
float prevValue = readDataDB(id + "-v").toFloat();
//сохраним в базу данных текущее значение, понадобится в следующие сутки
// сохраним в базу данных текущее значение, понадобится в следующие сутки
saveDataDB(id + "-v", value);
float difference = currentValue - prevValue;
if (telegram == 1) {
String msg = descr + ": total " + String(currentValue) + ", consumed " + String(difference);
for (std::list<IoTItem *>::iterator it = IoTItems.begin(); it != IoTItems.end(); ++it) {
if ((*it)->getSubtype() == "TelegramLT" || "Telegram") {
(*it)->sendTelegramMsg(false, msg);
}
}
}
jsonWriteInt(logData, "x", unixTime - 120);
jsonWriteFloat(logData, "y1", difference);
//прочитаем путь к файлу последнего сохранения
// прочитаем путь к файлу последнего сохранения
String filePath = readDataDB(id);
//если данные о файле отсутствуют, создадим новый
// если данные о файле отсутствуют, создадим новый
if (filePath == "failed" || filePath == "") {
SerialPrint("E", F("LogingDaily"), "'" + id + "' file path not found, start create new file");
createNewFileWithData(logData);
return;
}
//считаем количество строк и определяем размер файла
// считаем количество строк и определяем размер файла
size_t size = 0;
int lines = countJsonObj(filePath, size);
SerialPrint("i", F("LogingDaily"), "'" + id + "' " + "lines = " + String(lines) + ", size = " + String(size));
//если количество строк до заданной величины и дата не менялась
// если количество строк до заданной величины и дата не менялась
if (lines <= points && !hasDayChanged()) {
//просто добавим в существующий файл новые данные
// просто добавим в существующий файл новые данные
addNewDataToExistingFile(filePath, logData);
//если больше или поменялась дата то создадим следующий файл
// если больше или поменялась дата то создадим следующий файл
} else {
createNewFileWithData(logData);
}
@@ -106,20 +121,20 @@ class LogingDaily : public IoTItem {
void createNewFileWithData(String &logData) {
logData = logData + ",";
String path = "/lgd/" + id + "/" + id + ".txt"; //создадим путь вида /lgd/id/id.txt
//создадим пустой файл
if (writeEmptyFile(path) != "sucсess") {
String path = "/lgd/" + id + "/" + id + ".txt"; // создадим путь вида /lgd/id/id.txt
// создадим пустой файл
if (writeEmptyFile(path) != "success") {
SerialPrint("E", F("LogingDaily"), "'" + id + "' file writing error, return");
return;
}
//запишем в него данные
if (addFile(path, logData) != "sucсess") {
// запишем в него данные
if (addFile(path, logData) != "success") {
SerialPrint("E", F("LogingDaily"), "'" + id + "' data writing error, return");
return;
}
//запишем путь к нему в базу данных
if (saveDataDB(id, path) != "sucсess") {
// запишем путь к нему в базу данных
if (saveDataDB(id, path) != "success") {
SerialPrint("E", F("LogingDaily"), "'" + id + "' db file writing error, return");
return;
}
@@ -128,7 +143,7 @@ class LogingDaily : public IoTItem {
void addNewDataToExistingFile(String &path, String &logData) {
logData = logData + ",";
if (addFile(path, logData) != "sucсess") {
if (addFile(path, logData) != "success") {
SerialPrint("i", F("LogingDaily"), "'" + id + "' file writing error, return");
return;
};
@@ -138,7 +153,7 @@ class LogingDaily : public IoTItem {
bool hasDayChanged() {
bool changed = false;
String currentDate = getTodayDateDotFormated();
if (!firstTimeDate) {
if (!firstTimeInit) {
if (prevDate != currentDate) {
changed = true;
SerialPrint("i", F("NTP"), "Change day event");
@@ -149,7 +164,7 @@ class LogingDaily : public IoTItem {
#endif
}
}
firstTimeDate = false;
firstTimeInit = false;
prevDate = currentDate;
return changed;
}
@@ -221,10 +236,20 @@ class LogingDaily : public IoTItem {
}
}
//просто максимальное количество точек
// просто максимальное количество точек
int calculateMaxCount() {
return 86400;
}
void onModuleOrder(String &key, String &value) {
if (key == "defvalue") {
saveDataDB(id + "-v", value);
SerialPrint("i", F("LogingDaily"), "User set default value: " + value);
} else if (key == "reset") {
clearHistory();
SerialPrint("i", F("LogingDaily"), F("User clean chart history"));
}
}
};
void *getAPI_LogingDaily(String subtype, String param) {

View File

@@ -14,7 +14,10 @@
"int": 1,
"logid": "t",
"points": 365,
"column": 0
"telegram": 0,
"test": 0,
"btn-defvalue": 0,
"btn-reset": "nil"
}
],
"about": {
@@ -23,7 +26,7 @@
"authorGit": "https://github.com/DmitryBorisenko33",
"specialThanks": "@itsid1 @Valiuhaaa Serg",
"moduleName": "LogingDaily",
"moduleVersion": "3.0",
"moduleVersion": "3.1",
"usedRam": {
"esp32_4mb": 15,
"esp8266_4mb": 15
@@ -34,7 +37,8 @@
"int": "Интервал логирования в мнутах, частота проверки смены суток в минутах. Не рекомендуется менять",
"logid": "ID накопительной величины которую будем логировать",
"points": "Максимальное количество точек",
"column": "Режим тестирования - график будет обновляться не раз в сутки, а кадый заданный в int интервал. Суточные столбики - 0, Минутные столбики - 1"
"telegram": рафик будет отправлять в телеграм репорт с расходами каждый день",
"test": "Параметр необходим для разработчиков. Режим тестирования. График будет обновляться не раз в сутки, а кадый заданный в int интервал."
}
},
"defActive": true,