Jump to content
iT4iT.CLUB

Recommended Posts

Доброе время суток.

2 часа назад, post125 сказал:

Подскажите, пожалуйста, куда лучше добавлять описания переменных и инициализацию wire в основной файл или в sensors.h? И надо ли  еще добавлять библтотеку wire.h  или достаточно, что она загружается в tools.h?

Как Вы уже правильно заметили, библиотека wire.h уже объявлена в файле tools.h, объявлять её еще раз нет необходимости, но даже если и объявить его повторно, то это не даст совершенно никакого результата из-за определенных директив препроцессора, о которых можно почитать, например тут https://docs.microsoft.com/ru-ru/cpp/preprocessor/preprocessor-directives

Что касаемо добавления собственных переменных, функций, классов и т.п, то тут нет никакого ограничения, это можно делать где угодно, главное, чтобы эти данные были в области видимости того кода где они будут востребованы. Я могу только направить, порекомендовав использовать уже имеющиеся файлы по их назначению. Допустим взять файл config.h, он содержит описание класса, предоставляющего интерфейс работы с файлами конфигурации, файл логически завершен (в той или иной степени) и любая другая информация, не имеющая прямого отношения к данному классу, там будет лишней. К таким файлам можно отнести следующие:

  1. config.h
  2. cron.h
  3. sensors.h
  4. webserver.h
  5. wifi.h

Вносить изменения в эти файлы не рекомендуется, но не запрещается если Вы хотите доработать функционал, предоставляемый ими.

Другие файлы более открыты для редактирования, и даже нуждаются в нем т.к проект дорабатывается каждым под собственные нужды. Я бы посоветовал вносить в них правки, соответствующие их логическому предназначению.

  1. gpio.h - если требуется описать управление какой-либо нагрузкой через порты микроконтроллера в том числе и через различные платы расширения.
  2. services.h - если требуется описать взаимодействие контроллера с внешними серверами или устройствами, например, через TCP/IP.
  3. tools.h - если требуется где-то описать вспомогательные утилиты которые не заслуживают вынесения их в отдельный файл проекта.

Теперь, что касаемо пользовательских файлов

  1. users_auto.h
  2. users_bme280_x2.h
  3. users_ds18.h - нет в исходниках, но встречался в этой теме
  4. users_wspeed.h - нет в исходниках, но встречался в этой теме
  5. ...

То это файлы с примерами конфигурации сенсоров для web интерфейса. Конечно можно пользоваться и ими, но только каким-то одним за раз. Я же рекомендую закомсентировать их в основном файле и создать свой собственный и описать в нем все необходимые сенсоры, подключить все необходимые библиотеки для этих сенсоров и т.п. А имеющиеся файлы используйте как подсказки для реализации задуманного.

Ну и остается основной файл, он по сути, просто собирает все в кучу, но Вы можете вносить в него любые правки, даже разместить там все свои модификации, главное, чтобы Вам потом было удобно во всем этом разбираться.

Надеюсь это поможет Вам определиться с выбором файлов для модификации, но, если есть сомнения, просто создайте собственный файл, возможно даже не один, и опишите все там, так Вы точно не запутаетесь.

2 часа назад, post125 сказал:

Если у меня данные с ProMini передаются на ESP массивом, может проще из памяти ESP брать весь массив, чем считывать отдельно каждую ячейку по i2c?

Возможно Вы имели в виду считывание из памяти ProMini, поправьте если я не прав.

Я не знаю, как Вы организовали модель обмена данными между двумя контроллерами по i2c, имею только общее представление о проделанной Вами работе. Но посоветую обратиться к проверенному временем механизму, реализованному практически во всех популярных библиотеках, отвечающих за связь с датчиками на шине i2c.

Общая суть очень проста:

  • Есть набор команд, которые можно отправить своему Slave, они заранее оговорены, как и ответы на них.
  • Команда может запрашивать данные как по определенному параметру, так и по группе параметров, например, температура или температура и влажность.
  • Мастер всегда знает какой объем данных должен прийти в ответ на ту или иную команду, например, один Byte или массив из 8-и Byte, хотя никто не мешает принимать данные до тех пор, пока: не будет получен специальный Byte конца телеграммы, не будет превышен выделенный объем памяти под ответ, не будет пойман таймаут по тишине в эфире или таймаут из-за медленного ответа Slave.
  • После получения ответа производим разбор данных и выделение полезной часть и тут мы возвращаемся к первому и второму пункту этого списка.
  • Аналогичным образом можно отправлять конфигурационные команды, например, для управления нагрузкой на портах Slave.

Просто выберите удобный и быстрый для Вас способ обмена данными.

 

  • Like 1

Share this post


Link to post
Share on other sites
10 часов назад, Kitsum сказал:

А имеющиеся файлы используйте как подсказки для реализации задуманного

Благодарю за ответ! Теперь понятно, что не надо трогать. Я еще сам не делал скетчи, состоящие из нескольких файлов. По I2C из ProMini я научился передавать массив из 8 floatов в ESP, разбивая и собирая их побайтно на основе Ваших подсказок. Более крупные массивы пытаться передавать, наверное, не буду, мне и этого достаточно будет. 

на ProMini это выглядит так (Serial.print удалил, чтобы не загромождало):

Скрытый текст

#include "Wire.h"
#include "SPI.h"                      // библиотека для протокола SPI
#include "nRF24L01.h"                 // библиотека для nRF24L01+
#include "RF24.h"                     // библиотека для радио модуля
const uint64_t pipe = 0xF0F1F2F3F4LL; // индитификатор передачи, "труба"
RF24 radio(9, 10);                    // порты CE, CSN (MEGA 49,53;  ProMini 9,10 )
byte datab[32];
float dataf[8];
byte b[4];

