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

Kitsum

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

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

  • Посещение

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

    234

Все публикации пользователя Kitsum

  1. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Контроллер жалуется, что не может найти точку доступа, но находит её при сканировании эфира. К сожалению, нет какой-либо дополнительной информации чтобы можно было явно указать на проблему. Попробуйте следующее: попытайтесь подключиться к другой точке доступа, например, можно использовать в этой роли сотовый телефон попробуйте сменить имя своей точки доступа, на время теста И еще, очень важное замечание. Обязательно перейдите на WAP2-PSK шифрование. И не скидывайте в открытый доступ скриншоты с настройками доступа к Вашему маршрутизатору. В данном случае, Вы засветили свой ключ доступа, и его обязательно нужно менять.
  2. т.к нет обратной связи для понимания когда, в данных режимах, необходимо подавать сигнал на открытие механического замка, то стоит отказаться от попытки удержания замка в открытом состоянии. Как-никак это делалось для электромагнита. В Вашем случае открыть дверь можно как мастер ключом после выхода из режима программирования, так и любым из добавленных ключей. В случае отсутствия ключей в памяти, что может быть только при монтаже замка, проблема решается при добавлении первого ключа, что опять же делается при монтаже замка. Так что просто удалите код отвечающий за управление замком в этих режимах и попробуйте на практике как это будет работать.
  3. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Да, удалите в основном файле строку cron.add(cron::time_1m, [&](){ sensors.checkLine(); }, true); Всю инициализацию датчиков проведите самостоятельно без использования соответствующих функций при описании датчиков. Или замените указанную выше строку на разовый вызов метода checkLine sensors.checkLine(); Проверка датчиков на шине проводится через определение доступности адресов датчиков Wire.beginTransmission(sensor->address); /* ... */ sensor->status = (Wire.endTransmission() == 0); Скорее всего вы получаете не все данные при запросе данных для комплексного суточного графика в следствии чего json строка считается поврежденной и график не строится. А корень проблемы в том, что в данном случае контроллер передает данные по всем сенсорам, для которых активно ведение лога. Связано это с тем, что изначально не было графиков по конкретным сенсорам, существовал только комплексный график, соответственно и данные отдавались все и сразу. Получается, что Вы нашли придел для размера передаваемого объекта с данными. Часть кода уже переписана и прекрасно работает, но есть технические нюансы, из-за которых я не могу назвать какие-то конкретные строки. Ну и опять же, все приходится делать только в свободное время.
  4. Kitsum

    Метеостанция на ESP8266 от it4it.club

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

    Метеостанция на ESP8266 от it4it.club

    А вот это оставлять так не стоит. Не пытались выяснить через какое время после старта это происходит или после какого события? Обратите внимание, что в 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. В общем, не бросайте эту ситуацию. Лично я использую Zabbix, передача данных идет через MQTT. Но думаю, что стоит отталкиваться от того, на чем вы можете развернуть какую-либо систему мониторинга. Эту возможность планировалось реализовать в текущей версии, но выход ESP32 перебросил свободное время хобби микроконтроллеров на себя. Это вполне возможно в будущем.
  6. Kitsum

    Метеостанция на ESP8266 от it4it.club

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

    Метеостанция на ESP8266 от it4it.club

    Проблема действительно была в коде и искать её нужно в файле 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 Есть другие, более лучшие способы обработки, постараюсь их рассмотреть в следующей версии проекта, но есть вероятность, что в этой части кода не будет нужды. Уверяю Вас, что все графики масштабируются одинаково. Все дело в том, что: Фактические показания барометра всегда находятся в узкой полосе по оси Y относительно лимитов этой оси График автоматически масштабируется под минимальные и максимальные значения переданных ему данных Изначально массив с данными для графика заполнен нулевыми значениями во всем своем диапазоне Получается, что пока все нулевые значения не будут вытеснены из массива, а это первые 24 часа работы, график будет строиться с учетом этих значений т.к для него это живые данные, хотя в человеческом понимании (появление значений по оси Y отличных от 0) это дает ошибочное чувство, что график только начал наполняться и визуально изменяться. Даже если Вы перезапустите контроллер и откроете график до того, как контроллер начнет перезапись массива с логами, Вы увидите полностью построенный график, но просто все значения по оси Y равны 0. Обратите внимание, как выглядит график давления после первых суток работы. Вот пример на сайте разработчика плагина, который демонстрирует динамическое обновление данных на графике, но, если Вы уделите просмотру этого демо чуть больше времени, то заметите как происходит автоматическое масштабирование графика по шкале Y в зависимости от минимального и максимального значения в переданном массиве данных. https://www.highcharts.com/demo/live-data Возможно в API можно найти свойство, отвечающее за выход значения по оси Y за определенные лимиты и регулирующее поведение графика, но это мои догадки, ответ нужно искать в документации от Highcharts.
  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. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Доброе время суток. Не совсем понятно, эти проблемы и на локальных графиках тоже или только на народном мониторинге? Если на локальных тоже провалы, значит вы в течении какого-то времени получаете такие данные т.к на наполнение медианного фильтра требуется время, а это не менее трех запросов данных (по умолчанию размер буфера фильтра равен пяти). Тут не все так просто, гарантировать целостность данных нельзя т.к никаких проверок попросту нет. Наличие данных, похожих на настоящие, в одном элементе массива не дает гарантии, что в других элементах все также хорошо. Для повышения надежности используется механизм проверки контрольной суммы, алгоритм выбирается в зависимости от конкретной ситуации. Например, мы отправляем 1 байт полезной нагрузки, пусть это будет чисто 123 или ‭01111011‬ в двоичной системе счисления, следом за ним отправляем еще 1 байт который будет представлять из себя контрольную сумму. Содержимое второго байта зависит от алгоритма, который мы выбираем, пусть это будет битовая операция "И" (AND) и по завершению расчетов мы хотим видеть 0, что будет сигналом о корректности данных. Таким образом второй байт должен содержать такую последовательность бит, чтобы в ходе операции получить значение 0. В нашем примере, второй бит должен содержать число 132 или ‭10000100‬ в двоичной системе счисления. На принимающей стороне производим расчет: 01111011 & 10000100 = 00000000 Также доступны и другие битовые операции https://ru.wikipedia.org/wiki/Битовые_операции Для каждой конкретной задачи требуется свой алгоритм, конечно не факт, что это будут именно битовые операции. Используется только медианный фильтр. Чтобы отключить его, перейдите в файл sensors.h и найдите строку medianFilter_t lastDimension; Замените её на float lastDimension; Медианный фильтр использует float для хранения значений, на практике он нужен только чтобы сгладит пиковые выбросы, спровоцированные кратковременными внешними изменениями в среде в которой находятся сенсоры. В последних исходниках проекта имеются только сжатые файлы, но поддерживаются оба варианта. Приоритет отдается сжатому файлу т.к его транспортировка требует меньше времени. Вы можете удалить архивную копию, но предварительно убедитесь, что на контроллере имеется его распакованный вариант, иначе могут быть небольшие трудности. Явного округления в коде не предусматривалось, давайте искать. Для начала, стоит посмотреть на данные передаваемые от контроллера в web интерфейс. Сделать это можно пройдя по ссылке http://espws.local/api/sensors/log (espws.local стоит заменить на ip адрес если пытаетесь открыть ссылку с устройства не поддерживающего mDNS или имеющего проблемы при работе с зоной .local). Еще более наглядный вариант, это зайти на главную страницы web сервера микроконтроллера, открыть режим разработчика в браузере (раздел network), далее открыть график и поймать запрос на страницу /api/sensors/log. В окне ответа сервера ищем вкладку с предварительным просмотром, там будет разобранный json ответ с данными. Просмотрите эти данные и попытайтесь определить, получаете ли Вы эти значения уже округленными или это происходит во время создания самого графика. На народном мониторинге используется тот же самый плагин для создания графиков, что и в проекте метеостанции. Вы можете изменять визуализацию как Вам больше нравится, но в приделах возможностей самого плагина. Вот ссылка на сайт разработчика https://www.highcharts.com/ они предоставляют очень наглядные демо и всю документацию для создания собственной визуализации данных, это могут быть не только графики. Постараюсь в ближайшее время воссоздать Вашу проблему с округлением, но с разовыми пропажами данных все сложнее т.к это касается непосредственно Вашего кода.
  10. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Скорее всего Вы достигли придела в шаге шкалы для библиотеки Knob. Возможно Вам подойдет иной вариант отображения состояния батареи, например, в процентах отображающих полезную емкость аккумулятора, только не от 0 до maxV, а от минимально напряжения питания контроллера до maxV. Например, для ESP8266 эти границы будут от 2.2V до 3.6V, что дает нам (3.6V-2.2V)/100 = 0.014V на 1% шкалы сенсора. В таком случае, когда мы видим, что осталось 5% полезной емкости аккумулятора, приходит точное понимание, что аккумулятор нужно заменить. Возможно Вы найдете более информативный способ визуализировать изменение тысячных долей. На всякий случай скину ссылки на сам плагин Knob: Примеры: http://anthonyterrien.com/demo/knob/ Исходники: https://github.com/aterrien/jQuery-Knob
  11. Kitsum

    Метеостанция на ESP8266 от it4it.club

    @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 Т.к Вы выбрали механизм сбора всех данных за раз, то производить эту процедуру каждый раз когда требуются данные только по напряжению аккумулятора, нет никакого смысла. Считывайте данные отдельной задачей, а в коде сенсора просто забирайте нужный элемент массива из памяти. Также старайтесь избегать глобальных переменных, различные промежуточные операции можно делать прямо в ваших функциях и методах. Остальные ошибки по невнимательности или спешке, думаю нет смысла на них указывать.
  12. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Доброе время суток. Схожий вопрос уже был в теме, посмотрите этот комментарий, его вторая половина посвящена графику 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 где можно эти данные сохранять. Также отмечу, что контроллер не хранит временные позиции снятых показаний, сделано это для экономии оперативной памяти. При расчете конечной точки временной шкалы графика, используется единственная временная отметка с указанием времени в миллисекундах, прошедших с последнего обновления данных. Относительно этой отметки и времени, установленном на устройстве, с которого происходит просмотр графика, производится формирование всей шкалы с данными. Рассматривался ли вариант со снятием показаний через RS232 ИБП и дальнейшая передача показаний, например, через SNMP по запросу от внешнего хоста? Можно таким образом подвязать различные системы мониторинга, например, Zabbix.
  13. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Доброе время суток. Как Вы уже правильно заметили, библиотека wire.h уже объявлена в файле tools.h, объявлять её еще раз нет необходимости, но даже если и объявить его повторно, то это не даст совершенно никакого результата из-за определенных директив препроцессора, о которых можно почитать, например тут https://docs.microsoft.com/ru-ru/cpp/preprocessor/preprocessor-directives Что касаемо добавления собственных переменных, функций, классов и т.п, то тут нет никакого ограничения, это можно делать где угодно, главное, чтобы эти данные были в области видимости того кода где они будут востребованы. Я могу только направить, порекомендовав использовать уже имеющиеся файлы по их назначению. Допустим взять файл config.h, он содержит описание класса, предоставляющего интерфейс работы с файлами конфигурации, файл логически завершен (в той или иной степени) и любая другая информация, не имеющая прямого отношения к данному классу, там будет лишней. К таким файлам можно отнести следующие: config.h cron.h sensors.h webserver.h wifi.h Вносить изменения в эти файлы не рекомендуется, но не запрещается если Вы хотите доработать функционал, предоставляемый ими. Другие файлы более открыты для редактирования, и даже нуждаются в нем т.к проект дорабатывается каждым под собственные нужды. Я бы посоветовал вносить в них правки, соответствующие их логическому предназначению. gpio.h - если требуется описать управление какой-либо нагрузкой через порты микроконтроллера в том числе и через различные платы расширения. services.h - если требуется описать взаимодействие контроллера с внешними серверами или устройствами, например, через TCP/IP. tools.h - если требуется где-то описать вспомогательные утилиты которые не заслуживают вынесения их в отдельный файл проекта. Теперь, что касаемо пользовательских файлов users_auto.h users_bme280_x2.h users_ds18.h - нет в исходниках, но встречался в этой теме users_wspeed.h - нет в исходниках, но встречался в этой теме ... То это файлы с примерами конфигурации сенсоров для web интерфейса. Конечно можно пользоваться и ими, но только каким-то одним за раз. Я же рекомендую закомсентировать их в основном файле и создать свой собственный и описать в нем все необходимые сенсоры, подключить все необходимые библиотеки для этих сенсоров и т.п. А имеющиеся файлы используйте как подсказки для реализации задуманного. Ну и остается основной файл, он по сути, просто собирает все в кучу, но Вы можете вносить в него любые правки, даже разместить там все свои модификации, главное, чтобы Вам потом было удобно во всем этом разбираться. Надеюсь это поможет Вам определиться с выбором файлов для модификации, но, если есть сомнения, просто создайте собственный файл, возможно даже не один, и опишите все там, так Вы точно не запутаетесь. Возможно Вы имели в виду считывание из памяти ProMini, поправьте если я не прав. Я не знаю, как Вы организовали модель обмена данными между двумя контроллерами по i2c, имею только общее представление о проделанной Вами работе. Но посоветую обратиться к проверенному временем механизму, реализованному практически во всех популярных библиотеках, отвечающих за связь с датчиками на шине i2c. Общая суть очень проста: Есть набор команд, которые можно отправить своему Slave, они заранее оговорены, как и ответы на них. Команда может запрашивать данные как по определенному параметру, так и по группе параметров, например, температура или температура и влажность. Мастер всегда знает какой объем данных должен прийти в ответ на ту или иную команду, например, один Byte или массив из 8-и Byte, хотя никто не мешает принимать данные до тех пор, пока: не будет получен специальный Byte конца телеграммы, не будет превышен выделенный объем памяти под ответ, не будет пойман таймаут по тишине в эфире или таймаут из-за медленного ответа Slave. После получения ответа производим разбор данных и выделение полезной часть и тут мы возвращаемся к первому и второму пункту этого списка. Аналогичным образом можно отправлять конфигурационные команды, например, для управления нагрузкой на портах Slave. Просто выберите удобный и быстрый для Вас способ обмена данными.
  14. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Доброе время суток. @Convix_Maximus Из обязательных библиотек только две: https://github.com/knolleary/pubsubclient https://github.com/bblanchon/ArduinoJson/releases/tag/v5.13.2 Все остальные ссылки на библиотеки датчиков используемых в файлах с примерами можно найти в этих самых файлах с примерами. Вы вольны вообще отказаться от предложенных примеров и создать свой файл конфигурации, описать в нем совершенно другие датчики и библиотеки. Исходники проекта можно забрать тут https://it4it.club/files/file/2-meteostanciya-na-esp8266/
  15. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Что Вы имеете в виду под фигурирует, связь между двумя контроллерами по Serial? Если да, то оба контроллера подключаются друг к другу через порты RX и TX с общей землей (GND). RX подключается к TX не зависимо от того с какой стороны смотреть. Также необходимо помнить об согласовании уровней сигналов. В программе работаете с контроллерами через Serial, различия будут лишь в том, что в ESP буфер с данными формируется автоматически, а в ATmega данные получаете по одному байту и буфер нужной длинны необходимо формировать самому. Дело в том, что предоставленный пример написан под 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: прошу прощение за задержку с ответами.
  16. Kitsum

    Метеостанция на ESP8266 от it4it.club

    @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.
  17. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Доброе время суток. @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.
  18. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Доброе время суток. Ограничения есть только в 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}$/); } Это говорит о том, что Вы проходите проверку на стороне web интерфейса ESP8266. Следовательно, причина кроется на стороне микроконтроллера. В первую очередь будет вызван один из методов web сервера, отвечающий за обработку пользовательских запросов. Файл webserver.h По сути тут будет проведена проверка на авторизацию пользователя и передача новых параметров вашему объекту конфигурации через вызов его метода config::write(String apiSave) Файл config.h Метод перебирает все доступные ему параметры, находящиеся в оперативной памяти и перезаписывает значения для тех из них чьи имена упоминались в списке, переданном web интерфейсом. Далее записывает данные в конфигурационный файл находящийся во Flash памяти. Могу предположить, что причина кроется в обработке некоторых символов библиотекой 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 Если причина действительно в этом и Вам удастся выловить символ, то дайте мне знать какой он.
  19. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Как мне кажется, эта библиотека не подойдет, но проверить конечно же стоит. Я бы копал в сторону стандартной библиотеки Wire.h как для AVR контроллеров (Atmega ...) так и для ESP, ищите их в вашей Arduino IDE. Также надо учитывать, что для этих контроллеров библиотеки разные. Например, ESP может работать только в качестве Master устройства, что в принципе и требуется, а вот AVR контроллеры могут работать в Master/Slave режиме. Это можно подсмотреть в заголовочных файлах (.h) их библиотек. Также для начала будут очень полезны эти материалы: https://www.arduino.cc/en/Reference/Wire https://www.arduino.cc/en/Tutorial/MasterReader https://www.arduino.cc/en/Tutorial/MasterWriter https://forum.arduino.cc/index.php?topic=336543.msg2321656#msg2321656 (стоит ознакомиться с возможными проблемами, прочтите всю тему) Также помните о подтягивающих резисторах на 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. Очень велика вероятность, что после изучения их содержимого у Вас появится свое видение как это должно быть реализовано, и это очень хорошо.
  20. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Доброе время суток. @Дмитрий Давайте попробуем, но я заранее предупреждаю, что Вам придется самостоятельно проводить все испытания. Я лишь постараюсь помочь с рекомендациями относительно данного проекта. И так. На сколько я понял, общая идея заключается в подсчете импульсов чашечного анемометра. Самый верный путь, это регистрировать импульсы по прерыванию т.к это не тратит драгоценное время ЦП. Далее, опираясь на частоту импульсов вычислять расстояние, которое прошел анемометр как будто это колесо автомобиля, а уже из этих данных выводить скорость. Стоит учитывать, что при расчете частоты нужно брать время между предыдущим и текущим расчетом скорости ветра, а не фиксированный интервал т.к есть и другие задачи время выполнения которых может меняться, а микроконтроллер выполняет код в реальном времени без распараллеливания задач. В первую очередь необходимо определиться, какой порт микроконтроллера будем задействовать. Я возьму за основу порт 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
  21. Ничем не отличается. Разницы нет, это просто уникальные идентификаторы для подсетей.
  22. Вроде бы и ничего сложного тут нет, но то параметр забудешь, то еще какая ни-ть мелочь, а по справке бегать как всегда нет особого желания. В общем оставляю лично для себя. find /catalog -type d -exec chmod 755 {} \; find /catalog -type f -exec chmod 644 {} \;
  23. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Доброе время суток. Электронных компонентов для проверки у меня нет, но я постараюсь помочь, опираясь на код библиотеки. Все фактические проверки Вам придется произвести самостоятельно. Я буду использовать эту библиотеку 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(); Отпишитесь о результатах.
  24. Kitsum

    esp8266 и парсинг погоды с OpenWeatherMap

    Доброе время суток. @Же ка Ваша проблема скорее всего связана с ошибочным значением в переменной 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
  25. Kitsum

    Метеостанция на ESP8266 от it4it.club

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