/*Программа измерения тока по WIFI 16 каналов
* Релиз 03 от 18/02/2023
* Сброс настроек по двойному ресету
*
*/
//Библиотеки и определения к ним
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
//Создаем клиента TCP
WiFiClient client;
#include <DoubleResetDetector.h>
#define DRD_TIMEOUT 1 // Количество секунд после сброса, в течение которых последующий сброс будет считаться двойным сбросом.
#define DRD_ADDRESS 0 // Адрес памяти RTC для использования DoubleResetDetector
DoubleResetDetector drd(DRD_TIMEOUT, DRD_ADDRESS); //инициализация детектора длинного сброса
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager библиотека первичной конфигурации подключения
//добавим параметры для заполнения при конфигурации
byte bIp[] = { 192, 168, 1, 101 }; //адрес сервера для подключения по умолчанию
int uiPort = 713; //порт сервера для подключения по умолчанию
char server[15] = "192.168.1.101";
char port[6] = "713";
char IDKey[8] = "DT16_1"; //идентификатор блока для сервера
WiFiManagerParameter custom_server("server", "server", server, 15); //перед цифрой server это переменная по умолчанию
WiFiManagerParameter custom_port("port", "port", port, 5); //перед цифрой port это переменная по умолчанию
WiFiManagerParameter custom_IDKey("IDKey", "IDKey", IDKey, 7); //идентификатор блока для сервера
#include <EEPROM.h>
#include "Wire.h"
//адреса устройств
int PCF8591_0=0x48; // I2C bus address для 7 бит (H91 >> 1)
int PCF8591_1=0x49; // I2C bus address
int PCF8591_2=0x4B; // I2C bus address
int PCF8591_3=0x4F; // I2C bus address
byte AV[4]; //массив для измеренного
byte AMIN[4]; //массив минимальных значений
byte AMAX[4]; //массив максимальных значений
byte VD[16]; //массив всех измеренных размахов
void setup()
{
WiFi.mode(WIFI_STA); // явно укажем режим запуска
Serial.begin(115200);
delay(10);
WiFiManager wifiManager; //создаем объект конфигурации
//настраиваем меню конфигурации
//уберем из меню то что не нужно
std::vector<const char *> wifiManager_menu = {"wifi", "exit"};
wifiManager.setShowInfoUpdate(false);
wifiManager.setShowInfoErase(false);
wifiManager.setMenu(wifiManager_menu);
//добавим параметры настройки
wifiManager.addParameter(&custom_server);
wifiManager.addParameter(&custom_port);
wifiManager.addParameter(&custom_IDKey);
//укажем обработчик события сохранения конфигурации событие сохранения конфигурации
// сохранять надо только то что добавили, имя сети и пароль сохранится сам
wifiManager.setSaveConfigCallback(saveConfigCallback);
wifiManager.setConfigPortalTimeout(60); //при рестарте открываем портал на минуту, если сеть не доступна
wifiManager.setClass("invert"); //темная тема
// wifiManager.setDebugOutput(false); //отключает вывод отладки
//проверим, был ли двойной сброс
if (drd.detectDoubleReset()) {
wifiManager.resetSettings(); //Был двойной сброс. Очистим конфигурацию
}
//зажигаем светодиод чтобы сообщить что в режиме станции
pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output
digitalWrite(LED_BUILTIN, LOW); //вкл
wifiManager.autoConnect();
digitalWrite(LED_BUILTIN, HIGH);
Serial.println("Connected! IP address: ");
Serial.println(WiFi.localIP());
//Читаем настройки из EEPROM
LoadSroperties ();
//установки шины I2C для опроса АЦП библиотеку поправлял, штатная может подвисать, сам видел
Wire.setClock(100000); //стандартная скорость
Wire.pins(4,5); // just to make sure
Wire.begin(4,5); // the SDA and SCL
}//end setuo
void loop(){
drd.loop(); //необходимо периодически вызывать, для распознавания двойного сброса
delay(3000);
//считываем 0 АЦП
GetVAalog(PCF8591_0);
//переносим в массив для передачи размах амплитуды
VD[0] = AMAX[0] - AMIN[0];
VD[1] = AMAX[1] - AMIN[1];
VD[2] = AMAX[2] - AMIN[2];
VD[3] = AMAX[3] - AMIN[3];
//считываем 1 АЦП
GetVAalog(PCF8591_1);
//переносим в массив для передачи размах амплитуды
VD[4] = AMAX[0] - AMIN[0];
VD[5] = AMAX[1] - AMIN[1];
VD[6] = AMAX[2] - AMIN[2];
VD[7] = AMAX[3] - AMIN[3];
//считываем 2 АЦП
GetVAalog(PCF8591_2);
//переносим в массив для передачи размах амплитуды
VD[8] = AMAX[0] - AMIN[0];
VD[9] = AMAX[1] - AMIN[1];
VD[10] = AMAX[2] - AMIN[2];
VD[11] = AMAX[3] - AMIN[3];
//считываем 3 АЦП
GetVAalog(PCF8591_3);
//переносим в массив для передачи размах амплитуды
VD[12] = AMAX[0] - AMIN[0];
VD[13] = AMAX[1] - AMIN[1];
VD[14] = AMAX[2] - AMIN[2];
VD[15] = AMAX[3] - AMIN[3];
Serial.println(" ");
Serial.print("Data ADC: ");
for(byte i = 0; i < 16; i++){ Serial.print(String(VD[i],DEC) + ".");}
Serial.println(" ");
//пробуем подключиться к серверу
if (!client.connect(bIp, uiPort)) {
Serial.println("Not connect server");
return;
}
//строка запрос
String url = "/update?key=";
url+= String(IDKey); //"DT16_1"; //apikey;
url+="&field0=";
url+=String(VD[0]);
url+="&field1=";
url+=String(VD[1]);
url+="&field2=";
url+=String(VD[2]);
url+="&field3=";
url+=String(VD[3]);
url+="&field4=";
url+=String(VD[4]);
url+="&field5=";
url+=String(VD[5]);
url+="&field6=";
url+=String(VD[6]);
url+="&field7=";
url+=String(VD[7]);
url+="&field8=";
url+=String(VD[8]);
url+="&field9=";
url+=String(VD[9]);
url+="&field10=";
url+=String(VD[10]);
url+="&field11=";
url+=String(VD[11]);
url+="&field12=";
url+=String(VD[12]);
url+="&field13=";
url+=String(VD[13]);
url+="&field14=";
url+=String(VD[14]);
url+="&field15=";
url+=String(VD[15]);
url+="&Err=";
url+=String(Wire.status());
url+="\r\n";
Serial.println(url);
// запрос на сервер
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + "\r\n" +
"Connection: close\r\n\r\n");
}//end loop
//------------------------Подпрограммы для работы с I2C--------------------------------------------------------------------------
void GetVAalog(int DIVACE) //подпрограмма получает напряжения по входам указанного АЦП
{
//задаем исходные нулевые значения, средняя точка измерителя на делителе 1/2
AMIN[0] = 128;
AMAX[0] = 128;
AMIN[1] = 128;
AMAX[1] = 128;
AMIN[2] = 128;
AMAX[2] = 128;
AMIN[3] = 128;
AMAX[3] = 128;
Wire.beginTransmission(DIVACE); // wake up PCF8591
Wire.write(0x44); // control byte: reads ADC0 then auto-increment гдето прочитал, что если авто инскримент, то обязательно включить выход аналоговый
Wire.write(0x00);
Wire.endTransmission(); // end tranmission
Wire.requestFrom(DIVACE, 1); // тут предыдущее измеренное, оно нам не надо. Особенности микросхемы
AV[0]=Wire.read();
for (int I = 0; I < 100; I++) { //делаем 100 измерений, ищем максимальное и и минимальное амплитудное значение, размах
Wire.requestFrom(DIVACE, 1); // принять 1 байт из устройства
AV[0] = Wire.read();
Wire.requestFrom(DIVACE, 1); // принять 1 байт из устройства
AV[1] = Wire.read();
Wire.requestFrom(DIVACE, 1); // принять 1 байт из устройства
AV[2] = Wire.read();
Wire.requestFrom(DIVACE, 1); // принять 1 байт из устройства
AV[3] = Wire.read();
//минимальные и максимальные значения
AMIN[0] = min(AV[0], AMIN[0]);
AMAX[0] = max(AV[0], AMAX[0]);
AMIN[1] = min(AV[1], AMIN[1]);
AMAX[1] = max(AV[1], AMAX[1]);
AMIN[2] = min(AV[2], AMIN[2]);
AMAX[2] = max(AV[2], AMAX[2]);
AMIN[3] = min(AV[3], AMIN[3]);
AMAX[3] = max(AV[3], AMAX[3]);
}
delay(10);
}//end GetVAalog
//-------------------------------------------------------------------------------------------------------------------------------------------
//------------------------Подпрограммы настройки конфигурации---------------------------------------------------------------------
void saveConfigCallback () {
//обработчик события сохранения конфигурации WiFiManager
//shouldSaveConfig = true; //событие устанавливает флаг необходимости сохранить параметры
Serial.println("saving config");
//читаем адрес сервера и порт, ключа из WiFiManager
Serial.println(custom_server.getValue());
Serial.println(custom_port.getValue());
Serial.println(custom_IDKey.getValue());
//преобразуем custom_server в массив байт, custom_port в int, пока все во временные
byte bT[4]; // IP
parseBytes(custom_server.getValue(), '.', bT, 4, 10); //IP адрес удаленного сервера
int uiP; // порт
String str = String(custom_port.getValue()); //установки порта в строку
uiP = str.toInt();
char IDK[8]; // массив для ключа
str = custom_IDKey.getValue();
str.toCharArray(IDK, 8);
byte bBUF [16]; //буфер для записи в eeprom
byte bSUM; //контрольная сумма
for(byte i = 0; i < 4; i++){ //IP адрес удаленного сервера
bBUF[i] = bT[i];
}
bBUF[4] = highByte(uiP); //старший байт номера порта удаленного сервера
bBUF[5] = lowByte(uiP); //младший байт адреса порта удаленного сервера
for(byte i = 0; i < 8; i++){ //
bBUF[i + 6] = IDK[i];
}
//считаем контрольную сумму
bSUM= 0;
for(byte i = 0; i < 14; i++){
bSUM += bBUF[i];
}
bBUF[14] = (bSUM ^ 0xe5);
//Сохраняет в EEPROM
EEPROM.begin(16); //4 + 2 + 8 байт = 14 + 1 контрольная сумма = 16
for(byte i = 0; i < 16; i++){
EEPROM.put(i, bBUF[i]);
}
EEPROM.commit();
EEPROM.end();
delay(100); //чтобы все записалось
}//end saveConfigCallback
void LoadSroperties (){
//подпрограмма читает и устанавливает настройки из EEPROM
byte bBUF [16]; //буфер для чтения eeprom
byte bSUM; //контрольная сумма
EEPROM.begin(16);
for(byte i = 0; i < 16; i++){ //читаем в буфер
bBUF[i] = EEPROM.read(i) ;
}
EEPROM.end();
//проверим контрольную сумму
bSUM = 0;
for(byte i = 0; i < 14; i++){ //читаем в буфер
bSUM += bBUF[i];
}
if ((bSUM ^ 0xe5) != bBUF[14] ) {
Serial.print ("CRC no correct");
return;
}
//все верно, разбираем
for(byte i = 0; i < 4; i++){ //IP адрес удаленного сервера
bIp[i] = bBUF[i];
}
uiPort = 256 * bBUF[4] + bBUF[5]; //номера порта удаленного сервера, два байта
for(byte i = 0; i < 8; i++){ //Id устройства
IDKey[i] = bBUF[i + 6];
}
}//end LoadSroperties
void parseBytes(const char* str, char sep, byte* bytes, int maxBytes, int base) {
//подпрограмма для выделения IP в байтовый массив
for (int i = 0; i < maxBytes; i++) {
bytes[i] = strtoul(str, NULL, base); // Convert byte
str = strchr(str, sep); // Find next separator
if (str == NULL || *str == '\0') {
break; // No more separators, exit
}
str++; // Point to next character after separator
}
}//end parseBytes
//-------------------------------------------------------------------------------------------------------------------------------- |