void setup() {
Wire.begin(1); //подключиться к шине i2c с адресом #1
Wire.onRequest(requestEvent); // register event
  radio.begin();                      // включаем радио модуль
  radio.setAutoAck(0);
  delay(100);
  radio.setChannel(100);                // устанавливаем канал (0-127)  dec100 = hex64
  radio.setDataRate(RF24_250KBPS);      // скорость передачи данных : RF24_250KBPS, RF24_1MBPS или RF24_2MBPS чем меньше скорость, тем выше чувствительность приемника
  radio.setPALevel(RF24_PA_HIGH);     //мощность передатчика, RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBM,RF24_PA_MAX= 0dBm
  radio.openReadingPipe(1, pipe);     // открываем первую трубу
  radio.startListening();             // начинаем слушать трубу
  delay(1000);
}

void requestEvent() {
Wire.write(datab, sizeof(datab));
}

void loop() {
    if (radio.available())              // проверяем буфер обмена  NRF24
    {
      radio.read(&dataf, sizeof(dataf));
    } // читаем данные, указываем сколько байт читать

byte x=0;
byte y;
for (y=0; y<8; y++)
{
 *(float*)b = dataf[y];
datab[x]=b[0];
x=x+1;
datab[x]=b[1];
x=x+1;
datab[x]=b[2];
x=x+1;
datab[x]=b[3];
x++;    
}
}

 

на ESP это выглядит так (Serial.print то же удалил):

Скрытый текст

// драйвера ESP8266/32 версии 2.4.2

#include <Wire.h>

#define SDA_PIN D2
#define SCL_PIN D1
const int16_t I2C_MASTER = 0x42;
byte data1[32];
byte b1[4];
float f1[8];

byte x;
void setup() {
  Wire.begin(SDA_PIN, SCL_PIN);        // join i2c bus (address optional for master)
    delay(500);
}

void loop() {

//-------------------- чтение с первого slave --------------------
    Wire.requestFrom(1, 32);    //     Wire.requestFrom(1, 32);  запрос со slave адреса #1     32-х байт
    while (Wire.available()) { // slave may send less than requested
      
for (x=0;x<32; x++)
{
data1[x] = Wire.read();
}

byte x=0;
for (byte y=0; y<8; y++ )
{
 b1[0] =  data1[x];
 x++;
 b1[1] =  data1[x];
  x++;
 b1[2] =  data1[x];
  x++;
 b1[3] =  data1[x];
  x++;
 f1[y] = *(float*)b1;  
}
  delay(500);
    }
}

 

Итого получилось, что уличная ProMini получает данные с датчиков, через NRF24 передает массив из 8 чисел на домашнюю ProMini , а та, как slave, отдаёт этот массив на ESP по I2C. Попробовал на одну master ESP повесить одновременно три slave ProMini (в примерах, соответственно, оставил работу только с одним slave ). Вся эта связка работает без сбоев. Осталось подружить с Вашим проектом.

Кстати, уличные датчики на ProMini (с NRF24 и SHT31) получаются весьма непрожорливыми - в режиме сна потребляют от двух батареек АА около 5мкА. И работают они стабильно до напряжения примерно в 2,1В. Так что батареек должно на долго хватить, если передвать данные раз в неколько минут.

Еще раз благодарю за помощь!

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

Спасибо большое автору. Подскажите пожалуйста как сделать график не по 10 минут, а по часу и скажем не на сутки, а на неделю.

И еще - небольшая интеграция в мою систему. Начало истории тут http://arduino.ru/forum/proekty/vatchdog-220v-klient-server-win

Это детектор 220В. С клиентской частью для отключения ПК после отсутствия электричества определенное время (для тех у кого есть проблема с получением данных из ИБП).

Сейчас по случаю решил переделать все это на ESP.

Добавлен класс watchdog220

В нем описана функция "инициализации", запроса состояния линии и функция отправки в Broadcast.

Из изменений в авторском коде:

В ESP8266_WS_V2.0_iT4IT.CLUB-220watchdog.ino

объявляем заголовочный файл:

#include "watchdog220.h"  // 220WatchDog

В функции setup() инициализируем наш пин (пин определяется в заголовочном файле. не стал выносить лишнее в авторский код) и тут же добавляем в Cron задание на отправку сообщений раз в секунду:

/* Инициализация Wathcdog'а*/
  watchdog220.startwatchdog();
/* Добавление в планировщик заданий по проверке 220В на линии и отправке данных на внешнии ресурсы */
  cron.add(cron::time_1s, [&](){ watchdog220.send2broarcast();  });       // Отправка данных в Broarcast

По идее в кроне была и проверка линии, но... как-то не срасталось. Вынес функцию просто в loop():

watchdog220.acCheck();

 

Из настроек:

#define WATCHDOGPIN D5 - пин на котором висит датчик
#define WAITTIME 10000 - время через которое система меняет статус на "отсутствие 220В" (дело в том что частота у нас 50Гц и когда попадешь на полупериод, когда не попадешь...)

IPAddress broadcastIp(192, 168, 0, 255); - IP широковещательный (последний адрес в подсети (для привычных 255.255.255.0 - это 255))

int udpPort = 4545;  - порт как ни странно )

 

Лично я схему почерпнул от сюда: http://arduino.ru/forum/apparatnye-voprosy/nuzhno-otslezhivat-nalichie-220-volt-na-linii#comment-237805

Из дополнений к ней (в комменте указано) - цифровой пин на котором будем ловить сигнал надо подтянуть к +3В через резистор (4,7кОм)

Тут программа с исходниками: https://www.dropbox.com/s/4741p3jdc3isqfd/win.7z?dl=0

