Перейти к публикации
iT4iT.CLUB

Kitsum

Пользователи
  • Публикации

    424
  • Зарегистрирован

  • Посещение

  • Дней в лидерах

    234

Сообщения, опубликованные пользователем Kitsum


  1. 03.05.2019 в 22:25, vlasov67 сказал:

    Добрый вечер. Хотел узнать почему не могу подключиться к роутеру пишет:

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

    Попробуйте следующее:

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

    И еще, очень важное замечание. Обязательно перейдите на WAP2-PSK шифрование. И не скидывайте в открытый доступ скриншоты с настройками доступа к Вашему маршрутизатору. В данном случае, Вы засветили свой ключ доступа, и его обязательно нужно менять.


  2. 03.05.2019 в 23:31, vlulu333 сказал:

    Время удержания реле при открытии я подправил, но что делать с режимом программирования и когда в ЕЕПРОМ нет ключей? В этом режиме дверь постоянно открыта.

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


  3. 19.04.2019 в 13:05, post125 сказал:

    Можно ли вообще отключать проверку шины?

    Да, удалите в основном файле строку

    cron.add(cron::time_1m,  [&](){ sensors.checkLine();  }, true);

    Всю инициализацию датчиков проведите самостоятельно без использования соответствующих функций при описании датчиков. Или замените указанную выше строку на разовый вызов метода checkLine

    sensors.checkLine();
    22.04.2019 в 20:44, post125 сказал:

    Снизил частоту иницилизации шины до 1раза в час,  на одной ESPке пропуски отсутствуют пока, на другой был однократный пропуск только на одном датчике (болело два датчика). Видимо, ProMini не любят инициализацию шины i2c.

    Проверка датчиков на шине проводится через определение доступности адресов датчиков

    Wire.beginTransmission(sensor->address);
    /* ... */
    sensor->status = (Wire.endTransmission() == 0);

     

    22.04.2019 в 20:44, post125 сказал:

    Уперся в нехватку оперативной памяти. Можно добавить еще 19 датчиков, с 20-го ESP перестаёт строить суточный график из стандартных четырёх датчиков - ошибка "Во время выполнения запроса произошла ошибка. Код ответа:200 (ОК)"; графики отдельно по каждому датчику пока еще строит.

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

    22.04.2019 в 20:44, post125 сказал:

    Проект на ESP32 на горизонте не виднеется?

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

    • Like 1
    • Thanks 1

  4. 14 часов назад, post125 сказал:

    Ранее пытался поднять частоту сбора данных на графики, как-то не получилось. Вроде бы вернул всё обратно.

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

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

    Попробую перепроверить файл index.htm, может там что-то накосячил.

    Работа index.htm не может влиять на микроконтроллер т.к весь код этого файла обрабатывается на стороне браузера. Контроллер принимает участие только в ответах на запросы API.

    10 часов назад, svchekalin сказал:

    зачем заставлять контроллер принимать решение когда это может сделать малина

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

    • Thanks 1

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

    У меня что-то обе ESPки перезагружаются примерно 1 раз в сутки

    А вот это оставлять так не стоит. Не пытались выяснить через какое время после старта это происходит или после какого события? Обратите внимание, что в Serial монитор периодически сбрасываются данные о свободной памяти (freeHeap), это значение не должно постоянно уменьшаться. Обычно, после выполнения всех заданий в планировщике это значение останавливается на фиксированной отметке и больше не уменьшается. Также для отслеживания памяти через web можно добавить программный сенсор.

    sensors.add(new knob_t(0, 81920, "1", "RAM", "Byte"), device::in, "ram", [&](){
      return 81920 - ESP.getFreeHeap();
    });

    Это первое с чего стоит начать.

    Также можете отключать разные части кода и смотреть на работу в течении суток. И помните, что в ESP8266 v2.4.1 для Arduino IDE имеется утечка памяти. Я рекомендую использовать 2.4.2. В общем, не бросайте эту ситуацию.

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

    Нет ли какой-нибудь ссылки как построить простенький сервер для этих целей.

    Лично я использую Zabbix, передача данных идет через MQTT. Но думаю, что стоит отталкиваться от того, на чем вы можете развернуть какую-либо систему мониторинга.

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

    В следующей версии не планируете получать данные на ESP с удаленных датчиков через NRF подключенной к slave ардуине по i2c?

    Эту возможность планировалось реализовать в текущей версии, но выход ESP32 перебросил свободное время хобби микроконтроллеров на себя. Это вполне возможно в будущем.


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

    А нельзя ли при запуске ESP первым значением с датчика заполнить все ячейки, а потом замещать их новыми данными? Тогда сразу графики будут презентабельными

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

    Выделение интересующей нас области

    image.png

    Результат зуммирования

    image.png

    Смотрите как будет удобнее лично Вам.

    • Thanks 1

  7. 15.04.2019 в 21:36, post125 сказал:

    Показания от -1 до +1 округляет до нуля как с фильтром, так и без фильтра.

    Проблема действительно была в коде и искать её нужно в файле sensors.h, нас интересует метод clear

    String sensors::clear(float value) {
      if ((int)value == 0) return "0";
      else if (value - (int)value == 0) return String((int)value);
      else return String(value);
    }

    Данный код используется для обрезания лишних нулей после запятой при формировании json объекта с данными журнала для их передачи в web интерфейс. Смысл был в уменьшении размера передаваемого объекта. Проблема крылась в самой первой проверке, её не смогут пройти числа меньше от -1 до 1 из-за приведения их к целому значению.

    Замените его на более явный и понятный код

    String sensors::clear(float value) {
      if (value == 0) return "0";
      if (value - (int16_t)value == 0) return String((int16_t)value);
      return String(value);
    }

    Вот пример его работы на числах близких к нулю

    0.000000, 0
    0.123400, 0.12
    0.500000, 0.50
    -0.900000, -0.90
    1.000000, 1
    0.987654, 0.99
    9.000000, 9
    

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

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

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

    Уверяю Вас, что все графики масштабируются одинаково. Все дело в том, что:

    1. Фактические показания барометра всегда находятся в узкой полосе по оси Y относительно лимитов этой оси
    2. График автоматически масштабируется под минимальные и максимальные значения переданных ему данных
    3. Изначально массив с данными для графика заполнен нулевыми значениями во всем своем диапазоне

    Получается, что пока все нулевые значения не будут вытеснены из массива, а это первые 24 часа работы, график будет строиться с учетом этих значений т.к для него это живые данные, хотя в человеческом понимании (появление значений по оси Y отличных от 0) это дает ошибочное чувство, что график только начал наполняться и визуально изменяться. Даже если Вы перезапустите контроллер и откроете график до того, как контроллер начнет перезапись массива с логами, Вы увидите полностью построенный график, но просто все значения по оси Y равны 0.

    Обратите внимание, как выглядит график давления после первых суток работы.

    image.png

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

    https://www.highcharts.com/demo/live-data

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

    • Thanks 1

  8. @init.d У Вас ряд явных проблем при работе с массивом.

    for (int i = 0; i < KEYS; i++) kst = DIS; // состояние датчика задается константой

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

    for (int i = 0; i < KEYS; i++) kst[i] = DIS;

    Вообще два одинаковых цикла for можно и одним заменить, но если честно, то наполнение массива kst не имеет смысла т.к массив был заполнен при объявлении, просто заполните его нужными значениями.

    boolean kst[KEYS] = {0};

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

    for (int i = 0; i < 3; i++) kst = ex1.digitalRead(i);
      for (int i = 0; i < 3; i++){
      if (kst[i] == ACT) { // если хотя бы 1 ключ активен
        String state = "Active";
        Serial.println (state);
      }
    }

    А хотели, видимо, получить это

    bool state = false; // Водим bool переменную чтобы не спамить Active в Serial если более одного порта активно
    for (int i = 0; i < KEYS; i++) { // Все делаем в одном цикле с лимитом указанным к KEYS
      kst[i] = ex1.digitalRead(i); // Пишем состояние порта в соответствующий элемент массива
      if (kst[i] == ACT) state = true; // Меняем состояние если хотябы один порт в состоянии ACT
    }
    if (state) Serial.println("Active"); // Сообщаем о состоянии ACT

    Ну и все в таком духе.

    А если по нормальному, то надо использовать прерывания, PCF8575 их поддерживает. Но опять вопрос, зачем нужен этот расширитель портов, если не задействованы стандартные порты микроконтроллера (в данном случае UNO). Выкидываем PCF и используем прерывания на стандартных портах. Почитать о них можно тут https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/

    И в таком случае код будет выглядеть совсем иначе, а работать намного быстрее и стабильнее. Единственный минус, это всего два порта поддерживающих прерывания у UNO.


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

    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

  10. 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

  11. @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

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

    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

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

    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

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

    @Convix_Maximus Из обязательных библиотек только две:

    1. https://github.com/knolleary/pubsubclient
    2. https://github.com/bblanchon/ArduinoJson/releases/tag/v5.13.2

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

    Исходники проекта можно забрать тут https://it4it.club/files/file/2-meteostanciya-na-esp8266/

     


  15. 11.03.2019 в 15:39, post125 сказал:

    Благодарю за ответ, буду пробовать. А если фигурирует seral, надо Мини к ESP по uartу подключать?

    Что Вы имеете в виду под фигурирует, связь между двумя контроллерами по Serial? Если да, то оба контроллера подключаются друг к другу через порты RX и TX с общей землей (GND). RX подключается к TX не зависимо от того с какой стороны смотреть. Также необходимо помнить об согласовании уровней сигналов. В программе работаете с контроллерами через Serial, различия будут лишь в том, что в ESP буфер с данными формируется автоматически, а в ATmega данные получаете по одному байту и буфер нужной длинны необходимо формировать самому.

    11.03.2019 в 23:57, post125 сказал:

    что-то не хочет компилироваться:

    Дело в том, что предоставленный пример написан под ESP 8266/32 и для них в объекте Serial есть метод printf, а вот под ATmega данного метода нет, но есть одноименная функция, приводящая к аналогичному результату. Так что для ATmega строки такого вида

    Serial.printf ("f1: %f\r\nf2: %f\r\n", f1, f2);

    приведите к такому

    printf ("f1: %f\r\nf2: %f\r\n", f1, f2);

    и все должно заработать.

    Вообще все строки с Serial можно удалить, я добавил их для вывода отладочной информации дабы можно было отследить как выглядит число, записанное в float при разборе на массив из 4-х byte элементов и дальнейший обратный процесс с записью значение в другую переменную.

    PS: прошу прощение за задержку с ответами.

    • Like 1

  16. @post125 попробуйте такой вариант разбора float на массив byte

    float f1 = -3.14;
    float f2 = 0;
    byte  b1[sizeof(float)];
    
    void setup() {
      Serial.begin(115200);
      Serial.println();
      *(float*)b1 = f1;
      Serial.printf("f1: %f\r\nf2: %f\r\n", f1, f2);
      Serial.printf("0x%02X\r\n0x%02X\r\n0x%02X\r\n0x%02X\r\n", b1[0], b1[1], b1[2], b1[3]);
      f2 = *(float*)b1;  
      Serial.printf("f1: %f\r\nf2: %f\r\n", f1, f2);
    }
    
    void loop() {
    }

    Передавайте этот массив и собирайте его в обратном порядке на стороне ESP.

    • Like 1

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

    @post125 В первую очередь нужно понять, что I2C и NRF это две разные транспортные линии, не рассматривайте их как единую среду передачи данных от беспроводных устройств к ESP, так ничего не выйдет.

    Со стороны ProMini необходимо организовать систему получения данных по беспроводному каналу их обработку и хранение в оперативной памяти. Допустим Вы получаете данные с 5-и беспроводных устройств, значит ProMini должна держать в памяти 5 разных значений с этими данными, пусть это будет float или, что угодно. Далее ESP, по мере надобности, запрашивает у ProMini данные по конкретному устройству, одному из 5-и. В ответ ProMini передает заранее преобразованное значение float с одного из датчиков в массив из 4-х byte или char и по очереди передает все элементы массива ESP. Далее проводите обратную операцию и получаете значение float. Главное помнить простую вещь, что float имеет размер в 4 byte, обращайтесь к каждому из них как к элементу массива и передавайте значение по одному byte.

    Таким образом получается, что ProMini является агрегатором данных со всех беспроводных устройств, работающих через NRF и передающих мастеру данные в виде массива из 4-х byte для каждого float.

    • Like 1

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

    26.02.2019 в 22:33, post125 сказал:

    Есть ли какие либо ограничения по используемым символам в SSID и пароле.

    Ограничения есть только в web интерфейсе проекта, в файле index.htm

    Для проверки SSID применяется следующее регулярное выражение, соответствующее латинским буквам от A до Z без учета регистра, всем цифрам и дополнительным символам "_. -". Общая длинна от 3 до 30 символов включительно.

    function checkSSID(ssid) { return ssid.match(/^[a-z0-9_. -]{3,30}$/i); }

    Для пароля все еще проще, это от 5 до 63 любых символов

    function checkPassw(passw) { return passw.match(/^.{5,63}$/); }
    26.02.2019 в 22:33, post125 сказал:

    не ругается, пишет, что сохранено, но при перезагрузке контроллера или страницы остаются старые значения

    Это говорит о том, что Вы проходите проверку на стороне web интерфейса ESP8266. Следовательно, причина кроется на стороне микроконтроллера.

    В первую очередь будет вызван один из методов web сервера, отвечающий за обработку пользовательских запросов.

    Файл webserver.h

    Скрытый текст
    
    void http::api_settings() {
      this->sendServerHeaders();
      this->sendHeader("Cache-Control", "no-store, no-cache");
      if (!this->security()) this->send(403);
      else if (this->authorized()) {
        if (this->hasArg(F("save"))) conf.write(this->arg(F("save")));
        this->send(200, headerJson, conf.showSecureConfig());
      } else this->send(401);
    }

    По сути тут будет проведена проверка на авторизацию пользователя и передача новых параметров вашему объекту конфигурации через вызов его метода config::write(String apiSave)

    Файл config.h

    Скрытый текст
    
    bool config::write(String apiSave) {
      if (this->parameterList) {
        DynamicJsonBuffer jsonBuffer;
        JsonObject& json = jsonBuffer.parseObject(apiSave);
        if (json.success()) {
          configParameter *parameter = this->parameterList;
          while (parameter) {
            if (json.containsKey(parameter->name)) this->param(parameter->name, json[parameter->name]);
            parameter = parameter->next;
          } return this->write();
        }
      } return false;
    }

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

    27.02.2019 в 11:30, post125 сказал:

    Заменил пароль на буквенно-цифровой, стало сохраняться.

    Могу предположить, что причина кроется в обработке некоторых символов библиотекой ArduinoJson в методе config::write(String apiSave), что приводит в отказу от записи конфигурации.

    json.success()

    Попробуйте в файле webserver.h добавить код ответа 500 для подобного события в метод http::api_settings(), приведите его к следующему виду

    void http::api_settings() {
      this->sendServerHeaders();
      this->sendHeader("Cache-Control", "no-store, no-cache");
      if (!this->security()) this->send(403);
      else if (this->authorized()) {
        if (this->hasArg(F("save"))) {
          if(!conf.write(this->arg(F("save")))) this->send(500);      
          else this->send(200, headerJson, conf.showSecureConfig());
        } else this->send(200, headerJson, conf.showSecureConfig());
      } else this->send(401);
    }

    В теории, если ошибка происходит на уровне json формата, то она должна появиться с сообщением

    500 Internal Server Error

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

    • Like 1

  19. 13 часов назад, post125 сказал:

    Как Вы уже рекомендовали, хочу подключить Ардуину как slave к ESP по I2C. Нашел библиотеку iarduino_I2C_connect для этих целей. Думаю, должно получиться. А вот как потом эти данные переварить в ESP и отправить в локальный web-сервер и (или) народный монитор? Подскажите, пожалуйста, куда копать, а то несколько дней никак не могу сообразить, с чего начать.

    Как мне кажется, эта библиотека не подойдет, но проверить конечно же стоит. Я бы копал в сторону стандартной библиотеки Wire.h как для AVR контроллеров (Atmega ...) так и для ESP, ищите их в вашей Arduino IDE. Также надо учитывать, что для этих контроллеров библиотеки разные. Например, ESP может работать только в качестве Master устройства, что в принципе и требуется, а вот AVR контроллеры могут работать в Master/Slave режиме. Это можно подсмотреть в заголовочных файлах (.h) их библиотек.

    Также для начала будут очень полезны эти материалы:

    Также помните о подтягивающих резисторах на SDA и SCL т.к они не отражены на схемах. Они понадобятся если Вы соединяете два контроллера между собой, но если на шине установлен какой ни-ть Китайский датчик, то очень велика вероятность, что резисторы уже есть. И еще один важный момент, это согласование уровней сигнала т.к ESP работает от 3.3V, а для ATmega стандартом является 5V, но они могут поддерживать и 3.3V. В любом случае, Вы должны гарантировать, что рассогласования уровней сигнала не будет. Лично мне нравится вариант, когда оба контроллера имеют питание 3.3V, так можно питать Slave от Master и не ставить плату согласования, но это зависит от конкретных задач, этот вариант не всегда приемлем.

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

    Описание для интерфейса

    knob_t *sensor_knob_cfg = new knob_t(0, 100, "1", "Что показывает", "Ед. измер.");

    Функция сбора данных

    float getSensorData() {
      float value = 0;
      /* Тут описываем работу с Slave по i2c, результат записываем в value */
      return value;
    }

    Добавление датчика

    sensors.add(sensor_knob_cfg, device::out, "sensor_uid", getSensorData);

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

    • Like 1

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

    23.02.2019 в 19:28, Дмитрий сказал:

    Хотелось бы добавить в сборку анемометр, об этом уже был разговор в теме.

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

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

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

    //gpio_14();    // Расхождение расчетной абсолютной влажности между показаниями с двух датчиков, например, BME280

    Теперь порт свободен и можно преступать к коду анемометра.

    Мне не известно какие датчики Вы еще используете поэтому всё дальнейшее описание я буду делать так, как будто у меня только один этот датчик, так будет более понятно. Выберите пользовательский файл в котором будите работать, это любой .h файл начинающийся с префикса users_ или создайте новый файл со своим уникальным именем, например users_wspeed.h. Выбранный Вами файл должен быть подключен через оператор include в основном файле программы, другие пользовательские файлы должны быть закомментированы.

    Для себя я выбрал вариант с новым файлом users_wspeed.h

    //#include "users_auto.h";  // Пользовательская конфигурация датчиков, именно тут описывается с какими датчиками работать
    //#include "users_bme280_x2.h"; // Пример для двух датчиков BME280 (несовместим с users_auto.h)
    //#include "users_multiple_ds18b20.h";
    #include "users_wspeed.h";

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

    #ifndef USERS_H
    #define USERS_H
      
      /* Весь код описанный ниже располагается тут */
      
    #endif

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

    Теперь добавим описание для плагина Knob который отобразит наш сенсор в web интерфейсе. Установим приделы шкалы от 0 до 40 метров в секунду с шагом в одну десятую и соответствующим описанием.

    /* Параметры индикаторов web интерфейса для плагина Knob
                           Мин  Макс   Шаг    Заголовок      Ед. измер.
    |---------------------|----|------|------|--------------|---------| */
    knob_t *S = new knob_t(0,   40,    ".1",  "Скорость в.", "м/c");

    Теперь объявим все необходимые константы. Обязательно укажите значения, подходящие для Вашего датчика. Учтите количество импульсов на один полный оборот, радиус анемометра и коэффициент для калибровки датчика. По сути этот коэффициент равен расхождению в скорости (м/c) между показаниями Вашего датчика и какого ни-ть эталонного, например другого анемометра. Можно собрать анемометр, покататься с ним на машине и сравнить показания, только помним о переводе км/ч в м/c. Я надеюсь, что зависимость линейная и все будет в порядке.

    /* Параметры конфигурации для расчета скорости ветра */
    #define  windSpeed_Pin 14       // GPIO микроконтроллера к которому подключен чашечный анемометр
    #define  windSpeed_Pulses 1     // Количество импульсов на один оборот чашечного анемометра
    #define  windSpeed_Correction 0 // Коэффициент поправки. Разница в скорости м/с между измеренным и фактическим значением полученная при калибровки
    #define  windSpeed_Radius 100   // Радиус чашечного анемометра от центра до середины чашечки в милиметрах

    Объявим переменные для хранения показаний частоты и расчетной скорости.

    uint32_t windSpeed_Hz = 0;      // Тут будет зафиксирована частота за ПЛАВАЮЩИЙ интервал времени
    float    windSpeed = 0;         // Тут будет зафиксирована скорость ветра

    Далее опишем функцию, которая будет вызываться по прерыванию и изменять показания частоты

    /* Функция, регистрирующая импульсы с чашечного анемометра */
    void pulseDetected() { 
      ++windSpeed_Hz;
    }

    Переходим к основной функции, отвечающей за расчет скорости ветра. Обязательно все за мной перепроверяйте т.к я мог ошибиться в расчетах или что-то сделать не так. На время расчетов мы выключаем регистрацию новых импульсов. За время мы возьмем интервал между предыдущим вызовом этой функции и текущим. Рассчитаем длину окружности и общий пройденный путь. Полученный результат запишем в одну из объявленных ранее глобальных переменных.

    /* Функция, производящая расчет скорости ветра */
    void pulseCounter() {
      detachInterrupt(windSpeed_Pin); // Отключаем регистрацию импульсов на время расчета
      /* Расчет скорости ветра */
      if (windSpeed_Hz) {
        float time = cron.lastRun("Wind Speed Calculation") / 1000;         // Время прошедшее с последнего расчета скорости ветра в секундах
        float circumference = 3.14 * 2 * windSpeed_Radius;                  // Длинна окружности анемометра в милиметрах
        float distance = (windSpeed_Hz / windSpeed_Pulses) * circumference; // Пройденое растояние в милиметрах
        float speed = distance / time / 1000;                               // Скорость в метрах в секунду (грязная)
        windSpeed = speed + windSpeed_Correction;                           // Скорость ветра с учетом коректировки
      } else windSpeed = 0;
      /* Сброс частоты */
      windSpeed_Hz = 0;
      attachInterrupt(windSpeed_Pin, pulseDetected, FALLING); // Возобновляем регистрацию импульсов
    }

    Опишем функцию возвращающую расчетный результат скорости.

    /* Функция, возвращающая последнее расчетное значение скорости ветра */
    float getWindSpeed() {
      return windSpeed;
    }

    Ну и осталось самое главное, это функция описывающая наши сенсоры.

    void sensors_config() {
      pinMode(windSpeed_Pin, INPUT_PULLUP);                             // Конфигурируем порт микроконтроллера как вход с активным встроенным подтягивающим резистором
      attachInterrupt(windSpeed_Pin, pulseDetected, FALLING);           // Регистрация импульсов с чашечного анемометра по прерыванию на землю
      cron.add(cron::time_10s, pulseCounter, "Wind Speed Calculation"); // Задача в планировщике для расчета скорости ветра
      sensors.add(S, device::out, "windSpeed", getWindSpeed);           // Добавляем сенсор скорости ветра в web интерфейс
    }

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

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

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

    users_wspeed.zip

    • Thanks 1

  21. 07.02.2019 в 13:24, Den MoRDa сказал:

    Реализация для CentOS чем нибудь отмечается? что нужно подправить?

    Ничем не отличается.

    07.02.2019 в 13:24, Den MoRDa сказал:

    В чем разница между network_id, object_name

    Разницы нет, это просто уникальные идентификаторы для подсетей.

    • Like 1

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

    16 часов назад, evgenyD сказал:

    посоветуйте как лучше реализовать подключение к данному проекту HX711 c тензодатчиками

    Электронных компонентов для проверки у меня нет, но я постараюсь помочь, опираясь на код библиотеки. Все фактические проверки Вам придется произвести самостоятельно. Я буду использовать эту библиотеку https://github.com/bogde/HX711, Вы можете использовать любую другую, просто действуйте по аналогии.

    В первую очередь необходимо определиться с используемыми портами микроконтроллера. Предлагаю задействовать 12 и 13 порты, но т.к они уже были использованы ранее, то в основном файле проекта необходимо закомментировать вызов функции gpio_12_13(). Я выбрал эти порты для примера, возможно Вы задействуете какие ни-ть другие.

    /* Инициализация GPIO для управления внешней нагрузкой */
    //gpio_12_13(); // Простое превышение температуры или влажности (выставляется в WEB интерфейсе)

    Теперь мы уверенны, что порты не заняты и можем переходить к реализации весов.

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

    В начале файла подключаем выбранную библиотеку.

    #include "HX711.h"

    Объявляем объект с помощью которого будем работать с весами. При объявлении мы передаем в качестве параметров номера задействованных портов.

    HX711 scale(12, 13);

    Создадим описание для системы визуализации (плагин Knob).

    knob_t *W = new knob_t(-100, 10000, "1", "Вес", "Гр");

    Мне не известно какой датчик Вы будите использовать, поэтому значения я выбрал на свое усмотрение. Минимальный вес равен -100 грамм, максимальный 10000 грамм, шаг шкалы 1, описание сенсора "Вес", ну и "Гр" в качестве единиц измерения. Минимальный вес в -100 грамм взят не случайно, так Вам будет проще найти калибровочный коэффициент.

    Теперь модифицируем функцию sensors_config() и объявим новый сенсор.

    /* Добавление датчиков в систему */
    void sensors_config() {
      /* Тут описан код других датчиков */
      
      scale.set_scale(3); // калибровочный коэффициент
      scale.tare(); // тарирование
    
      sensors.add(W, device::in, "in_weight", [&](){
        return scale.get_units() * 0.035274; // перевод в граммы
      });
    }

    В теории, этого должно быть достаточно.

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

    scale.set_scale(3);

    Также обратите внимание, что при запуске микроконтроллера происходит тарирование весов.

    scale.tare();

    Отпишитесь о результатах.


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

    @Же ка Ваша проблема скорее всего связана с ошибочным значением в переменной appid. Возможно опечатка или Вы не прошли до конца процесс получения ключа. Проверьте все еще раз.

    Таблицу с кодами ответов можно посмотреть тут https://ru.wikipedia.org/wiki/Список_кодов_состояния_HTTP#401

    А вот тестовый пример для проверки API.

    https://samples.openweathermap.org/data/2.5/weather?lat=35&amp;lon=139&amp;appid=b6907d289e10d714a6e88b30761fae22


  24. 2 часа назад, IvAn сказал:

    Простое добавление строчки для корректировки сенсора ccs811 не подходит. Все датчики перестают отвечать примерно через час. 

    Убедитесь в работоспособности проекта без строки корректировки. Проверьте датчик стандартным скетчем, идущим в примере с библиотекой. Укажите в качестве температуры и влажности какие-нибудь значения, можно статичные. Посмотрите на результат длительной работы.


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

    9 часов назад, IvAn сказал:

    Очень интересная метеостанция. Жалко, что дальше не развивается.

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

    9 часов назад, IvAn сказал:

    Почему на телефоне нет иконки статистики за 24 часа?

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

    Но если хочется её вернуть, то в файле index.htm найдите следующий фрагмент css кода.

    @media screen and (max-width:610px) {
        #graph { display: none; }
        div.copyright { position: unset; }
    }

    И удалите из него строку

    #graph { display: none; }

    Не забудьте запаковать файл обратно в .gz формат

    9 часов назад, IvAn сказал:

    CCS811 несовсем корректно обрабатывается. У меня после проветривания комнаты резко растут показания и  плавно снижаются.

    Это зависит от самого датчика. В проекте данные проходят только через медианный фильтр, класс medianFilter_t в файле tools.h. По сути, это просто накопительный буфер для сглаживания случайных пиков. Больше информации можно посмотреть тут https://ru.wikipedia.org/wiki/Медианный_фильтр

    9 часов назад, IvAn сказал:

    В библиотеке CCS811 есть пример возможности корректировки датчика по температуре и влажности. Подскажите как подправить  код.,

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

    В файле users_auto.h есть пример кода для работы с датчиком

    #if SENSOR_CCS811
      sensors.add(C, device::out, 0x5A, "out_co2", [&](){ 
        ccs811.begin(); 
        ccs811.start(CCS811_MODE_1SEC); 
      }, [&](){ 
        uint16_t eco2, etvoc, errstat, raw;    
        ccs811.read(&eco2, &etvoc, &errstat, &raw); 
        return eco2; 
      }, true);
    #endif

    Замените его на этот

    #if SENSOR_CCS811
      sensors.add(C, device::out, 0x5A, "out_co2", [&](){ 
        ccs811.begin(); 
        ccs811.start(CCS811_MODE_1SEC); 
      }, [&](){ 
        uint16_t eco2, etvoc, errstat, raw;
        ccs811.set_envdata(sensors.get("out_temperature"), sensors.get("out_humidity"));
        ccs811.read(&eco2, &etvoc, &errstat, &raw); 
        return eco2; 
      }, true);
    #endif

    Разница всего в одной строке

    ccs811.set_envdata(sensors.get("out_temperature"), sensors.get("out_humidity"));

    Где out_temperature и out_humidity, это имена объявленных Вами сенсоров температуры и влажности.

×
×
  • Создать...