Для данной реализации нужна только клиентская часть. 

Еще раз автору данной метеостанции большое спасибо!

ESP8266_WS_V2.0_iT4IT.CLUB-220watchdog.7z

Edited by Василий Залукаев

Share this post


Link to post
Share on other sites

Доброе время суток.

23 часа назад, Василий Залукаев сказал:

Подскажите пожалуйста как сделать график не по 10 минут, а по часу и скажем не на сутки, а на неделю.

Схожий вопрос уже был в теме, посмотрите этот комментарий, его вторая половина посвящена графику https://it4it.club/topic/55-meteostanciya-na-esp8266-ot-it4itclub/page/19/?tab=comments#comment-999

На всякий случай опишу ключевые места связанные с графиком.

За обновления лога с сенсоров отвечает задача в планировщике, по умолчанию она вызывается каждые 10 минут, найти её можно в основном файле проекта.

cron.add(cron::time_10m, [&](){ sensors.logUpdate();  }, "httpSensorsLog");

В файле sensors.h, в классе sensors имеется свойство, отвечающее за размерность массива в котором хранятся данные с сенсоров. По умолчанию стоит значение 144, что при вызове задачи обновления каждые 10 минут дает нам данные за полные сутки.

class sensors {    
  public:
	/* ... лишнее вырезано .... */
  private:
	/* ... лишнее вырезано .... */
    byte logSize = 144;
} sensors;

Изменяя эти значения можно получить нужный временной диапазон начала и конца графика с удобным шагом между точками на графике.

Теперь нас интересует файл index.htm в каталоге data, по умолчанию он сжат в .gz с параметром ultra. Распаковываем и вносим следующие правки, по завершению редактирования сжимаем его обратно в .gz.

Нас интересуют две функции в которых происходит формирование графика, найти их можно по формуле используемой в расчете позиции первого элемента графика. Формирование графика происходит с лева на право, то есть от старшей временной позиции к младшей. Также в этих функция имеется упоминание об интервале между точками.

Для общего графика

var pointStart = new Date().getTime() - obj.timeAdjustment - 143 * 10 * 60 * 1000; // Начальная точка сутки назад
var pointInterval = 600 * 1000; // Интервал между точками 10 минут

Для графика по конкретному сенсору

pointStart: new Date().getTime() - obj.timeAdjustment - 143 * 10 * 60 * 1000,
pointInterval: 600 * 1000

Внесите изменения относительно правок в коде формирования лога на микроконтроллере.

На этом все правки закончены, но я обязан напомнить, что массив с данными лога хранится в оперативной памяти, а она, как и все в этом мире, имеет свой конец. Также это означает, что при потере питания на контроллере, будут потеряны и данные. Сделано это для защиты от износа spi flash где можно эти данные сохранять. Также отмечу, что контроллер не хранит временные позиции снятых показаний, сделано это для экономии оперативной памяти. При расчете конечной точки временной шкалы графика, используется единственная временная отметка с указанием времени в миллисекундах, прошедших с последнего обновления данных. Относительно этой отметки и времени, установленном на устройстве, с которого происходит просмотр графика, производится формирование всей шкалы с данными.

05.04.2019 в 12:19, Василий Залукаев сказал:

И еще - небольшая интеграция в мою систему.

Рассматривался ли вариант со снятием показаний через RS232 ИБП и дальнейшая передача показаний, например, через SNMP по запросу от внешнего хоста? Можно таким образом подвязать различные системы мониторинга, например, Zabbix.

  • Like 1

Share this post


Link to post
Share on other sites

Добрый день!

Что-то не получается считать массив  в user файле, если считывать данные со slave в loope, то их получается использовать и в вэб-интерфейсе они отображаются. В loop, наверное,  не правильно вставлять считывание со slave , а то мастер будет постоянно долбать их. А счтитываие в user не хочет компилироваться, пишет " 'getSensorData1' was not declared in this scope". Я что-то делаю неправильно. Взгляните, пожалуйста.

Скрытый текст

#define USERS_H

#define ON  true
#define OFF false
const int16_t I2C_MASTER = 0x42;
byte data1[32];
byte data2[32];

byte b1[4];
byte b2[4];

float f1[8]={1,1,1,1,1,1,1,1};
float f2[8]={2,2,2,2,2,2,2,2};

byte x;

/* Параметры индикаторов web интерфейса для плагина Knob
                       Мин  Макс   Шаг    Заголовок          Ед. измер.
|---------------------|----|------|------|------------------|---------| */
knob_t *T = new knob_t( -40,   1025,  ".1", "Температура",     "°C");
knob_t *P = new knob_t(-500,  9000, ".01", "Давление",        "mm");
knob_t *H = new knob_t(   0,   100, ".01", "Влажность",       "%");
knob_t *L = new knob_t(   0, 65000,   "1", "Освещенность",    "lx");
// knob_t *C = new knob_t(   0,  8192,   "1", "eCO<sub>2</sub>", "ppm");
knob_t *F1_0 = new knob_t(0,  4, ".01", "батарея1", "V");
knob_t *F2_0 = new knob_t(0,  4, ".01", "батарея2", "V");

/*****************************************************************************************************************************
 * Ниже описан порядок инициализации сенсоров в зависимости от выбранной библиотеки, а также пример инициализации датчиков.  *
 *****************************************************************************************************************************/
  #include <BH1750.h>
  BH1750 BH1750;

  #include <BME280I2C.h>
  BME280I2C BME;
  
//  #include <SI7021.h>
//  SI7021 SI7021;
 
void sensors_config() {
  Wire.begin(4, 5);

sensors.add(L, device::out, 0x23, "out_light", [&](){ BH1750.begin(); }, [&](){ return BH1750.readLightLevel(); }, true);
BME.begin();
sensors.add(P, device::out, 0x76, "out_pressure",     [&](){ return BME.pres(BME280::PresUnit_torr); }, true);
sensors.add(H, device::out, 0x76, "out_humidity",      [&](){return BME.hum(); }, true);
sensors.add(T, device::out, 0x76, "out_temperature",  [&](){ return BME.temp(BME280::TempUnit_Celsius); }, true);
sensors.add(F1_0, device::out, 0x01, "battery1",  [&](){ return getSensorData1(); }, true);
sensors.add(F2_0, device::out, 0x02, "battery2",  [&](){ return f2[0]; }, true);


  /* пример еще нескольких программных сенсоров */
 
  sensors.add(new knob_t(-100, 0, "1", "RSSI", "dbm"), device::in, "rssi",[&](){ 
    return wifi.isConnected() ? WiFi.RSSI() : 0; 
  });
  sensors.add(new knob_t(0, 5, ".01", "Питание", "V"), device::in, "vcc", [&](){ 
    return ESP.getVcc() * 0.001; 
  });
  sensors.add(new knob_t(0, 81920, "1", "RAM", "Byte"), device::in, "ram", [&](){
    return 81920 - ESP.getFreeHeap();
  });

}

//-------------------- чтение с первого slave --------------------
void getSensorData1() {
//float value=0;
float f1[8]={1,1,1,1,1,1,1,1};

//  Wire.begin(4, 5);
    Wire.requestFrom(1, 32);    //     Wire.requestFrom(1, 32);  запрос со slave адреса #1     32-х байт 
    while (Wire.available()) { 
for (x=0;x<32; x++)
{
data1[x] = Wire.read();
}

byte x=0; 
for (byte y=0; y<8; y++ )
{
 b1[0] =  data1[x];
 x++;
 b1[1] =  data1[x];
  x++;
 b1[2] =  data1[x];
  x++;
 b1[3] =  data1[x];
  x++;
 f1[y] = *(float*)b1;  
}
  delay(100);
    }
return  f1[];
}
//-------------------------------------------------------

 

 

Share this post


Link to post
Share on other sites
23.04.2017 в 17:02, EndWar сказал:

SI7021

SHT31 - самые точные датчики из из тех, что я тестировал (ВМЕ280, HDC1080, SI7021, DHT, DS18, AM2320) в диапазоне от -25 до +70 гр.С. Не счтитая SHT35 (но он дороже всех этих) и Si7051(измеряет только температуру)

Share this post


Link to post
Share on other sites
06.04.2019 в 12:39, Kitsum сказал:

 

Рассматривался ли вариант со снятием показаний через RS232 ИБП и дальнейшая передача показаний, например, через SNMP по запросу от внешнего хоста? Можно таким образом подвязать различные системы мониторинга, например, Zabbix.

Рассматривался. Но тут возникла проблема на которую не реагирует даже производитель. Есть ИБП eaton P5 в количестве несколько штук. Так вот еще при USB подключении я словил неприятность - часть ИБП отваливали интерфейсы. Была возможность взять плату расширения (2ethernet) и с ней абсолютна такая же история. Т.е. сам ИБП прекрасно работает, проблем нет, но вот его интерфейс... при чем не все, а часть.

По сему сейчас все просто - выключили свет - ждем 5 минут - выключаем все. ИБП умеют при появлении питания дергать POWER на выходах, все железо настроено на Power on, и все включается. В старом здании было очень актуально. В новом всего 2 раза за год выключили питание.

За остальное спасибо. Поиском правда пробежался, но... видимо плохо искал )

Share this post


Link to post
Share on other sites

@post125 в данном случае функция getSensorData1 должна быть объявлена до функции sensors_config, но у Вас есть другие проблемы в коде. Попробуйте такой вариант, не могу гарантировать его работоспособность, но общее понимание процесса он должен дать.

#ifndef USERS_H
#define USERS_H

float slaveF1[8];
knob_t *F1_0 = new knob_t(0, 4, ".01", "батарея1", "V");

void getFullDataF1() {
  byte i, y;
  byte b[4];
  Wire.requestFrom(0x01, 32);  
  while (Wire.available()) {
    b[i++] = Wire.read();
    if (i >= 3) {
      i = 0;
      slaveF1[y++] = *(float*)b;
      if (y >= 7) return;
    }
  }
}

float getPowerF1() {
  return slaveF1[0];
}

void sensors_config() {
  Wire.begin(4, 5);
  cron.add(cron::time_5s, getFullDataF1, true);
  sensors.add(F1_0, device::out, 0x01, "battery1", getPowerF1, true);
}

#endif

Т.к Вы выбрали механизм сбора всех данных за раз, то производить эту процедуру каждый раз когда требуются данные только по напряжению аккумулятора, нет никакого смысла. Считывайте данные отдельной задачей, а в коде сенсора просто забирайте нужный элемент массива из памяти.

Также старайтесь избегать глобальных переменных, различные промежуточные операции можно делать прямо в ваших функциях и методах. Остальные ошибки по невнимательности или спешке, думаю нет смысла на них указывать.

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
45 минут назад, Kitsum сказал:

Остальные ошибки по невнимательности или спешке, думаю нет смысла на них указывать.

Благодарю за ответ! На ошибки крайне желательно указывать, если не сложно. Я не специалист в программировании, посему принимаю всё с глубокой благодарностью.

Share this post


Link to post
Share on other sites

так, почему то, совсем не хочет ничего читать

  byte i, y;
  byte b[4];
  Wire.requestFrom(0x01, 32);  
  while (Wire.available()) {
    b[i++] = Wire.read();
    if (i >= 3) {
      i = 0;
      slaveF1[y++] = *(float*)b;
      if (y >= 7) return;
    }
  }

остановлюсь на своём варианте, упростив согласно вашим рекомендациям

Wire.requestFrom(0x01, 32);
while (Wire.available()) { 
     
for (x=0;x<32; x++)
{
data[x] = Wire.read();
}
byte x=0, z=0;
for (byte y=0; y<8; y++ ){
  
for (byte z=0; z<4; z++&x++ ){
  b[z] =  data[x];
}
 F1[y] = *(float*)b;
}

 

Share this post


Link to post
Share on other sites
08.04.2019 в 14:14, Kitsum сказал:

cron.add(cron::time_5s, getFullDataF1, true);
sensors.add(F1_0, device::out, 0x01, "battery1", getPowerF1, true);

подскажите, пожалуйста, чтобы собирать данные с датчиков 1 раз в 3 минуты, надо написать "cron::time_3m"? :

void sensors_config() {
  Wire.begin(4, 5);
  cron.add(cron::time_3m, getFullDataF1, true);
  sensors.add(F1_0, device::out, 0x01, "battery1", getPowerF1, true);
}

и добавить в файл chron.h ? :

time_3m  = 10800,

или как-то иначе?

Share this post


Link to post
Share on other sites
08.04.2019 в 21:40, post125 сказал:

подскажите, пожалуйста, чтобы собирать данные с датчиков 1 раз в 3 минуты, надо написать "cron::time_3m"? :


void sensors_config() {
  Wire.begin(4, 5);
  cron.add(cron::time_3m, getFullDataF1, true);
  sensors.add(F1_0, device::out, 0x01, "battery1", getPowerF1, true);
}

и добавить в файл chron.h ? :


time_3m  = 10800,

или как-то иначе?

Именно так. 

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
07.11.2018 в 18:45, Dmitry Moshalkov сказал:

Как в Mac OS поменять тип - сходу не нашел. Поправил в index.htm:

Добрый день!

То же столкнулся с проблемой обновления прошивки на Mac OS. Изменил строку в index.htm на вашу

if(file.type !== "application/octet-stream" && file.type !== "application/macbinary") {

результата нет. Через Win7 обновление работает, но это неудобно, т.к. надо запускать Parallels. Можете подсказать, что еще надо подправить?

Спасибо, проблема решена: надо было внести изменения не index.htm, а в index.htm,gz

  • Like 1

Share this post


Link to post
Share on other sites
08.10.2018 в 12:04, Kitsum сказал:

Я не вижу причин не позволяющих реализовать то, что Вы задумали. Конечно есть нюансы, но они будут всегда.

С вашей помощью заработало! Ура! Маленький вопрос - можно ли отображать значение напряжения до 3-го знака после запятой?  изменение .01 на .001 результата не даёт, хотя данные со slave имеют и третью цифру после запятой

knob_t *F2_0 = new knob_t(0, 125, ".001", "батт_улица", "В");

meteo.jpg

Share this post


Link to post
Share on other sites
21 час назад, post125 сказал:

Маленький вопрос - можно ли отображать значение напряжения до 3-го знака после запятой?  изменение .01 на .001 результата не даёт, хотя данные со slave имеют и третью цифру после запятой

Скорее всего Вы достигли придела в шаге шкалы для библиотеки Knob. Возможно Вам подойдет иной вариант отображения состояния батареи, например, в процентах отображающих полезную емкость аккумулятора, только не от 0 до maxV, а от минимально напряжения питания контроллера до maxV. Например, для ESP8266 эти границы будут от 2.2V до 3.6V, что дает нам (3.6V-2.2V)/100 = 0.014V на 1% шкалы сенсора. В таком случае, когда мы видим, что осталось 5% полезной емкости аккумулятора, приходит точное понимание, что аккумулятор нужно заменить.

Возможно Вы найдете более информативный способ визуализировать изменение тысячных долей. На всякий случай скину ссылки на сам плагин Knob:

 

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
3 часа назад, Kitsum сказал:

На всякий случай скину ссылки на сам плагин Knob

Благодарю за ответ, посмотрю, но думаю, это на самом деле совсем не критично. Надо двигаться дальше.

Вот на народном мониторе проявились проблемка - сейчас через ProMini c NRF24 принимаются три параметра температура, влажность и напряжение батареи; В графиках батареи и влажности есть пропуски данных (в виде нулевых значений), причём в разное время, а в графике температуры таких пропусков нет. Странно это, ведь данные с ProMini считываются сразу всем массивом в память ESP, а потом из памяти раздаются. Может где-то ESPка не успевает их считать. Попробую снизить скорость обмена по i2c, если позволит библиотека. Хотя думаю, что проблема где-то в другом месте. Первым в массиве идёт батарея, тогда в других данных должна была бы возникнуть подобная ошибка в такое же время, как в батарее, но этого не наблюдается.

По датчикам ESP на шине i2c пропусков нет.

На локальных графиках пропусков то же нет.

Без названия 6.jpg

Без названия 7.jpg

Без названия 5.jpg

Edited by post125
уточнение

Share this post


Link to post
Share on other sites

Добрый день!

Как отключить медианный фильтр и фильтр Кальмана? Толи они, толи еще что-то не дает строить график температуры от 0 до 1 градС. На диаграмме температура отражается корректно, на графике стабильно "0".

Без имени-1.jpg

Без имени-3.jpg

Без имени-2.jpg

Share this post


Link to post
Share on other sites
08.10.2018 в 12:04, Kitsum сказал:

Конечно есть нюансы, но они будут всегда.

Добрый день! Подскажите, пожалуйста, для чего в Data два файла index - index.htm и index.htm.gz ? Как я понял , приоритет имеют сжатые файлы, но их неудобно редактировать. Можно ли удалить сжатый файл и пользоваться только index.htm? Благодарю за ответ.

Share this post


Link to post
Share on other sites
08.10.2018 в 12:04, Kitsum сказал:

Конечно есть нюансы, но они будут всегда

Добрый день! Сегодня ночью были удачные сочетания температури и влажности (иначе бы не заметил). Проанализировав графики ESP и народного монитора пришел к выводу, что ESP все данные от -1 до +1 округляет ровно к нулю. Подскажите, пожалуйста, где это отключить в программе?

Еще один вопрос№2, можно ли в графиках ESP смещать на графике оси У так, как примерно на народном монитере, чтобы было видно когда температура приближается к точке росы?

И еще один вопрос№3, в форуме не нашел, как можно изменить частоту передачи данных на narodmon? возможно, более редкая отправка данных решит проблему с эпизодичеккими отправками нулевой температуры на графике narodmon? не факт, но попробовать надо.

Благодарю за ответ

ESP 15-4-19.jpg

narodmon 15-4-19.jpg

Edited by post125
добавление вопроса

Share this post


Link to post
Share on other sites

Доброе время суток.

10.04.2019 в 16:47, post125 сказал:

В графиках батареи и влажности есть пропуски данных (в виде нулевых значений), причём в разное время, а в графике температуры таких пропусков нет.

Не совсем понятно, эти проблемы и на локальных графиках тоже или только на народном мониторинге? Если на локальных тоже провалы, значит вы в течении какого-то времени получаете такие данные т.к на наполнение медианного фильтра требуется время, а это не менее трех запросов данных (по умолчанию размер буфера фильтра равен пяти).

10.04.2019 в 16:47, post125 сказал:

Первым в массиве идёт батарея, тогда в других данных должна была бы возникнуть подобная ошибка в такое же время, как в батарее, но этого не наблюдается.

Тут не все так просто, гарантировать целостность данных нельзя т.к никаких проверок попросту нет. Наличие данных, похожих на настоящие, в одном элементе массива не дает гарантии, что в других элементах все также хорошо. Для повышения надежности используется механизм проверки контрольной суммы, алгоритм выбирается в зависимости от конкретной ситуации. Например, мы отправляем 1 байт полезной нагрузки, пусть это будет чисто 123 или ‭01111011‬ в двоичной системе счисления, следом за ним отправляем еще 1 байт который будет представлять из себя контрольную сумму. Содержимое второго байта зависит от алгоритма, который мы выбираем, пусть это будет битовая операция "И" (AND) и по завершению расчетов мы хотим видеть 0, что будет сигналом о корректности данных. Таким образом второй байт должен содержать такую последовательность бит, чтобы в ходе операции получить значение 0. В нашем примере, второй бит должен содержать число 132 или ‭10000100‬ в двоичной системе счисления. На принимающей стороне производим расчет:

01111011 & 
10000100 = 
00000000

Также доступны и другие битовые операции https://ru.wikipedia.org/wiki/Битовые_операции

Для каждой конкретной задачи требуется свой алгоритм, конечно не факт, что это будут именно битовые операции.

8 часов назад, post125 сказал:

Как отключить медианный фильтр и фильтр Кальмана? Толи они, толи еще что-то не дает строить график температуры от 0 до 1 градС. На диаграмме температура отражается корректно, на графике стабильно "0".

Используется только медианный фильтр. Чтобы отключить его, перейдите в файл sensors.h и найдите строку

medianFilter_t lastDimension;

Замените её на

float lastDimension;

Медианный фильтр использует float для хранения значений, на практике он нужен только чтобы сгладит пиковые выбросы, спровоцированные кратковременными внешними изменениями в среде в которой находятся сенсоры.

8 часов назад, post125 сказал:

Подскажите, пожалуйста, для чего в Data два файла index - index.htm и index.htm.gz ? Как я понял , приоритет имеют сжатые файлы, но их неудобно редактировать. Можно ли удалить сжатый файл и пользоваться только index.htm?

В последних исходниках проекта имеются только сжатые файлы, но поддерживаются оба варианта. Приоритет отдается сжатому файлу т.к его транспортировка требует меньше времени. Вы можете удалить архивную копию, но предварительно убедитесь, что на контроллере имеется его распакованный вариант, иначе могут быть небольшие трудности.

1 час назад, post125 сказал:

Проанализировав графики ESP и народного монитора пришел к выводу, что ESP все данные от -1 до +1 округляет ровно к нулю. Подскажите, пожалуйста, где это отключить в программе?

Явного округления в коде не предусматривалось, давайте искать. Для начала, стоит посмотреть на данные передаваемые от контроллера в web интерфейс. Сделать это можно пройдя по ссылке http://espws.local/api/sensors/log (espws.local стоит заменить на ip адрес если пытаетесь открыть ссылку с устройства не поддерживающего mDNS или имеющего проблемы при работе с зоной .local). Еще более наглядный вариант, это зайти на главную страницы web сервера микроконтроллера, открыть режим разработчика в браузере (раздел network), далее открыть график и поймать запрос на страницу /api/sensors/log. В окне ответа сервера ищем вкладку с предварительным просмотром, там будет разобранный json ответ с данными.

image.png

Просмотрите эти данные и попытайтесь определить, получаете ли Вы эти значения уже округленными или это происходит во время создания самого графика.

1 час назад, post125 сказал:

И еще один вопрос, можно ли в графиках ESP смещать на графике оси У так, как примерно на народном монитере, чтобы было видно когда температура приближается к точке росы?

На народном мониторинге используется тот же самый плагин для создания графиков, что и в проекте метеостанции. Вы можете изменять визуализацию как Вам больше нравится, но в приделах возможностей самого плагина. Вот ссылка на сайт разработчика https://www.highcharts.com/ они предоставляют очень наглядные демо и всю документацию для создания собственной визуализации данных, это могут быть не только графики.

Постараюсь в ближайшее время воссоздать Вашу проблему с округлением, но с разовыми пропажами данных все сложнее т.к это касается непосредственно Вашего кода.

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
11 минут назад, Kitsum сказал:

Явного округления в коде не предусматривалось, давайте искать.

Благодарю за ответы, буду смотреть

Share this post


Link to post
Share on other sites
1 час назад, Kitsum сказал:

Просмотрите эти данные и попытайтесь определить, получаете ли Вы эти значения уже округленными или это происходит во время создания самого графика.

в логе эти данные  нулевые (те которые в диапазоне от -1 до +1)

контроль околонулевых значений.pdf

Share this post


Link to post
Share on other sites
10 часов назад, Kitsum сказал:

Медианный фильтр использует float для хранения значений, на практике он нужен только чтобы сгладит пиковые выбросы, спровоцированные кратковременными внешними изменениями в среде в которой находятся сенсоры.

отключение медианного фильтра дало только более плавные графики (в моей конфигурации);

Взял актуальную прошивку, заменил только считывание с датчиков температуры и влажности на арифметические прогрессии от -1,9 и от +1,9 с шагом +0,1 и -0,1 соответственно. Показания от -1 до +1 округляет до нуля как с фильтром, так и без фильтра. На круглых диаграммах данные в этом диапазоне отображаются корректно.

с медианным фильтром.jpg

без медианного фильтра.jpg

Без имени-1.jpg

Share this post


Link to post
Share on other sites
20.06.2018 в 20:24, Kitsum сказал:

График масштабируется автоматически и после суток работы приделы значений (в данном случае давления) будут скорректированы.

Добрый день! Подскажите, пожалуйста, возможно ли масштабировать график давления сразу по получении данных, как  это происходит с другими графиками? Кроме как установить принудительно min и max пределы оси Y? Например,  присваивать минимальному и максимальному значениям первое показание с датчика , а потом последующии данные сравнивать и, при необходимости, заменять ими минимальное и максимальное значения? А то как-то давление совсем грустно выглядит.

Скрытый текст

990034505_6.thumb.jpg.e1bbf42760eab1defb1855337cf95e24.jpg

 

Edited by post125

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Similar Content

    • By Kitsum
      Хотите помочь проекту или спонсировать новый?
      Yandex.Money PayPal.me Тема проекта
      Arduino IDE + Project + Libraries + tools: https://yadi.sk/d/jseefFB50NMhAg
    • By Kitsum
      Просмотреть файл [esp8266] Библиотека CMD, реализует настройку микроконтроллера и управление вашей программой через терминал.
      Основная задача библиотеки, это прием пользовательских команд через UART интерфейс, их обработка и выполнение пользовательского кода, связанного с той или иной командой.
      Данная библиотека позволяет реализовать:
      Управление микроконтроллером Любую настройку, будь то WiFi, другие библиотеки или часть Вашей программы Вызывать Ваши задачи (функции) из терминала по команде и передавать им требуемые параметры Использовать контроллер в качестве шлюза между датчиками и программами на PC Внимание: любая команда, передаваемая в терминал обязана заканчиваться символом перевода строки "\n".
      Подключение библиотеки
      #include <cmd.h> Инициализация объекта, к которому мы будем обращаться для добавления команд. В качестве параметра объекту необходимо передать указатель на объект Serial или любой другой схожий по типу интерфейс.
      cmd command(&Serial); В функции Setup описываем какие команды требуется обрабатывать. Например, по команде "test" вызывать пользовательскую функцию с именем "myFunctionName". Имя пользовательской функции может быть абсолютно любым.
      void Setup() { Serial.begin(115200); command.add("test", myFunctionName); } Пользовательская функция будет вызываться каждый раз, когда по интерфейсу Serial поступит команда "test". Если команда будет передана с параметрами, то эти параметры будут переданы в качестве аргументов пользовательской функции.
      В функции loop должна находится команда вызова обработчика.
      void loop() { command.handleEvents(); } Пользовательская функция обязана соответствовать ряду требований:
      Не возвращать никакого результата (быть объявленной с типом void) Принимать в качестве первого аргумента переменную с типом byte в которой будет храниться число равное количеству переданных параметров Принимать в качестве второго параметра переменную с типом char** в которой будет храниться указатель на массив со всеми указателями (char*) на переданные параметры void myFunctionName(byte argc, char** argv) { /* ... */ } Функция всегда должна иметь такой вид, даже если не подразумевается, что ей будут передаваться какие-либо параметры.
      Чтобы перебрать все переданные параметры и вывести их в консоль, можно воспользоваться следующим примером
      void myFunctionName(byte argc, char** argv) { if (0 < argc) { for (uint8_t i = 0; i < argc; i++) { Serial.printf("%i. %s\n", i, argv[i]); } } } Пример вызова пользовательской функции без параметров и с ними
      # test No parameter was passed # test p1 p2 p3 p4 p5 0. p1 1. p2 2. p3 3. p4 4. p5 Помните, что параметры представлены в виде указателей и работать с ними нужно как с обычными переменными не получится т.к указатель содержит не значение переменной (переданный параметр), а указатель на ту область памяти микроконтроллера в которой это значение находится.
      Чтобы сравнить два значения, например, параметр под индексом 0 (идет первым в списке) с каким-либо значением в программе, воспользуйтесь функцией strcmp, которая возвращает целочисленное значение, указывающее на лексическое расхождение строк. Если строки равны, то возвращаемое значение равно 0.
      if (!strcmp(argv[0], "wifi")) { Serial.println(F("Первый аргумент WiFi")); } else { Serial.println(F("Первый аргумент НЕ WiFi!!!")); } Для копирования значения указателя в другую переменную с типом char можно воспользоваться функцией strcpy
      char myVar[20]; strcpy(myVar, argv[0]); if (myVar == "123456") { Serial.prinln(F("ok")); } Также можно обернуть указатель объектом String и получить весь функционал этого объекта, который будет содержать значение параметра
      String param1(argv[0]); // String param1 = argv[0]; Serial.printf("argv[0] length: %i\n", param1.length()); Serial.printf("argv[0] is integer?: %s\n", param1.toInt() ? "YES" : "NO"); if (param1 == "qwerty") { Serial.println(F("Hello QWERTY!")); } С библиотекой идут несколько примеров, в том числе и пример конфигурации WiFi в режиме STA.
      Автор Kitsum Добавлен 05.12.2018 Категория Библиотеки  
    • By Kitsum
      Просмотреть файл [esp8266] Библиотека smartBlink, реализует умное управление штатным светодиодом, что позволяет добавить индикацию состояния вашей программы или микроконтроллера.
      Основная задача библиотеки, это добавление индикации состояния Вашей программы или микроконтроллера. Отображение состояния производится посредством светодиода. Что самое важное, работа библиотеки через прерывание, это позволяет ей поддерживать индикацию даже в то время, когда выполняется длительный код основной программы. Например, Вы можете использовать её для отображения в каком режиме сейчас работает WiFi микроконтроллера, STA или AP и т.д. Или ход выполнения какой-либо операции, например, передача данных на внешний сервер.
      Подключение библиотеки
      #include <smartBlink.h> Чтобы инициализировать управление светодиодом необходимо создать объект, через который мы буем задавать режимы работы индикации.
      smartBlink::smartBlink(byte gpio, bool on = LOW); Объекту необходимо передать два параметра, первый это номер порта, на котором находится светодиод, а второй это уровень логического сигнала, который заставит светодиод работать. Сигнал может быть низким (LOW) или высоким (HIGH), это зависит от схемотехники подключения светодиода.
      Например, штатный светодиод модуля ESP12, использующий GPIO2 (порт 2) можно объявить следующим образом.
      #define led2_pin 2 #define led2_on_signal LOW smartBlink led2(led2_pin, led2_on_signal); Теперь можно в основной программе использовать метод устанавливающий какой режим индикации использовать.
      smartBlink::setMode(mode_t mode); Например, зададим режим светодиода led2 в котором светодиод будет давать одну короткую вспышку раз в секунду.
      led2.setMode(smartBlink::mode_flash1); Режимов работы может быть несколько.
      led2.setMode(smartBlink::mode_off); led2.setMode(smartBlink::mode_flash1); led2.setMode(smartBlink::mode_flash2); led2.setMode(smartBlink::mode_flash3); led2.setMode(smartBlink::mode_flash4); led2.setMode(smartBlink::mode_burn); led2.setMode(smartBlink::mode_inhalf); Чтобы вернуть предыдущий режим индикации для ранее объявленного светодиода led2 используйте следующий метод
      led2.previous(); Благодаря работе библиотеки через прерывания по таймеру, индикация будет работать даже в тех случаях, когда выполняется долгий код.
      С библиотекой идут несколько примеров.
      Автор Kitsum Добавлен 10.12.2018 Категория Библиотеки  
    • By Kitsum
      Основная задача библиотеки, это добавление индикации состояния Вашей программы или микроконтроллера. Отображение состояния производится посредством светодиода. Что самое важное, работа библиотеки через прерывание, это позволяет ей поддерживать индикацию даже в то время, когда выполняется длительный код основной программы. Например, Вы можете использовать её для отображения в каком режиме сейчас работает WiFi микроконтроллера, STA или AP и т.д. Или ход выполнения какой-либо операции, например, передача данных на внешний сервер.
      Подключение библиотеки
      #include <smartBlink.h> Чтобы инициализировать управление светодиодом необходимо создать объект, через который мы буем задавать режимы работы индикации.
      smartBlink::smartBlink(byte gpio, bool on = LOW); Объекту необходимо передать два параметра, первый это номер порта, на котором находится светодиод, а второй это уровень логического сигнала, который заставит светодиод работать. Сигнал может быть низким (LOW) или высоким (HIGH), это зависит от схемотехники подключения светодиода.
      Например, штатный светодиод модуля ESP12, использующий GPIO2 (порт 2) можно объявить следующим образом.
      #define led2_pin 2 #define led2_on_signal LOW smartBlink led2(led2_pin, led2_on_signal); Теперь можно в основной программе использовать метод устанавливающий какой режим индикации использовать.
      smartBlink::setMode(mode_t mode); Например, зададим режим светодиода led2 в котором светодиод будет давать одну короткую вспышку раз в секунду.
      led2.setMode(smartBlink::mode_flash1); Режимов работы может быть несколько.
      led2.setMode(smartBlink::mode_off); led2.setMode(smartBlink::mode_flash1); led2.setMode(smartBlink::mode_flash2); led2.setMode(smartBlink::mode_flash3); led2.setMode(smartBlink::mode_flash4); led2.setMode(smartBlink::mode_burn); led2.setMode(smartBlink::mode_inhalf); Чтобы вернуть предыдущий режим индикации для ранее объявленного светодиода led2 используйте следующий метод
      led2.previous(); Благодаря работе библиотеки через прерывания по таймеру, индикация будет работать даже в тех случаях, когда выполняется долгий код.
      С библиотекой идут несколько примеров.
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...