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

Таблица лидеров


Популярные публикации

Отображаются публикации с наибольшей репутацией начиная с 14.08.2015 в Сообщения

  1. 5 баллов
    Всем привет, в этой статье поговорим об уже надоевшей всем теме - "Метеостанция". Каждый пытается сделать что-то свое, вот и я не стал исключением и попытался материализовать свои эротические фантазии на контроллере ESP8266. Тема задумывалась уже давно как некое обновление для предыдущего проекта этой тематики, но из-за своей неспешности переросла в нечто самостоятельное. При всей привлекательности микроконтроллера ESP8266 с его большим объемом памяти, железной поддержкой Wi-Fi и массой разных плюшек, он не лишен недостатков. Самый основной - ограниченное количество поддерживаемых одновременных TCP соединений равное 5. Если превысить этот лимит, то контроллер потеряет связь с окружающим миром, при этом watchdog будет думать, что все в порядке, а следовательно, даже не попытается нам помочь. Будем стараться это помнить! Стоит начать с концепции Доступ к данным метеостанции нужно получать без установки внешних приложений и под любой операционной системой. Для этих целей подойдет практически любой современный браузер. Меня всем устраивает Chrome. Раз уж за основу взят HTTP протокол, стоит озаботиться экономией трафика и ограничением числа TCP соединений. Хорошим тоном будет передача всего необходимого для формирования страницы контента только при первом обращении, а все последующие операции, такие как отображение показаний с датчиков или настройку контроллера, производить через API. В этом нам поможет JQuery. А вот, чтобы ослабить болевые ощущения от передачи файлов с SPI Flash в браузер, стоит предусмотреть систему кэширования, например, Etag. Это позволит отдавать тяжелый контент единожды, а при последующих загрузках страницы просто подтверждать его актуальность на уровне Web сервера микроконтроллера и кэш браузера вступит в игру, неимоверно уменьшив время загрузки страницы! "Вы были правы в одном, Мастер: переговоры были недолгими." © Звездные войны. Эпизод 1 Из-за того, что метеостанция с датчиками и контроллером должна располагаться на улице, жизненно необходимо предусмотреть возможность обновлять прошивку ESP через Web интерфейс. Аналогичным образом должны обновляться файлы Web сервера расположенные на SPI Flash. Этот и предыдущий пункт вкупе позволят обновлять функционал микроконтроллера из домашней сети или из интернета, если конечно в этом возникнет острая необходимость. Чтобы никто посторонний не могу вмешаться в работу устройства или изменить файлы Web сервера, последний должен хотя бы как-то себя защищать. Пускать в панель управления только после авторизации, блокировать доступ при попытках брутфорса пароля. В конце концов, контроллер обязан самостоятельно генерировать ключи (salt) для авторизации, дабы сделать алгоритм непредсказуемым и исключить потенциальный взлом, в случае если злодей завладеет исходниками проекта. Понятно, что кому она там нужна, эта метеостанция, если её не завязывать с умным домом, если только из-за спортивного интереса, но как говориться “Береженого Бог бережет”. Датчики стоит расположить по уму - в метеобудке, а вот контроллер в сухом и закрытом боксе. Объединить их между собой, как мне кажется, удобнее по I2C шине - минимум проводов, максимум удобства. Практически на всех вариантах плат ESP-xx имеется штатный светодиод, можно воспользоваться им как для индикации режимов и состояния микроконтроллера, так и для вывода какой-либо промежуточной информации. Что касаемо режимов работы ESP8266, как ни странно, но он должен находить домашнюю Wi-Fi сеть и подключаться к ней. Если вдруг звезды не были к нам благосклонны, и домашняя беспроводная сеть приказала долго жить, контроллер обязан перейти в режим точки доступа (AP) дабы к нему можно было подключиться с какого-либо устройства и перенастроить его на другую сеть. А вот пока последнее не произошло, ESP должен периодически сканировать эфир в поисках долгожданной домашней точки доступа и, если боги были к нам милосердны, и домашняя сеть появилась в эфире, незамедлительно переключиться в режим клиента (STA) и в пылу страсти воссоединиться с ней. Ну и естественно, как же без отправки данных на внешние ресурсы, сейчас без этого не обходится ни одна уважающая себя кофеварка, не говоря уже о метеостанции. Думаю, что основным блюдом станет протокол MQTT, это уже облегчает возможность интеграции с умным домом, стулом или той же кофеваркой. Ну а на закуску добавим поддержку "ThingSpeak" и "Народного мониторинга". При желании можно нарастить функционал, благо памяти у микроконтроллера еще много. Как я себе это представляю Учтите, что на видео, данные с датчиков, эмитируются самим микроконтроллером, это нужно для наглядности. В жизни метеорологическая обстановка намного спокойнее слава Богу. Перейдем к физической сборки устройства Как по мне, так самый оптимальный вариант, это воспользоваться отладочной платой NodeMCU V3 и базой для неё. Таким образом, мы получим отличный комплект с разведенной на его борту всей необходимой обвязкой и возможностью питать устройство от 5 до 24 Вольт. Отладочная плата на базе, и смотрится хорошо, и удобства хоть отбавляй. Заливаем прошивку, образ SPI Flash и подключаем четырьмя проводами датчики. Справится даже ребенок. Ссылки: Базовая плата для NodeMCU V3 с преобразователем питания 5-24V в 5V Отладочная плата ESP8266 от NodeMCU Естественно никто не запрещает Вам развести свою плату. Если Вы это сделаете, скиньте нам свое творение, возможно мы перейдем на него. В идеале, все должно размещаться в метеобудке. Датчики взятые за основу Теперь настал момент озаботиться, где описанные выше ребята будут жить. В прошлый раз мы использовали для этих целей, найденную в подножном корме, электрическую распределительную коробку. Кроме дешевизны в этом решении нет ничего положительного. В этот раз мы воспользуемся более серьезным вариантом – "Метеорологическая будка Стивенсона". Она способна защитить датчики от прямых воздействий окружающей среды, но при этом имеет открытую структуру со стенками в виде жалюзи. Удобно, красиво и самое главное – правильно! Будка печатается на 3D принтере по эскизам опубликованным на Thingiverse неким kowomike, спасибо добрый человек! Архив с эскизами можно будет скачать в конце поста. Фото готовой будки Шпилька М8 крепится через зажимной хомут к мачте уличной антенны. Примерка. Шпилька практически не укорачивалась, чтобы не закрывать будку параболической Wi-Fi антенной. Хотя в моем случае все это сделано не правильно т.к это солнечная сторона дома. Доступа на теневую сторону дома у меня нет, поэтому приходиться довольствоваться тем, что имеем. По прошлой метеостанции мне говорили "на солнечной стороне все эти измерения - сферический конь в вакууме, слепи %описание-многА-букАв% и закрепи на теневой стороне дома". Я пока живу в панельном многоквартирном доме, как и не малая часть нашей страны. Доступ к теневой стороне дома (а для меня, по факту, это окна в подъезде) - прямой вызов всем гопникам района трущимся рядом, любопытным соседям с бегающими глазками и всей элите человечества скрашивающей фоном мою унылую и слишком простую, по их мнению, жизнь. Думаю, что мысль я донес. Датчики располагаются на разных уровнях. В основании находится датчик освещенности BH1750 и смотрит ровно вниз. Мне кажется, так он будет меньше пачкаться и покрываться пылью и при этом смотреть наружу сквозь минимальное количество препятствий для солнечного света. Вообще размещение этого датчика, это целая головная боль. Как не крути, все будет не то. Оставил так, ведь по сути важны не сами показания, а тенденция изменения. Хотя кого я пытаюсь обмануть, точность важна всегда! Предлагайте свои варианты. Намного проще обстоят дела с датчиком атмосферного давления BMP180 и влажности SI7021, кстати, с последнего мы также будем забирать данные о температуре. Их размещаем в оставшемся свободном пространстве будки, благо его там с избытком, но не в конусе т.к пространство в нем менее проветриваемое. Все хозяйство подключается между собой следующим образом NodeMCU | ESP 07/12 | Датчики ----------------------------- D2 | GPIO 4 | SDA D1 | GPIO 5 | SCL 3.3V | 3.3V | 3.3V GND | GND | GND ВАЖНО: при финальном монтаже устройства на его место службы, обязательно установите перемычку между пинами GPIO 0 (D3) и питанием 3.3 Вольта. Причины её установки описаны в закрепленном сообщении с описание обновления от 12.08.2017. Сам микроконтроллер будет спрятан в уже знаменитую распределительную коробку, закрепленную на шпильке, чуть ниже будки Стивенсона. У меня все находится на стадии неторопливой сборки с попутным поиском более удачных идей. Плата расширения, на которой будет установлена плата NodeMCU, закреплена через ножки для крепления компьютерных материнских плат в корпусах. Разъемы для подключения внешних датчиков и питающей линии установил на местах где была пара штатных заглушек. Закрепил все через переходную пластину, выпиленную из куска фольгированного текстолита. Естественно, предварительно пластина была протравлена, а вся медь искоренена, ибо в этом случае она нам не друг. Также была предусмотрена проставка из полиэтиленового поролона (используется в качестве упаковочного материала при транспортировке грузов) между текстолитом и корпусом, общей толщиной 5мм, а после затяжки крепежных винтов, его толщина не превышает 1мм. Это было сделано из-за опыта эксплуатации предыдущего (временного) бокса для этой метеостанции. Без проставки влага быстро найдет путь вовнутрь, и срок службы устройства снизится. Производим примерку. При окончательном монтаже обязательно необходимо удалить все не плотно прилегающие части полиэтиленового поролона, то есть те части, которые располагаются снаружи и не сдавлены крепежной текстолитовой пластиной. Это необходимо сделать для препятствования накоплению влаги в доступных для неё полостях. Также пришлось увеличить число крепежных болтов для более надежного прилегания текстолита, в противном случае он может выгибаться. Все самое сложное позади, остается только вывести на один разъем шину i2c с питание 3.3 Вольта, а на другой подвести пины питания платы расширения. Но т.к у меня валялся "хвост" отрезанный когда-то от не рабочего блока питания маршрутизатора, и я не побрезговал им воспользоваться по прямому назначению. Далее останется все подравнять, проверить качество монтажа, возможность замены платы NodeMCU, если это будет необходимо при эксплуатации и самое главное, дважды проверить, что и куда припаяно. Мои кривые руки и невнимательность уже наказывали меня, а т.к ждать новые запчасти долго, повторять не хочется. Общий вид получился таким А вот как все выглядит в боевых условиях. Кстати, могу предложить идею с помещением в бокс мешочка содержащий впитывающий влагу гель, они часто встречаются в коробках с обувью. Если все герметично, то он впитает остатки влаги, а если нет, то лишним уж точно не будет. Требования (!!!Читать обязательно!!!) Arduino IDE с поддержкой контроллера ESP8266, версия 2.6.2 (на версиях выше работоспособность не проверялась) Установленный модуль в Arduino IDE для загрузки файлов во Flash память микроконтроллера. Как установить описано тут. Для работы модуля загрузки файлов во Flash может понадобится последняя версия Python https://www.python.org/downloads/ Любой модуль на базе ESP8266 c Flash 4MB (3MB выделяем под SPIFFS) В параметрах выставляем lwIP версии 2 и максимальную производительность (lwIP v2 Higher Bandwidth) Сам архив с последней версией проекта. Скачать можно в конце статьи или по этой ссылке. Обязательные библиотеки (!!!Читать обязательно!!!) ArduinoJson (v5.13.5) PubSubClient Ссылки на библиотеки сенсоров указаны в комментариях к коду. Сами библиотеки, как и обслуживаемые ими сенсоры, не являются обязательными. Вы вольны использовать любые датчики, как физические, так и программные. Порядок установки (!!!Читать обязательно!!!) Изучите файлы проекта с примерами использования тех или иных сенсоров. Все файлы с примерами начинаются с префикса users_, это users_auto.h, users_bme280_x2.h и т.д. Загрузите необходимые Вам библиотеки или используйте эти файлы как пример для добавления иных датчиков. Выставите необходимые настройки для контроллера в среде разработки Arduino IDE. Пример настроек указан на скриншоте выше. Обязательно убедитесь, что выбрано правильное распределение места для внутренней файловой системы, это значит, что 3MB должно быть выделено под файловую систему. Также проверяем, чтобы использовался lwIP v2 в режиме максимальной производительности (lwIP v2 Higher Bandwidth). Произведите загрузку программы с помощью среды разработки (Ctrl + U). Произведите загрузку содержимого каталога data в файловую систему. Меню/Инструменты/ESP8266 Sketch Data Upload Перед тем как устанавливать метеостанцию на постоянное место жительства, подтянуть GPIO-0 (пин D3 на плате NodeMCU) к питанию 3.3V. Во время данной процедуры, питание на контроллере должно отсутствовать. Первый запуск (!!!Читать обязательно!!!) Помните, что вся конфигурация микроконтроллера производится исключительно через web интерфейс. Никаких изменений значений тех или иных параметров в коде не требуется, а подобную практику будем считать плохим тоном. И так, после запуска микроконтроллера он сразу перейдет в аварийный режим и поднимет собственную точку доступа с именем WeatherStation. Это нормальное поведение т.к подразумевается использование метеостанции в домашней беспроводной сети, ну а раз о ней пока ничего не известно, то и подключаться не к чему. Подключитесь к данной сети с любого удобного устройства и перейдите в панель управления (для этого имеется соответствующая иконка, запутаться невозможно), контроллер будет доступен по адресу http://espws.local или http://192.168.4.1 При попытке входа в панель управления будет запрошено имя пользователя и пароль, по умолчанию admin/admin. После входа в панель управления перейдите в раздел "Основные настройки WiFi" и укажите имя и пароль Вашей домашней сети, а также, при необходимости, укажите пароль для подключения к точке доступа поднимаемой контроллером в аварийном режиме. Если все сделано правильно, то контроллер подключится к домашней сети в течении 5-и минут. Если Ваша домашняя сеть скрыта, то после первоначальной настройки необходимо перезагрузить контроллер. Это необходимо из-за частичной поддержки работы со скрытыми сетями. После перезагрузки контроллер увидит Вашу сеть и запомнит её MAC адрес. Помните об этом если захотите сменить домашний маршрутизатор. Хотите помочь проекту или спонсировать новый? Yandex.Money PayPal.me Файлы
  2. 5 баллов
    Обновление от 27.02.2018 (v2.0 Beta) Друзья, всем доброе время суток. Немного не хватает времени и технических возможностей подготовить все как положено до конца месяца, в связи с этим прошу отнестись с пониманием. Основная статья будет переписана в течении нескольких дней после публикации этого сообщения. Все исходники, по доброй традиции, опубликованы в первом сообщении темы. Краткий список изменений Требования Arduino IDE c поддержкой esp8266 v2.4.0+ Любой модуль на базе ESP8266 c Flash 4MB (3MB выделяем под SPIFFS) Код для микроконтроллера структурирован и разбит на модули, что делает его более простым для понимания и внесения изменений config.h - работа с файлом конфигурации хранящимся во flash памяти микроконтроллера в формате json. Реализована возможность быстрого добавления пользовательских параметров. Поиск, чтение, запись этих параметров, а также специализированные функции для работы с WEB интерфейсом – обновление и запись группы параметров, переданных в формате json и формирование списка параметров и их значений с фильтрацией паролей для их скрытия при передаче в WEB интерфейс (в WEB интерфейсе реализована ответная часть). cron.h - планировщик заданий основной целью которого является выполнение пользовательских заданий с установленным интервалом времени. Задания представляют из себя функции описанные пользователем. На данный момент они не должны принимать или возвращать никаких значений, обязаны выполнять всю работу самостоятельно или с помощью глобальных объектов. Интервал выполнения задания выставляется в миллисекундах или с помощью макросов, представляющих из себя человекочитаемые имена, за которыми скрываются часто используемые отрезки времени в миллисекундах. Доступен дополнительный функционал в виде поиска задания в журнале, сброс его интервала вызова, выставление нового интервала, остановка выполнения и проверка активности задания. gpio.h - не является модулем. Содержит примеры реализации работы с GPIO для самых часто упоминаемых пользователями задач – управление нагрузкой по превышению установленных через WEB интерфейс приделов температуры и влажности, а также управление нагрузкой при расхождении расчетных значений абсолютной влажности между показаниями двух датчиков. sensors.h - тестовый вариант модуля для реализации автоматического сбора данных с пользовательских датчиков. Очень тесно завязан с планировщиком заданий и http сервером. Преследует только одну цель – избавить пользователя от внесения изменений в большую часть кода при составления собственного набора датчиков, в том числе не описанных в проекте, работающих на других шинах данных или с другими библиотеками. Также позволяет создавать программные сенсоры для вывода расчетных данных, например, абсолютная влажность или любой иной информации представленной в числовом виде. Это могут быть данные об уровне сигнала, напряжения питания или значение с аналогово порта. Помимо добавления сенсоров доступен поиск по списку всех сенсоров, проверка и изменения статуса (актуально только для i2c шины), получение последнего собранного значение с одного или группы сенсоров, аналогичная процедура для логов (активируются для каждого сенсора отдельно) и формирование списка в формате json из всех сенсоров с описанием всех необходимых характеристик. services.h - не является модулем. Содержит примеры реализации передачи показаний на внешние ресурсы на примере связи с MQTT брокером, а также передача данных через Rest API на такие ресурсы как "ThingSpeak" или "Народный мониторинг". tools.h - содержит набор вспомогательных утилит. webserver.h - Основная рабочая лошадка. Представляет из себя http сервер с реализацией API для обмена данными с WEB интерфейсом проекта, а также работающий с файлами во flash памяти микроконтроллера. Тесно связан со всеми модулями. Описание всего функционала заслуживает отдельного раздела. wifi.h - модуль описывает режимы работы Wi-Fi а также переключение между ними. Добавлена поддержка работы со скрытыми беспроводными сетями. В связи с тем, что целью было охватить все желаемые пользователями датчики, код был унифицирован и теперь поддерживает работу с любыми источниками данных. Примеры пользовательской конфигурации расположены в следующих файлах. users_auto.h - не является модулем. Содержит пример с реализацией выбора используемых датчиков с помощью подобия виртуальных переключателей ON/OFF. Также является примером как добавлять датчики в систему с использованием лямбда функций. Не совместим с users_bme280_x2.h users_bme280_x2.h - не является модулем. Содержи пример реализации работы с двумя датчиками BME280 на I2C шине. В отличие от users_auto.h, при добавлении нового датчика используются обычные функции. Не совместим с users_auto.h Изменения в WEB интерфейсе WEB интерфейс больше не запрашивает дублирующие файлы с внешних ресурсов, все необходимое для работы хранится на микроконтроллере. Список индикаторов на главной странице строится автоматически в зависимости от данных предоставленных объектом sensors через API. Добавлена поддержка двух групп датчиков – внешних и внутренних. Группа внешних сенсоров считается основной и отображается по умолчанию. Если зафиксировано наличие внутренней группы, то в меню будет добавлен переключает с индикацией выбранной группы. Исправлен баг с блокировкой доступа к панели управления из-за паразитных cookies различных систем аналитики. Изменен алгоритм работы системы защиты доступа к панели управления – реакция на брутфорс пароля или cookies, метод генерации соли и т.п. Также клиент получает соответствующее уведомление при блокировке доступа. В разделе основных настроек добавлена возможность изменять имя контроллера для MDNS протокола. Изменения вступят в силу в течении 10 минут или после перезапуска микроконтроллера. Найти устройство можно по этому имени в зоне ".local", по умолчанию "espws.local". Также в основных настройках добавлен пункт подтверждения пароля для домашней беспроводной сети. Его отсутствие было историческим упущением, но справедливость наконец восторжествовала. Раздел "Система" был расширен и теперь включает в себя всю информацию о текущем подключении. Также добавлена возможность динамического обновления некоторых данных, в список входят: уровень сигнала, напряжение питания и объем свободной памяти. В разделе обновления прошивки микроконтроллера ужесточена проверка контрольной суммы загружаемого файла, теперь нельзя загрузить программу без этих расчетов. Ранее просто выводилось предупреждение. Также увеличен список расшифровок ответа микроконтроллера в ходе обновления микропрограммы. В разделе "Файловая система" отображается корректный объем доступной flash памяти для внутренней файловой системы. Добавлен раздел для внешнего коллектора данных “ThingSpeak”. Пока доступен только ввод ключа для работы с API. По Вашим просьбам был добавлен раздел "Контроль состояния GPIO". Это пробный вариант конфигурации взаимодействия ESP8266 с внешней нагрузкой через WEB интерфейс. На данный момент в разделе присутствуют два параметра выставляющие границу включения внешней нагрузки при превышении установленных значений температуры или влажности. Доработана система оповещений. Мелкие правки и исправления ошибок в коде web интерфейса. В связи с тем, что старая реализация графика была нацелена на конкретные данные, унификация его кода на данный момент невозможна. График работает, но принимает строго указанные значения. Данная проблема будет решена позже. PS: Еще раз прошу отнестись с понимание и обратить внимание, что это тестовая версия. Спасибо.
  3. 5 баллов
    В продолжение темы будем пробовать подружить Arduino + RFID ридер MFRC522 c Ethernet и MySQL базой данных, в которой будут храниться наши ключи. Автором идеи является svchekalin. Это первый вариант реализации СКУД на Arduino с использование БД, уверен, что в дальнейшем получится значительно улучшить работу программы. Первым делом необходимо озаботиться созданием самой базы для ключей. Подразумевается, что раз Вас интересует вопрос хранения ключей не в EEPROM, а во внешней СУБД, то Вы имеете представление о MySQL, работе с ней и сам сервер базы данных у Вас имеется. Я не буду описывать тут процесс его установки и настройки т.к. эта тема не для этого раздела. Создадим базу данных с именем "test" и добавим в ней таблицу с именем rc522 со следующей схемой: CREATE TABLE IF NOT EXISTS `rc522` ( `uid` bigint(12) NOT NULL, `type` enum('0','1','2') NOT NULL DEFAULT '2', `description` varchar(250) DEFAULT NULL, UNIQUE KEY `uid` (`uid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; uid - содержит id ключа type - тип ключа. Может быть один из трех вариантов: 0 - ключ в базе, но деактивирован, 1 - мастер ключ, 2 - обычный ключ description - поле не используется в работе замка. Подразумевается, что в дальнейшем будет использоваться некая web форма для работы с ключами, и данное поле будет содержать некое описание, например ФИО владельца ключа. Первый ключ необходимо добавить самостоятельно. Код ключа можно узнать из консоли при попытки открыть замок. iT4iT CLUB (C) 2015 https://it4it.club Connected to server version 5.5.47-0+deb7u1 KEY: 3177510 access dany Disconnected. Чтобы добавить ключ 3177510 в базу и сделать его мастером необходимо выполнить SQL запрос: INSERT INTO `rc522` (`uid`, `type`) VALUES (3177510, '1'); База и таблица созданы, мастер ключ добавлен, переходим к монтажу электронной части. Я использовал Arduino UNO c Ethernet Shield на чипе W5100 (если Вы хотите подвязать ENC28J60, сразу советую отказаться от этой идеи). Сам шилд и библиотека Ethernet.h используют заранее определенные контакты SPI шины, это: 13 - SCK 12 - MISO 11 - MOSI 10 - SS В тоже время RFID сканер MFRC522 тоже использует SPI шину, и чтобы он чувствовал себя не ущемленным в правах, необходимо его пины SS и RST перенести: 13 - SCK 12 - MISO 11 - MOSI 9 - SS 8 - RST Все это дело будет выглядеть следующим образом. Переходим к скетчу. Для его работы понадобятся следующие дополнительные библиотеки: RFID-RC522 (NRF) Bounce2 (избавляет от дребезга контактов при нажатии кнопок) MySQL Connector (реализует работу с базой данных) Сам скетч Сразу хочу уточнить некоторые моменты. В программе Вам необходимо указать имя пользователя и пароль к MySQL серверу. Пользователь должен обладать достаточными правами для доступа к созданной в начале статьи базе. Также не забудьте указать IP адрес самого сервера в Вашей локальной сети. IPAddress server(10, 10, 10, 254); // IP адрес MySQL сервера char user[] = "login"; // MySQL username char password[] = "password"; // MySQL password Если Вы решили изменить имя базы или таблицы на какие-нибудь другие, то необходимо отредактировать константы, содержащие SQL запросы. const char QUERY_S[] = "SELECT type FROM test.rc522 WHERE uid = %s;"; const char QUERY_I[] = "INSERT INTO test.rc522 (uid) VALUES ('%s');"; Как видите, имя базы и таблицы указаны через разделитель точку ".", и в данном примере база имеет имя test а таблица rc522, что соответствует записи test.rc522 Алгоритм работы схож с предыдущими вариантами замка, за исключением того, что EEPROM в данной версии не используется. Соответственно и мастер ключ самостоятельно не создается, именно поэтому мы добавили его в базу руками. Связь с базой и последующая обработка ответа происходит с некоторой задержкой, это связано с производительностью контроллера, особенностями работы библиотеки, самой программы и т.д и т.п. В моем случае, время с момента начала считывания метки до реакции на неё занимало до 3 сек. Плюс ко всему, из-за определенных обстоятельств, MySQL сервер пришлось поднимать на Raspberry PI, а это далеко не лучший вариант для СУБД. В данный момент на одну аутентификацию метки требуется создать одно подключение и один запрос, это тоже увеличивает время реакции. Можно устанавливать соединение с базой при подачи питания на Arduino и просто клепать запросы. Такой вариант уменьшит время реакции в два раза, НО есть ложка дегтя в этой бочке. Если по каким либо причинам связь с сервером будет прервана (а оно так и будет, т.к. 100% гарантию дает только страховой полис), то контроллер зависнет при попытке выполнить заброс к БД. Проснуться он сможет только с помощью сторожевого таймера. В общем, этот момент еще будет проработан в следующих версиях замка. Думаю, что с нормальной СУБД время реакции уменьшится до 2 сек. Для входа в режим программирования необходимо, после того как замок разблокируется, удерживать мастер ключ еще 5 секунд у RFID сканера. Произойдет звуковой сигнал, а замок откроется, и будет находиться в таком состоянии пока Вы не выйдите из режима программирования (повторно удерживаем мастер ключ у сканера до звукового сигнала). В режиме программирования, как и в предыдущих версиях замка, все новые ключи будут записаны в MySQL. Все действия по-прежнему сопровождаются отчетами в Serial мониторе. Вот пример с попытками добавить существующий ключ в базу и добавлением нового ключа. IP: 10.10.10.97 # <- IP адрес полученный от DHCP сервера iT4iT CLUB (C) 2015 https://it4it.club Connected to server version 5.5.47-0+deb7u1 # <- Поднесен новый ключ. Подключаемся к MySQL серверу KEY: 26214177213 # <- ID текущего ключа у RC522 сканера access allow # <- Доступ разрешен (ключ в базе с меткой 1 - мастер) Disconnected. # <- Отключаемся от сервера * closed lock # <- Замок автоматически закрылся, НО КЛЮЧ ВСЕ ЕЩЕ У СКАНЕРА! MASTER PROGRAMMING MODE ON # <- После 5сек. Вход в режим программирования. Connected to server version 5.5.47-0+deb7u1 # <- Поднесен новый ключ. Подключаемся к MySQL серверу KEY: 204641111 # <- ID текущего ключа у RC522 сканера error: key elrady exists in eeprom # <- ID ключа уже прописан на сервере <!> Disconnected. # <- Отключаемся от сервера Connected to server version 5.5.47-0+deb7u1 # <- Поднесен новый ключ. Подключаемся к MySQL серверу KEY: 3177510 # <- ID текущего ключа у RC522 сканера add key in MySQL # <- ID ключа не найден в СУБД. Arduino завписывает новый ключ в базу. Disconnected. # <- Отключаемся от сервера Connected to server version 5.5.47-0+deb7u1 # <- ID текущего ключа у RC522 сканера KEY: 26214177213 # <- ID ключа найден в СУБД (ключ в базе с меткой 1 - мастер) Disconnected. # <- Отключаемся от сервера MASTER PROGRAMMING MODE OFF # <- Выходим из режима программирования PS: На данный момент это полностью рабочий вариант и отличная отправная точка для будущих изменений.
  4. 4 балла
    Доброе время суток. Вот небольшой спойлер, но работы ведутся совсем не такими темпами как мне бы хотелось, банально из-за нехватки времени в связи с переездом в другой город и со всеми вытекающими из этого событиями. Я постарался сделать снимок экрана так, чтобы, присмотревшись к косвенным признакам, была возможность понять, что уже реализовано и, что используется в коде. Последние изменения были сделаны еще в конце лета 2019. @kamikozz Рад, что Вы с таким азартом отнеслись к этому проекту. Но, к сожалению, Вы упустили главную мысль - проект модульный и wifi.h один из модулей с малым количеством зависимостей, а если быть точным, то от него не зависят другие модули вообще. Вы вправе вообще удалить его или полностью переписать согласно необходимой логике работы. Главная идея wifi.h, это балансировка между режимами AP и STA. Нормальным считается, что контроллер подключен к домашней беспроводной сети, если этот пункт не выполнен, то контроллер переходит в режим AP и периодически пытается найти домашнюю сеть. В этом режиме мы получаем возможность его перенастроить т.к контроллер мог потерять домашнюю сеть из-за того, что у неё изменился SSID или контроллер переехал на другое место жительства. В Вашем случае работа данного модуля немного противоречит тому, что Вы хотите получить т.к в случае отсутствия связи с домашней точкой доступа контроллер будет пытаться её найти, а это возможно только при переводе контроллера в режим STA для сканирования эфира. В Вашем случае в этом нет необходимости, и можно пользоваться штатными средствами восстановления связи, предоставляемыми на аппаратном уровне т.к для установки новой точки доступа в качестве домашней, достаточно подключиться к точке поднимаемой контроллером в режиме AP+STA, ведь она доступна всегда. Но у меня вопрос, зачем Вам режим AP+STA? Возможно лучше и надежнее подключить второй контроллер к общей с первым точке доступа и просто перекидываться через HTTP API запросами? Почему я это спрашиваю - дело в том, что я упоминал, в том числе и в первом посте, что мы ограничены количеством обрабатываемых контроллером запросов и при некоторой нагрузке все может поломаться. Кстати, именно по этой причине много кода WEB интерфейса размазано по малому количеству файлов, в Index.htm валяется и css и java, а в css сохранены некоторые картинки. Динамическая подгрузка компонентов. Все это позволяет уложиться в минимальное, как я это видел, количество tcp соединений с контроллером т.к браузер загружает все компоненты страницы параллельно, а текущий web сервер не способен обрабатывать более одного соединения за раз, да и у контроллера попросту нет на это ресурсов. Обязательно помните об этом. Но вернемся к wifi.h. Если Вам ближе режим AP+STA место центрального маршрутизатора для обоих контроллеров, то просто удалите wifi.h и в основном файле добавьте необходимый режим. Убедитесь, что имеете доступ со стороны AP и STA. После этого можете начинать прикручивать сохраненные в config значения параметров для поднятия точки с нужным именем и для подключения к домашней точке доступа. @Neon @den48rus давайте разбираться с NRF. Под рукой, в текущий момент, её нет, но мы попробуем и пробежимся по основным моментам. На сколько я понимаю, подключается она по SPI, а это значит, что потребуется много портов. Следовательно, Вам придется освободить все порты, используемые под управление нагрузкой, но скорее всего еще что-то. На фото ниже видны 5 основных портов для передачи данных и один для прерывания. В данном проекте придется использовать прерывания т.к NRF может получить данные в момент когда будет происходить другая длительная операция, например загрузка web интерфейса. В таком случае данные будут потеряны. Прерывание поможет получать данные в тот момент когда, они пришли и это будет незаметно для остальных процессов. Бегло, я нашел информацию, что прерывание генерирует низкий уровень сигнала на порту IRQ. Отследить его можно с помощью attachInterrupt. В функции, которая будет вызвана при прерывании реализуйте логику чтения данных, как это делается в обычном случае. А теперь самое интересное. Например, в библиотеки RF24.h, которую, как мне кажется, используют многие, возможно использовать свой тип данных для передачи. Таким образом Вы можете объявить свою структуру, в которой можно определить что угодно. Допустим не просто пустые и безликие данные, а тип сенсора, показания с нескольких датчиков и, например, напряжение питания удаленного устройства. struct { byte type; float temperature; float humidity; float voltage; } nrf_data; nrf_data remote_sensor; Теперь важный момент. Переменная, которую мы будем использовать для хранения данных (в примере remote_sensor), должна быть объявлена в глобальном пространстве имен чтобы избежать проблем в дальнейшем, конечно, если у Вас нет иного механизма передачи данных между модулями проекта. После того как данные будут переданы, они будут сохранены в оперативной памяти микроконтроллера. Теперь их необходимо связать с сенсором, а это уже совсем не сложно. sensors.add(new knob_t(0, 100, ".01", "Влажность", "%"), "Humidity", [&](){ return remote_sensor.humidity; } ); Конечно, могут быть ситуации, когда в момент чтения переменной будет произведена попытка её перезаписи, но и это можно решить. В общем, у Вас все должно получиться. Но если будут вопросы, то обязательно пишите, и я постараюсь найти NFR24 и подготовить полноценный код для решения этой задачи.
  5. 4 балла
    Доброе время суток Хорошая задачка. Полагаю, что Вы используете последнюю версия проекта. Решить задачу можно тремя способами и они потребуют физического доступа к контроллеру. В основном файле проекта, практически в самом начале, имеется описание констант отвечающих за инициализацию Serial монитора. /* Консоль */ #define console Serial // Обязательно закомментируйте эту строку перед финальной загрузкой программы #define consoleSpeed 115200 Если Вы не воспользовались подсказкой из комментария, то пароль засветится в консоли при рестарте контроллера. Еще один вариант, это затереть конфигурационный файл, но сделать это можно только загрузив по новой файлы WEB сервера. Эта операция полностью удаляет текущее содержимое области флешь памяти, выделенную под внутривенную файловую систему и записывает её новый образ. При этом файл конфигурации в образе отсутствует и будет создан самим контроллером в ходе выполнения программы. Данные авторизации будут сброшены по умолчанию - admin\admin Еще один способ подразумевает обновление программы микроконтроллера и игнорирование части конфигурационного файла или его удаление, но тогда обновлять программу придется дважды. Второй раз чтобы откатить изменения и восстановить функционал. Для этого в файле webserver.h найдите функцию bool http::authorized() она отвечает за проверку авторизации пользователя с помощью cookies. Приведите её к следующему виду. bool http::authorized() { return true; } После загрузки программы Вы сможете зайти в панель управления обойдя форму авторизации и изменить пароль. Данный способ хорош если Вам необходимо сохранить ключи доступа к внешним серверам и т.п В Вашем случае другого способа перехватить пароль нет т.к он передается только от пользователя к микроконтроллеру и никогда в обратную сторону. Подбор пароля тоже усложнен т.к лимит попыток входа ограничен и Вы вероятно спровоцируете тревогу поднятую функцией bool http::security() её описание и подробный комментарий также можно посмотреть в файле webserver.h Это первое, что приходит в голову, но если вы найдете другой способ, то дайте знать, буду очень признателен. Теперь о графиках и выхода за приделы суточного интервала. Графики отъедают очень много памяти, да и сам проект про то как получилось у меня, а не как стоит делать, но все же. Вам предстоит внимательно поработать с несколькими файлами: Файл sensors.h в котором описана логика работы с сенсорами. В описании класса sensors имеется приватная переменная содержащая размер массива выделяемого под хранение лога для каждого сенсора в котором эти самые логи активированы. byte logSize = 144; Значение 144 выбрано исходя из интервала между точками на графике, который равен 10-и минутам. Полные сутки содержат 144 значение. Чтобы увеличить количество выделенной памяти, необходимо увеличить это значение. Увеличьте это значение до адекватного и необходимо для Вас значения, главное, чтобы оно было кратно 144. byte logSize = 432; // Вариант для трех дней byte logSize = 144 * 5; // Или иной вариант записи для 5-и дней (по мне такой вариант записи более предпочтителен) Главное не перегнуть палку, всегда следите за памятью. Файл users_auto.h или users_bme280_x2.h или Ваш файл, в котором описаны используемые сенсоры. Вот пример описывающий датчик температуры. sensors.add(T, device::out, 0x76, "out_temperature", out_init, out_temp, true); Последнее значение метода add, то которое true, указывает, что необходимо вести логи. У тех сенсоров, для которых не требуется видение логов, не указывайте это значение вообще или измените его на false. Оставьте только действительно необходимые логи. Файл index.htm содержит две функции в которых производится построение графика $(".sensor .log").click(function(){ /* ... */ }); $("#graph").click(function() { /* ... */ }); Обе эти функции содержат расчетное временное значение первой точки графика в мс. new Date().getTime() - obj.timeAdjustment - 143 * 10 * 60 * 1000; Необходимо сдвинуть его на выбранный вами интервал времени, например, три дня. new Date().getTime() - obj.timeAdjustment - (144 * 3 - 1) * 10 * 60 * 1000; Вроде бы на этом все, надеюсь не обсчитался в точках. Сохраняем и обновляем программу и файлы. Что касаемо самих файлов WEB сервера и их упаковки: Как все уже правильно заметили, файлы упакованы только для уменьшения их размера, можно использовать их без сжатия. Но при наличии у микроконтроллера сжатого файла и его не сжатой копии, приоритет будет отдан сжатому файлу и именно он будет отдан пользователю при загрузке страницы. Оригинальные файлы сжаты с помощью архиватора 7-Zip. Формат сжатия GZIP, уровень сжатия Ультра (максимально возможный). Исходный код файлов написан в кодировке UTF-8 Сугубо мое мнение: если Вы хотите внести серьезные изменения в код, то стоит воспользоваться специализированным редактором, который сможет предупредить об опечатки или нарушении синтаксиса. Рекламировать ничего не буду, в сети множество редакторов для WEB разработок с поддержкой HTML и JavaScript
  6. 4 балла
    Друзья. Спасибо Вам за проявленный интерес к проекту. Хочу еще раз напомнить, что следующее обновление будет очень большим, своего рода v2.0 для всего проекта. В связи с этим, практически все исправления в теме станут не актуальны как в плане доработки, так и в плане их использования для собственных наработок.
  7. 3 балла
    Обновление по просьбе Alex13 находится тут Открытие/Закрытие разнесены на разные пины микроконтроллера (для управление соленоидом) Обновление по просьбе Alex13 находится тут Добавлен выбор режима закрытия замка (автоматический или по карте) Добавлена сигнализация оповещающая о попытках подбора ключа Обновление по просьбе svchekalin находится тут Добавлен Ethernet Shield на чипе W5100 Ключи теперь хранятся не в EEPROM контроллера, а в MySQL базе на удаленном сервере ... Внимание: Очень много фотографий в статье! Начнем с предыстории. В один обыденный рабочий день ко мне обратились мои друзья и по совместительству коллеги по работе с идеей сделать замок с радиочастотной идентификацией. Электронный замок должен обслуживать дверь в рабочее помещение. Все бы хорошо, но дверь далеко не домашняя, сделана из метала и стоит в металлической коробки. Собрать электронную начинку замка и написать программу для микроконтроллера - решаемая задача, но как механически удержать такого монстра в зафиксированном состоянии? Но то, что для меня казалось проблемой, было воспринято моими друзьями с ухмылкой, и мне показали здоровый электромагнит. Точно такие же электромагниты используются в домофонах. Даже не хочу знать, откуда они его достали, но меня увиденное воодушевило. Задача поставлена, приступаем к реализации! Техническое задание Замок должен аутентифицировать хозяев без физического контакта пользователя с устройством Память должна вмещать не менее двух десятков ключей Устройство должно иметь возможность добавлять в память новые ключи Добавлять новые ключи можно только, используя специальный, мастер ключ Мастер ключ должен также иметь возможность открывать замок Должна быть реализована возможность обнуления списка используемых ключей, в том числе и удаление мастер ключа Замок должен иметь возможность открываться изнутри по нажатию на кнопку (как в домофоне) Все описанные пункты должны быть просты в использовании и не требовать знания программирования Реализация За основу было решено взять клон Arduino UNO с ATmega328p на борту в паре с RFID (NRF) сканером RC522. Сам сканер является очень удачным выбором т.к работает на частоте 13.56 МГц и поддерживает чипы: MIFARE S50 MIFARE S70 MIFARE UltraLight MIFARE Pro MIFARE DESfire ... Данные чипы используются в различных карточках метро и прочего общественного транспорта, ключах современных домофонов, различных умных браслетах и носимой электроники. У братьев Китайцев можно купить даже кольца с RFID (NRF) меткой. Некоторые чипы имеют энергонезависимую память небольшого объема. Прокручиваем решение в голове Хранить все ключи будем в энергонезависимой памяти микроконтроллера (EEPROM). Хорошее и как мне кажется единственное решение. ATmega328p имеет 1kB памяти, RFID (NRF) ключи содержат уникальный номер размером от 4 до N байт. Если уровнять все типы ключей, то читать мы будем только первый четыре байта любого ключа. Делаем вывод, что 1024/4=256 ключей. Но необходимо знать точное их количество чтобы не читать пустую память, иначе можно взломать замок так, как это делается с некоторыми домофонами, а именно - передать ключ, состоящий из одних 0 или 255 и Вуаля! Выделим один и по совместительству первый байт в EEPROM под число с количеством ключей и получаем (1024-1)/4=255,75, а это 255 полноценных четырехбайтных ключей! Это более чем достаточно, хоть домофон делай. Добавлять ключи будем путем записи его первых четырех байт, в свободную память микроконтроллера, начиная с N+1 занятого байта памяти Arduino. Но делать это необходимо только с использованием мастер ключа. И тут встают два вопроса, какой из ключей должен быть мастером и как его найти среди кучи всех остальных? А пусть мастер ключ хранится в строго определенных "ячейках" памяти микроконтроллера, мы ведь делаем это с количеством ключей! Пусть первый байт EEPROM отвечает за количество известных нам ключей, а следующие четыре байта будут отведены мастер ключу. Оставшуюся память отдаем под все остальное. Открытие дверей. Как понять, что поднесенный к сканеру ключ является тем самым или наоборот. Давайте опять отталкиваться от идеи четырехбайтного ключа. Пройдя все предыдущие этапы записи памяти микроконтроллера, мы с 100% точностью можем сказать, сколько ключей и как они расположены в памяти Arduino. Следовательно, для быстрого сравнения логичнее искать совпадение по первому байту каждого ключа в памяти, и только если оно найдено переходить к сравнению следующего байта. Если какой либо из 4 байт не совпал, то останавливаем проверку и переходить к следующему ключу в памяти микроконтроллера. Если найдено совпадение всех четырех байт ключа, то прекращаем проверку и устанавливаем замок в состояние открыто, иначе оставляем замок запертым. Пройдя эту не хитрую процедуру, мы можем точно сказать разрешен данному ключу доступ или нет, а заодно является ли он мастер ключом. Ведь мы будем знать номер совпавшего ключа в памяти Arduino следовательно, если он первый (на самом деле нулевой), то это волшебный ключ. Чтобы добавить новый ключ в память замка необходимо поднести и удерживать у RFID (NRF) сканера мастер ключ. Для начала будет открыта дверь, чтобы впустить владыку в обитель. Но если мастер ключ удерживается в течение 5 секунд (по умолчанию), то замок переводится в постоянно открытое состояние и система распознавания ключей, описанная ранее, начинает работать как проверка наличия ключа в памяти. Ключа нет, тогда записываем его. Ключ найден, значит, ругаемся, плюемся и топаем ногами. Таким образом, можно добавлять ключи пачками. Для выхода из режима программирования необходимо поднести ключ владыки и удерживает его 5 секунд. Для очистки памяти решено ввести красную кнопку с защитой от ложного нажатия. Если удерживать её в течение 5 секунд, то контроллер начинает перезапись EEPROM одними нулями. По окончанию операции производится перезапуск программы микроконтроллера. Но теперь нет ни единого ключа, следовательно, и мастера тоже. Непорядок! В этом безмятежном состоянии замок стоит держать постоянно открытым иначе "Се Ля Ви", что в переводе с древнегреческого "не повезло"! Первый поднесенный к сканеру ключ будет записан в память Arduino и станет мастером т.к его порядковый номер - 0. Следом за этим замок перестанет бездельничать и перейдет в состояние закрыто. С этого момента помещение считается святым, и проникнуть в него может только обладатель единственного записанного в память ключа. Для всех остальных нужно начать процедуру добавления ключей, но её мы уже придумали. Открытие двери изнутри по нажатию на волшебную кнопку поначалу показалось мне тривиальной задачей, и я добавил этот механизм простым способом (как и кнопку очистки памяти) - ногу микроконтроллера посадил через резистор на землю, а сама кнопка коммутировала на эту же ногу +5V. Все дешево и сердито, но вся соль кроется в деталях! Кнопок открытия двери будет несколько. Все они должны сидеть параллельно и самая дальняя будет расположена как минимум в 15, а то и больше, метрах от контроллера (если мерить длинной кабеля)! Это расстояние смело можно умножать на 2 и получить нереальную для +5V цифру. Необходимо пересадить ногу Arduino с GND на +5V (через резистор 10k), предварительно задействовать встроенный подтягивающий резистор микроконтроллера, а сама кнопка станет прижимать ногу к земле. Резистор между ногой и питанием необходим для избегания короткого замыкания при использовании самой кнопки. Управление электромагнитом, по понятным и так причинам, происходит через реле. Электромагнит подключен через постоянно замкнутую группу контактов и соответственно при открытии замка, на реле подается логическая единица. Это удобно т.к не приходится постоянно держать реле под напряжением, но есть и обратная сторона медали – если нет питания на контроллере, а на электромагните есть, ты открыть замок станет очень проблемной задачей. В общем, Вам самим выбирать какой из подводных камней оставить. Я свой выбор сделал. Схема подключения - РАСПИНОВКА ---------------------------------------------------------------------------- MFRC522 Arduino Arduino Arduino Arduino Arduino Reader/PCD Uno Mega Nano v3 Leonardo/Micro Pro Micro Signal Pin Pin Pin Pin Pin Pin ----------------------------------------------------------------------------------------- RST/Reset RST 9 5 D9 RESET/ICSP-5 RST SPI SS SDA(SS) 10 53 D10 10 10 SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 ----------------------------------------------------------------------------------------- Оставлю дополнительные фото для наглядности. На самом деле, если вы будите внедрять подобное где-то в обиходе, а не просто собирать на столе, то обязательно все документируйте и перепроверяйте по несколько раз. Для быстрого монтажа я использовал плату для прототипирования. Цена на неё довольно завышена у братьев Китайцев, но я не пожалел. Перед установкой всего это добра на заслуженное рабочее место проводились испытания различных кабелей для выноса рабочей части (RFID сканера) за стену. В итоге выбор остановился на медной, многожильной витой паре используемой для прокладки Ethernet. Если использовать одножильную (моно) витую пару, то потери могут быть довольно высоки, как и с использованием различных Китайских (якобы медных) шлейфов. Гарантию работы, а соответственно и Вашего попадания в помещение, сможет гарантировать лишь страховой полис. Сам сканер был помещен в крышку от металлической коробки и закрыт стеклотекстолитом, естественно НЕ фольгированным! Полученный результат показался мне довольно сносным и был передан заказчику для установки. Для питания был задействован компьютерный блок питания, с которого, через стабилизатор напряжения 12v в 8v для запитки Arduino UNO через стандартный 5,5мм разъем. Фото монтажа За дверью все выглядит очень скромно. Т.к. сканер находится в просторном корпусе, то на него была прикреплена кнопка для электронного звонка. Довольно эстетически приятный вид, для промышленного помещения. Программная часть Вам понадобятся следующие библиотеки: RFID-RC522 (NRF) Bounce2 (избавляет от дребезга контактов при нажатии кнопок) Хотите помочь проект? Yandex.Money PayPal.me Сам скетч Все довольно плотно закомментировано, но есть большой фронт для доработки. Надеюсь, Вы дополните это создание своими идеями и нужным функционалом, а я в свою очередь уже присмотрел идеи для будущего обновления и заказал новый модуль RC522 для теста. PS: Желаю Вам приятного и надеюсь полезного использования.
  8. 3 балла
    Файлы проекта обновлены. Добавлена поддержка последних, на момент публикации, версий Arduino IDE и модуля ESP8266. Добавлены небольшие исправления и доработки. При использовании, указанных в основном посте, версий программных компонентов Вы не получите вылет программы с критической ошибкой. Исправлена серьезная ошибка в медианном фильтре, кто использует проект обязательно обновите у себя объект medianFilter_t, он находится в tools.h В разделе загрузок, добавлена утилита для загрузки файлов web сервера во flash память. Также в описании к файлам, добавлена ссылка на скачивание готовой Arduino IDE со всеми библиотеками, утилитами, и последней версией проекта. Для работы модуля загрузки файлов во Flash может понадобится последняя версия Python https://www.python.org/downloads/
  9. 3 балла
    Вот тут настраиваешь, и вставляешь в index.htm... мой выглядит так <a class="weatherwidget-io" href="https://forecast7.com/ru/51d3037d84/stary-oskol/" data-label_1="СТАРЫЙ ОСКОЛ" data-label_2="прогноз" data-font="Arial" data-icons="Climacons" data-theme="original" data-basecolor="" data-shadow="rgba(0, 0, 0, 0.65)" data-accent="rgba(255, 255, 255, 0.03)" data-highcolor="#febc2f" data-lowcolor="#0200ff" data-mooncolor="#c7c7c7" data-cloudcolor="#ffffff" data-cloudfill="#0003ff" data-raincolor="#0200ff" data-snowcolor="#000000" >СТАРЫЙ ОСКОЛ прогноз</a> <script> !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src='https://weatherwidget.io/js/widget.min.js';fjs.parentNode.insertBefore(js,fjs);}}(document,'script','weatherwidget-io-js'); </script>
  10. 3 балла
    @Вадим, вот есть ещё такой вариант с прогнозом погоды...
  11. 3 балла
    Два датчика BME280, изменения в файле index (направление ветра словом). Если кому надо... P. S. ветер, направление, облачность- подтягиваются сразу. Wether with wind direction .7z
  12. 3 балла
    Привет друзья. В данной теме пойдет речь о конфигурации микроконтроллера через UART (Universal Asynchronous Receiver-Transmitter) интерфейс. А рассмотрим мы это на примере MQTT логгера. В данном случае, это будет логгер температуры. Мне это устройство потребовалось на работе, даже не мне, а моим коллегам, и оно действительно работает и приносит огромную пользу т.к контроль температуры производится совместно с отличной, на мой взгляд, системой мониторинга Zabbix с оперативными оповещениями, построением графиков, блэк-джеком и... Подробнее о дружбе Arduino и Zabbix можно почитать тут Но как всегда, есть нюансы. А заключаются они в том, что в будущем, обслуживать армию мелких контроллеров придется людям, которые заняты своими задачами и им попросту некогда изучать Arduino, не говоря уже о серьезных альтернативах, разбираться в том, как прописать нужные значения переменных в программу и загрузить её в микроконтроллер. Все настройки необходимо производить быстро, с явным указанием изменяемого параметра и его значения. Ровно также, как это делается с любым промышленным оборудованием. И тут на помощь приходит UART Микросхема UART to USB имеется в большинстве плат семейства Arduino, а там, где её нет, обычно выведены соответствующие "пины". И все это очень облегчает жизнь т.к позволяет общаться с контроллером, просто подключив его к компьютеру напрямую или через переходник, благо их везде навалом, да и стоят они как пачка семечек. Остается только запустить любой терминал, который умеет доставлять в конец строки символ "перевод строки", что известен в народе как "\n", а в ASCII таблице имеет номер 0A. Кстати, в Serial мониторе Arduino IDE выставить символ конца строки можно так Ну а дальше только, что и остается, как общаться с устройством на той стороне. И тут мы переходим к основному алгоритму программы. Но перед этим хочу отметить, и это ВАЖНО, что за любое упрощение жизни, всякие красивости и прочее, приходиться платить, и цена довольно высока! В данном случае, это ОЗУ микроконтроллера. Поэтому не раскатываем губы, а если очень хочется, то берем следующий по характеристикам микроконтроллер. А начинать мы будем с ATmega328P, что известен в народе как Arduino UNO, Arduino Nano, IBoard v1.1 и т.д по списку. Заканчивать Вы можете чем угодно, хоть ATmega2560, ESP8266 или ESP32. В противном случае, производим оптимизацию кода, отказываемся от громоздких библиотек, или вообще, от Arduino IDE. Что мы хотим получить Вся конфигурация микроконтроллера должна храниться в энергонезависимой памяти (ПЗУ) известной нам как EEPROMM. Если в ПЗУ конфигурация отсутствует, необходимо иметь резервный план. И им станет сброс конфигурации на настройки по умолчанию. Это поведение знакомо всем, особенно по домашним дешевым маршрутизаторам, а значит, интуитивно понятно. Выводить справку при начале общения пользователя и устройства, на мой взгляд, как манеры высшего общества. Контроллер должен представляться и сообщать всю необходимую информацию о себе и о том, как с ним вести диалог. Все команды должны быть просты и иметь не двусмысленное значение. И конечно, мы должны иметь возможность просмотра текущего состояния датчиков или процессов, которыми занимается устройство в свободное от общения с нами время. Как сохранять конфигурацию в EEPROM Пожалуй, стоит начать с того, как сохранить конфигурацию микроконтроллера в энергонезависимую память. Для этих целей, в стандартный набор инструментов Arduino IDE входит библиотека для работы с EEPROM. #include <EEPROM.h> На данный момент нас интересуют две функции, это чтение и запись EEPROM.get(address, variable); EEPROM.put(address, variable); Обе принимают два параметра: Адрес, начиная с которого будет произведено чтение или запись данных в память Переменная чье содержимое надо сохранить или в которую нужно из памяти прочитать Особенность работы этих функция заключается в том, что в зависимости от типа переданной им переменной во втором параметре, будет произведено чтение или запись ровно того количества данных которое соответствует размеру типа этой самой переменной. На простом языке это означает, что если переменная variable будет иметь типа byte, то и работать мы будем с объемом памяти в 1 байт. И тоже самое произойдет с абсолютно любым типом данных пока мы не упремся в размеры самого EEPROM или ОЗУ микроконтролера. Из этого всего следует, что мы можем создать свой собственный тип данных, разместить в нем необходимую нам информацию и всего лишь двумя функциями помещать его в память и извлекать обратно. И в этом нам поможет пользовательский составной тип - структура (struct). Данный тип позволяет объединить в себе различные типы данных, упорядочить их и присвоить им понятные имена. Это общий пример для большего понимания, как объединить несколько типов данных в одной структуре, получить к ним доступ, записать и прочитать их из EEPROM. Наша структура будет немного сложнее, но суть остается той же самой. // Дополнительная структура описывающая IPv4 адреса struct addres { byte a; byte b; byte c; byte d; }; // Структура объекта конфига для хранения в EEPROM struct configObj { addres ip; addres subnet; addres gateway; addres dns; byte mac[6]; byte hex; char server[40]; char topic[40]; } config; Данная структура хранит сетевые настройки для работы с Ethernet модулем (w5100 и выше) Arduino, базовые настройки для связи с MQTT брокером. Сразу при описании структуры мы объявили новую переменную с именем config с типом нашей структуры. ВАЖНО: кроме наших данных в структуре имеется дополнительная переменная с именем hex. Её задача, это контроль наличия наших данных в EEPROM. Она всегда должна содержать одно и тоже значение. Представьте ситуацию, что вы взяли контроллер в EEPROM которого находится какая-либо информация (может там чисто, но мы этого не знаем наверняка) и мы прочитаем данные и поместим их в нашу переменную. В итоге мы получим данные которым нельзя доверять, а что еще хуже, это если эти самые данные нарушат работу внешнего оборудования. Более правильным, на мой взгляд, будет проверка значений по конкретно определенным адресам. Например, мы знаем, что в 16 байте должно быть значение 0xAA и если оно действительно там, то мы убеждаемся, что это наша информация. Естественно, что контрольных точек может быть несколько и разумеется с разными значениями, это увеличит гарантию того, что данные являются нашими, но 100% гарантии не даст. Для более серьезных проектов есть более серьезные методы, например, подсчет контрольной суммы всего набора данных. Также структура может иметь вложенные структуры, у нас ими являются: ip, subnet, gateway, dns. Вы можете отказаться от такого варианта и записывать данные просто в массив байт, как это было сделано с MAC адресом. Естественно, что обращаться к этим полям нужно по-разному. Запись данных в поле subnet config.subnet = {255, 255, 255, 0}; Запись данных в поле mac byte mac[] = {0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02}; memcpy(config.mac, mac, 6); С записью данных в поле server все еще проще config.server = "mqtt.it4it.club"; Функция, которая возвращает нашу структуру данных с полностью заполненными полями. // Начальный конфиг configObj defaultConfig() { configObj config = { {192, 168, 0, 200}, {255, 255, 255, 0}, {192, 168, 0, 1}, {192, 168, 0, 1}, {0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02}, 0xAA, // Не трогать! Используется для проверки конфигурации в EEPROM F("mqtt.it4it.club"), F("arduino/serial/config") }; return config; } К примеру, два последних значения записывать не обязательно, тогда эти поля останутся пусты если использовать данную функцию для возврата к "заводским" настройкам. Вот пример того, как используя описанную нами структуру, мы проверяем целостность настроек в EEPROM и в случае не совпадения hex значений, загружаем настройки по умолчанию. const byte startingAddress = 9; bool configured = false; void loadConfig() { EEPROM.get(startingAddress, config); if (config.hex == 170) configured = true; else config = defaultConfig(); configEthernet(); // Функция производящая настройку сети } Как контроллеру начать понимать, что от него хотят В Arduino имеется функция, вызываемая каждый раз, когда в передаваемый буфер данных попадает знакомый нам символ перевода строки. void serialEvent() { // Вызывается каждый раз, когда что-то прилетает по UART // Данные передаются посимвольно. Если в строке 100 символов, то функция будет вызвана 100 раз } И в контексте обсуждаемой нами программы, мы можем представить ее в следующем виде void serialEvent() { serialEventTime = millis(); if (console.available()) { char c = (char)console.read(); if (inputCommands.length() < inputCommandsLength) { if (c != '\n') inputCommands += c; else if (inputCommands.length()) inputCommandsComplete = true; } } } Её задача, символ за символом, собрать в кучу все переданные нами данные и при получении заветного символа перевода строки (именно он даст нам понять, что передача сообщения завершена) сообщить, что команда получена и передать накопленный буфер данных своей напарнице по цеху. Но перед тем как это сделать стоит рассмотреть альтернативную ветку развития событий, а именно тот факт, что нам попросту могут прислать огромную, кучу шлака без волшебного символа, а раз могут, значит рано или поздно пришлют. И мы бесполезно потратим ценные ресурсы микроконтроллера, что может привести к непредсказуемым результатам в дальнейшем. Поэтому, в логику функции, мы добавим дополнительное ограничение на количество переданных символов, если оно достигнуто, то попросту перестаем воспринимать последующие данные. Останется только избавиться от них, и самым удобным моментом будет, когда этот поток шлака прекратиться. Чтобы об этом узнать мы будем запоминать время, когда пришел каждый из символов переданной строки перезаписывая соответствующую временную переменную данными о следующем символе и т.д пока поток не иссякнет. И как только расхождение текущего времени CPU и времени, когда поступил последний символ превысит некоторое значение, пусть это будет 1 секунда, мы очистим нашу память. Этот простой механизм напоминающий амнезию позволит избавить нас от лишних проблем. Переменная отвечающая за размер принимаемого буфера const byte inputCommandsLength = 60; Теперь можно переходить к напарнице предыдущей героини и, по совместительству, основной рабочей лошадки - функции обрабатывающей адекватно полученные данные. void serialEventHandler() { // вызывается в loop и проверяет взведена ли переменная inputCommandsComplete // в полученных данных пытается распознать команды } По началу я хотел описать данную функцию в упрощенном варианте, но в процессе понял, что ничего хорошего из этого не выйдет, и я решил описать только ключевые моменты, но их будет достаточно, на мой взгляд. Разбор serialEventHandler Полученные данные будут переданы нам в переменной inputCommands с типом String В первую очередь стоит почистить ее от лишних пробельных символов. Они часто встречаются в начале и в конце строки если пользователь копирует текст, а не набирает его самостоятельно. Это распространенная ситуация, приводящая к отказу принятия команды и бороться с ней очень просто. inputCommands.trim(); Далее стоит отсеять команды, не несущие никакой динамической информации, например, help, restart, reset и т.п это предписывающие команды которые заставляют контроллер выполнять строго описанные функции без вмешательства в их работу. if (inputCommands == F("help")) { consoleHelp(); } else if (inputCommands == F("restart")) { resetFunc(); } else { // Все сложные команды обрабатываются в этом блоке } Как Вы видите, все очень просто и скучно. Но не в том случае если команда динамическая, то есть содержит не только саму команду (заголовок) но и полезную нагрузку (параметр) которая может меняться раз от раза. Простой пример это команда изменения ip адреса и её варианты: ip 37.140.198.90 ip 192.168.0.244 ip 10.10.10.88 В данном случае, нам стоит понять, относится ли данная команда именно к ip адресу. Для этого в наборе String имеется отличный метод, позволяющий производить сравнение переданного ему параметра с началом строки. if (inputCommands.startsWith(F("ip"))) { // Строка inputCommands начинается с пары символов "ip" } Если все идет так, как мы задумали, то нам стоит отделить динамическую часть - наш параметр, от заголовка и получить полезную нагрузку. В этом нам поможет, опять же из набора String, метод substring позволяющий получать часть строки с указанием начального и конечного символа подстроки. Последний параметр указывать не обязательно и в таком случае мы получим всю строку начиная с указанного символа. inputCommands.substring(4) В данном случае начиная с 4-его и заканчивая последним. И как Вы успели заметить, отсчет мы начинаем не с третьего символа, что соответствует нашей строке без вступительного "ip", а на один больше т.к между заголовком и параметром имеется разделяющий символ в виде пробела. Далее, полученную строку мы передадим в функцию, занимающуюся разбором на компоненты и принимающую следующие параметры: Указатель на переменную с типом char, для этого нам потребуется преобразовать наш тип String Символ разделителя, что для IPv4 является точка "." Указатель на массив типа byte, которому будет присвоен результат разбора Количество искомых элементов в строке И система счисления, подразумеваемая в качестве исходной для записи элементов подстроки /* Парсинг https://stackoverflow.com/questions/35227449/convert-ip-or-mac-address-from-string-to-byte-array-arduino-or-c */ void parseBytes(const char* str, char sep, byte* bytes, int maxBytes, int base) { for (int i = 0; i < maxBytes; i++) { bytes[i] = strtoul(str, NULL, base); str = strchr(str, sep); if (str == NULL || *str == '\0') break; str++; } } В нашем случае выглядеть это будет следующим образом byte ip[4]; parseBytes(inputCommands.substring(4).c_str(), '.', ip, 4, 10); А дале все становится еще проще, попросту проверить попадает ли наш ip адрес, в список правильных адресов. И самой простой проверкой послужит проверка первого байта адреса на несоответствие не угодным нам сетям (0, 127, 255) if (ip[0] != 127 and ip[0] != 255 and ip[0] != 0) { // Производим необходимые нам действия с ip адресом, например, запись в конфиг config.ip = {ip[0], ip[1], ip[2], ip[3]}; } Вы в праве реализовать собственные проверки, какие только душе угодны. Также хотелось бы отметить, что обрабатывать некоторые параметры проще и быстрее через их короткие записи. К таким можно отнести маску подсети устройства. Например, привычный дня нас адрес 192.168.0.1 с маской подсети 255.255.255.0 можно записать в виде 192.168.0.1/24, где цифра 24 указывает нашу подсеть в краткой форме. А, следовательно, мы можем записать несколько кратких форм масок подсети в следующем виде: subnet 255.255.255.0 или subnet 24 subnet 255.255.0.0 или subnet 16 subnet 255.0.0.0 или subnet 8 Это основные маски, и я не описывал все существующие т.к в этом нет нужды, но если Вам интересно, то почитать про них можно в wikipedia. if (inputCommands.startsWith(F("subnet"))) { String input = inputCommands.substring(8); if (input == F("24")) config.subnet = {255, 255, 255, 0}; else if (input == F("16")) config.subnet = {255, 255, 0, 0}; else if (input == F("8")) config.subnet = {255, 0, 0, 0}; else { // Все остальные маски попадают в этот блок byte subnet[4]; parseBytes(input.c_str(), '.', subnet, 4, 10); config.subnet = {subnet[0], subnet[1], subnet[2], subnet[3]}; } } MAC адрес хранится у нас в виде массива байт. Его перезапись другим массивом производится с помощью функции memcpy if (inputCommands.startsWith(F("mac"))) { byte mac[6]; parseBytes(inputCommands.substring(4).c_str(), ':', mac, 6, 16); memcpy(config.mac, mac, 6); } Изменение адреса MQTT сервера if (inputCommands.startsWith(F("server"))) { String server = inputCommands.substring(8); server.trim(); if (server.length() < 40) server.toCharArray(config.server, 40); } В принципе теперь понятно, как производить получение, разбор и сохранение конфигурации в EEPROM микроконтроллера. Как это выглядит на практике Заливаем программу в микроконтроллер и подключаемся к Arduino по usb или через переходник. Открываем терминал и нас приветствуют краткой справкой с описанием доступных команд. - --------------------------------------------------------------------------------------- # Sensor with data sending to mqtt server (c) it4it.club # Use the "config" command to view the current configuration # To change the configuration, specify the parameter name and its new value with a space, # for example "ip 192.168.0.200", "subnet 255.255.255.0" or "mac AA:BB:CC:DD:EE:FF" # You can also specify a subnet using the mask 24, 16 or 8 # Additional commands: # sensors - view current data from sensors # config - view current configuration # save - saves the current configuration # reset - resets all settings # restart - restarts the device # eeprom clear - removes all contents of eeprom # help - view this help - --------------------------------------------------------------------------------------- Т.к. в EEPROM микроконтроллера не была обнаружена конфигурация (волшебный hex байт нам подсказал), то были задействованы стандартные настройки. Просмотреть текущую конфигурацию можно командой config config # ip: 192.168.0.200 # subnet: 255.255.255.0 # gateway: 192.168.0.1 # dns: 192.168.0.1 # mac: 00:AA:BB:CC:DE:02 # server: mqtt.it4it.club # topic: arduino/serial/config чтобы изменить значение любого из этих параметров необходимо передать имя параметра и его новое значение, разделенные между собой пробелом. ip 10.10.10.99 # ok gateway 10.10.10.1 # ok dns 10.10.10.1 # ok После окончания конфигурации необходимо сохранить настройки и если были затронуты критические параметры, например, сеть, то перезапустить Arduino соответствующей командой. save # ok restart # ok # restarting device... Если параметр был успешно принят, то контроллер ответит нам "ok", а в противном случае ругнется. ip 127.0.0.1 # bad ip Также мы получим негативный ответ если команда не была распознана. qwerqwer1243 # bad command С остальными командами Вы разберетесь самостоятельно. Исходник: MQTT_CLIENT_328_SERIAL_CONFIG.zip PS: в общем то это статья родилась только для того, чтобы в соседнем форуме с системой мониторинга Zabbix появилась ссылка на устройство, но я надеюсь, что она также станет полезна любителям домашней автоматизации и не только.
  13. 3 балла
    Для того, чтобы motion стартовал автоматически при запуске системы, попробуйте добавить разрешение на запуск юнита в systemd systemctl enable motion или /lib/systemd/systemd-sysv-install enable motion перезапускаем систему и смотрим вывод service motion status
  14. 3 балла
    Добавлю свою маленькую лепту в проэкт. Немного поправил скетч и теперь замок пишет в две дополнительные таблицы события разрешенных и запрещенных действий т.е. ключ в базе и при доступе записывается его айди и время дата доступа в табличку allow также если ключа нет в базе он записывается аналогично в табличку deny. Накрапал коекакой php код который отображает данные таблиц и может дабавить ключ в базу. скетч содержание файла mysql php список ключей и форма добавления ключа думаю странички allow и deny добавлять смысла нет так как это часть кода выше
  15. 3 балла
    Данный пост является шпаргалкой из собранных в сети различных материалов связанных с распиновкой (pinout) распространенных микроконтроллеров и плат на их основе. Микроконтроллеры ESP8266EX ESP32 (R1) Платы ESP-01 ESP-07 Данная плата практически полностью идентична ESP-12X, разница только в наличие керамической антенны и разъема IPX для подключения внешней антенны. ESP-12 (E/F) NodeMCU ESP32 Board ESP32-WROOM-32 (DevKitC)
  16. 2 балла
    Доброе время суток. Сегодня мы будем собирать бесконтактный замок с использованием NFC контроллера PN532. Опираясь на опыт прошлого варианта (на контроллере MFRC522) и на отзывы тех, кто пытался повторить схему, были сделаны определенные выводы. Постараемся избавиться от старых подводных камней и поищем новые И так, что мы знаем о PN532: Очень компактный размер 42.7 x 40.4 мм Поддерживает работу по SPI, i2C и HSU (высокоскоростной UART) Читение/Запись RFID меток, может общаться с другими контроллерами PN532, и вроде как общаться с Android телефонами Рабочая дистанция 5-7 см Поддерживаемые чипы ISO 14443 Type A - NXP Mifare 1k, 4k, Ultralight, Desfire ISO 14443 Type B ISO/IEC 14443-4-совместимые чипы FeliCa Jewel TopaZ Чтение / Запись RFID меток Обмен данными P2P Передача данных смартфону Кстати, вроде как начиная с Androik 4.4 KitKat операционная система умеет эмулировать NFC метки программным способом. Это подразумевает, что мы можем на телефоне сделать копию проездного билета (БСК, Тройка) или просто обычной метки, и использовать смартфон в качестве ключа для замка. К сожалению, у меня пока нет под рукой аппарата с поддержкой NFC, а значит и проверить это мне не под силам. Оставляю эту задачу Вам! Для сборки замка нам понадобятся: Arduino UNO или любой аналог с контроллером ATmega328 Сам модуль сканера с контроллером PN532 Китайский модуль реле с опторазвязкой (в программе предусмотрена инверсия управляющего сигнала на случай управления реле напрямую или замены его на транзисторный ключ / мосфет) Две кнопки для, одна для разблокировки замка изнутри помещения, а другая для сброса памяти микроконтроллера Два резистора 10kOm и 4.7kOm Танталовый конденсатор на 1uF Светодиод для индикации о попытках взлома замка с помощью брутфорса ключа Транзистор KT315 или его аналог для управления питанием PN532. Говорят, что война между Десептиконами и Автоботами началась именно из-за этих Советских транзисторов! Зачем нужен транзистор? Он используется для управления питанием сканера, если по какой-либо причине Arduino пойдет на перезагрузку, то она потянет за собой и сканер. Таким образом мы лишний раз подстрахуем себя. Конденсатор в обвязке транзистора необходим для сглаживания пульсаций, у меня они были явно заметны при питании от USB. Конечно это все можно выкинуть из схемы и пустить на ножку VCC контроллера PN532 питание напрямую с 5V платы Arduino. Это уже на Ваш страх и риск. Критически важно обратить внимание на питание! Не поленитесь и возьмите отдельный блок питания, USB используйте только в качестве Serial монитора. На реле желательно подавать отдельное питание, на Китайских модулях для этого есть соответствующие пины (GND, VCC, JD-VCC). На схеме я это не отражено т.к каждый волен самостоятельно выбирать как управлять силовой частью замка. Может вы замените реле мосфетом. На просторах мирового интернета нашел пару изображений схем показывающий, как реализовано питание и управление китайскими релейными модулями. Так показано на схеме и так делает большинство. Все будет работать. А так будет правильно, но необходим отдельный источник питания для релейного модуля Выбор за Вами. Вернемся к сканеру. Уже упоминалось, что он имеет возможность общаться по одному из нескольких интерфейсов на выбор. Сам выбор интерфейса реализован на физическом уровне и представляет из себя сдвоенный переключатель. На изображении ниже выбран HSU (UART). В таком варианте модули приходят к нам из поднебесной. Мы будем использовать i2C интерфейс. Возможно стоило бы SPI? Все подключения можно свести к одной таблицы Как все устроено Часть функционала было позаимствовано из предыдущего варианта о котором говорилось в самом начале данного поста. При первом запуске Вам будет предложено создать мастер ключ, но не спешите это делать. Я советую Вам очистить EEPROM, для этого нажмите и удерживайте кнопку RESET до тех пор, пока не услышите звуковой сигнал. После очистки памяти контроллер будет перезапущен, замок разблокируется в ожидании первого поднесенного ключа (метки), может быть даже смартфона (ищите эмуляторы RFID меток и проверяйте). Первый поднесенный ключ станет мастером, советую его надежно спрятать дома т.к только с его помощью можно записывать новые ключи в память микроконтроллера. Кстати о памяти, вот схема как она используется, всего занято 1kB. Первые 8 байт используются для хранения системной информации. Пока заняты только первые 2 байта, а остальные 6 зарезервированы под будущие улучшения. Возможно Вы что-то захотите добавить свое. Начиная с 9 байта идут ключи. Ключи бывают разного размера, но мы будем использовать только первые его 4 байта. Первый ключ всегда идет мастер, все последующие обычные. Всего можно иметь 1 мастер и 253 обычных ключа. То есть мы израсходуем весь объем EEPROM контроллера ATmega328. Вы конечно можете воспользоваться другим контроллером, с большим количеством памяти, но программа не даст Вам создать более 254 ключей. Оставшаяся память останется свободной. И так после создания мастер ключа замок перейдет в дежурный режим, разблокировать его можно кратковременным нажатием на кнопку OPEN или самим мастер ключом. Для добавления новых ключей необходимо поднести мастер ключ к сканеру и удерживать более 5 секунд. Замок перейдет в режим программирования оповестив Вас об этом звуковым сигналом. В этом состоянии замок будет в разблокированном состоянии и все поднесенные новые ключи будет записаны в память. Для выхода из режима программирования необходимо опять поднести мастер ключ к сканеру и удерживать более 5 секунд. Звуковой сигнал оповестит об этом и замок вернется в дежурный режим. После открытия двери ключом или кнопкой запускается таймер, который закроет замок через 5 секунд. Можно удерживать замок в открытом состоянии при удержании кнопки OPEN, но при её отпускании замок сразу закроется. Теперь немного про защиту В программе имеется счетчик ложных срабатываний. Если в течении минуты будут зарегистрированы 5 попыток подбора ключа, замок будет заблокирован на 1 минуту. Открыть дверь можно будет только с кнопки OPEN. Поднесения действующего ключа, даже мастера, будет проигнорировано замком. По истечению минуты доступ будет открыт, но на этом еще не конец. Счетчик даст только одну попытку разблокировать замок, если она потерпит неудачу, блокировка повторится. Замок будет давать по одной дополнительной попытки за каждую минуту ожидания, но не более 5 попыток. Таким образом скорость подбора ключа сводится к 1 ключу в минуту, а учитывая длину ключа даже в 4 байта, тот кто захочет этим заняться должен быть бессмертным. Проще ключ украсть или сделать копию, но от этого не застрахованы даже обычные замки, но в следующем варианте программы мы позаботимся и об этом. Если кто-то пытался подобрать ключ и замок его поймал на этом, то светодиод начнет периодически мигать. И даже если отключить питания, контроллер не забудет об этом инциденте и при его восстановлении продолжит оповещать о случившемся. Интенсивность мигания будет напрямую зависеть от количества блокировок. 1 раз в секунду если была выявлена хотя бы одна блокировка 2 раза в секунду если было выявлено более 5 блокировок 3 раза в секунду если более 10 блокировок 4 раза в секунду если выявлено более 20 попыток Горит постоянно при более 50 попытках Есть два способа сбросить счетчик. Воспользоваться мастер ключом и перевести замок в режим программирования, после вернуть обратно в дежурный режим. Или удерживая активный ключ у сканера PN532 зажать кнопку OPEN на 5 секунд. В принципе на этом пока все. Для реализации Вам понадобятся следующие библиотеки: Bounce2 для программной защиты от дребезга Timer1 для удобной реализации прерываний Adafruit PN532 для связи с самим сканером Хотите помочь проект? Yandex.Money PayPal.me Сама программа замка: PN532_lock_iT4iT.CLUB.7z
  17. 2 балла
    Почитайте внимательно : https://alexgyver.ru/arduino-first/
  18. 2 балла
    Добрый день! А сделать , как у меня с Вашей помощью получилось, через slave-ардуину по I2C чем плохо? порты дополнительные не нужны, прерывания не нужны, лишняя библиотека не нужна, NRFке никто не мешает принимать данные и они не теряются. Небольшая проблема в нехватке оперативки у ESP8266 при большом количестве датчиков, так эта же проблема проявится и при подключении по SPI. Стоимость ардуино pro mini в районе 100р, что не сильно повысит общую стоимость.
  19. 2 балла
    Необходимо заменить саму микросхему памяти и в настройках среды разработки выставить размер flash и разметку. В Arduino IDE это делает в настройках выбора платы. Выгоднее всего покупать уже готовые модули с 4Мб памяти т.к по цене они точно такие же как и с 1 Мб. В теории можно поставить и 8Мб, но придется вносить изменения в конфигурационные файлы среды разработки. Я думаю, что львиную часть задач можно решить с 4Мб памяти. Конечно все это влияет на производительность, но еще больше на производительность влияет сам код и тут речь не только о пользовательских реализациях, но и коде самой Arduino платформы. Например, в 160МГц не будет никакого смысла если код изобилует вызовами delay, тоже самое относится к памяти, весь прирост скорости может упереться в режим dout, выставленный случайно место qio. В общем правильный ответ будет ДА, это может повысить производительность, НО только в купе с оптимизированным, хотя бы в приделах Arduino, кодом.
  20. 2 балла
    скетч ардуины, принимающей данные с орегонов INT_oregon-arduino_wind_rain_1_3_4_temp_slave1_7-7-19.zip
  21. 2 балла
    Добрый день! У меня все внешние датчики подключаются к ESP через ардуины про мини, подключенные по шине i2c как slave. Данные от датчиков Орегон считываются одной из таких ардуин с приемником на 433МГц. Принимаю данные от 1-го датчика ветра WGR800, 1-го датчика осадков PCR800 и трёх термогигрометров THGR810. Данные всех пяти датчиков принимаются со статусом питания, если его не читать, можно еще добавить два термогигрометр. Полный скетч в приложении. Там еще добавлен экран nextion. Его можно не подключать, без него работает нормально. скетч до конца не отработан. Проверен вебсервер ESP и народный мониторинг. MQTT знаю, что работает, но на всех датчиках еще не проверил. INT_Meteo_D_4slaves_nextion4x16_mqtt_10-7-19.zip
  22. 2 балла
    Всем добрый день. На днях получил все необходимые датчики и корпус. Собрал всё. Проблем не возникло. Только на датчике CCS8111 контакт WAK надо подключить к GND на плате. После нескольких часов работы показания датчика улетели на максимум и так пробыли до рестарта ESP... Как вы думаете, с чем может быть проблема?? И еще, как можно допилить код для взятия показания VOC??? Немного про корпус для датчиков из Китая, вот немного фоток: Сам корпус серого цвета. посмотрим как поведет себя на улице
  23. 2 балла
    Они там есть, только скрыты. Для того чтобы они были доступны через web-интерфейс необходимо раскомментировать в файле users_auto.h несколько строк. На рисунке показано какие. После это в на странице появится Жмём "полудомик" и получаем По поводу Blynk... Прикручивал сам, автор и так много сделал.. Каждый уже как бы пляшет от того что предоставлено в массы.
  24. 2 балла
    Доброе время суток @Astron Тут Вы поспешили, смотрите в чем дело Это сообщение сформировано самой библиотекой и говорит, что вы пытаетесь использовать динамический буфер, который не поддерживается в 6-ой и более старших версиях. Именно по этой причине я указал в инструкции, что необходимо использовать 5-ую версию. Так что вы практически все сделали правильно. На всякий случай, я сформировал архив с Portable Arduino IDE v1.8.9 для Windows с поддержкой ESP8266 и ESP32, а также установленными FS плагинами для загрузки файлов web сервера, базовым набором библиотек (не все нужно обновлять) и скетчем с проектом метеостанции. Я мог что-то упустить, но надеюсь у Вас все получится. Скачать можно тут: https://yadi.sk/d/lXNS4_juPVPYwA
  25. 2 балла
    @post125 попробуйте запустить скрипт в консольном режиме zabbixMqttClient.py window В выводе получите описания этапов подключения, например connecting... connected client id: server.local subscribe on "$SYS/#" subscribe on "kitsum/espWeatherStation/#" subscribe on "kitsum/serverRoom/#" Далее должен начаться вывод сообщений, полученных от брокера 2019-05-30 07:52:46 $SYS/broker/messages/sent 216459 (host: broker, key: topic[messages/sent]) server response: ... 2019-05-30 07:52:46 $SYS/broker/publish/messages/sent 34211 (host: broker, key: topic[publish/messages/sent]) server response: ... 2019-05-30 07:52:46 $SYS/broker/bytes/sent 1809731 (host: broker, key: topic[bytes/sent]) server response: ... 2019-05-30 07:52:46 $SYS/broker/publish/bytes/sent 206329 (host: broker, key: topic[publish/bytes/sent]) server response: ... Больше информации можно получить, включив вывод логов paho, для этого надо найти строку #mqttc.on_log = on_log Приводим её к такому виду mqttc.on_log = on_log Также можно модифицировать скрипт чтобы увидеть не стандартное поведение zabbix_sender Ищем блок if error == None: output = re.search('"processed: (\d+); failed: (\d+); total: (\d+); seconds spent: (\d+\.\d+)"', out$ if output.group(2) != '0': answer = 'failed (time ' + output.group(4) + ')' elif output.group(1) != '0': answer = 'processed (time ' + output.group(4) + ')' else: answer = output.group(0) alert(time.strftime('%Y-%m-%d %H:%M:%S ', time.localtime()) + msg.topic + ' ' + str(msg.payload.decode('utf-8')) + ' (host: ' + host + ', key: ' + key + ') server response: ' + answer) else: alert(error) return 0 Приводим его к такому виду if error == None: output = re.search('"processed: (\d+); failed: (\d+); total: (\d+); seconds spent: (\d+\.\d+)"', out$ if output == None: alert('zabbix_sender error!') return 0 elif output.group(2) != '0': answer = 'failed (time ' + output.group(4) + ')' elif output.group(1) != '0': answer = 'processed (time ' + output.group(4) + ')' else: answer = output.group(0) alert(time.strftime('%Y-%m-%d %H:%M:%S ', time.localtime()) + msg.topic + ' ' + str(msg.payload.decode('utf-8')) + ' (host: ' + host + ', key: ' + key + ') server response: ' + answer) else: alert(error) return 0 Также стоит попробовать отправить данные через zabbix_sender руками. zabbix_sender -vv -z 127.0.0.1 -p 1883 -s broker -k topic[my/test/path] -o 555 Где: 127.0.0.1 - имя или ip mqtt адрес сервера 1883 - порт mqtt сервера broker - имя узла в zabbix на который адресовано сообщение topic[my/test/path] - это ключ элемента данных который присутствует в шаблоне или создан руками 555 - любое значение для теста
  26. 2 балла
    Да, удалите в основном файле строку cron.add(cron::time_1m, [&](){ sensors.checkLine(); }, true); Всю инициализацию датчиков проведите самостоятельно без использования соответствующих функций при описании датчиков. Или замените указанную выше строку на разовый вызов метода checkLine sensors.checkLine(); Проверка датчиков на шине проводится через определение доступности адресов датчиков Wire.beginTransmission(sensor->address); /* ... */ sensor->status = (Wire.endTransmission() == 0); Скорее всего вы получаете не все данные при запросе данных для комплексного суточного графика в следствии чего json строка считается поврежденной и график не строится. А корень проблемы в том, что в данном случае контроллер передает данные по всем сенсорам, для которых активно ведение лога. Связано это с тем, что изначально не было графиков по конкретным сенсорам, существовал только комплексный график, соответственно и данные отдавались все и сразу. Получается, что Вы нашли придел для размера передаваемого объекта с данными. Часть кода уже переписана и прекрасно работает, но есть технические нюансы, из-за которых я не могу назвать какие-то конкретные строки. Ну и опять же, все приходится делать только в свободное время.
  27. 2 балла
    Благодарю за ответ! Теперь понятно, что не надо трогать. Я еще сам не делал скетчи, состоящие из нескольких файлов. По I2C из ProMini я научился передавать массив из 8 floatов в ESP, разбивая и собирая их побайтно на основе Ваших подсказок. Более крупные массивы пытаться передавать, наверное, не буду, мне и этого достаточно будет. на ProMini это выглядит так (Serial.print удалил, чтобы не загромождало): на ESP это выглядит так (Serial.print то же удалил): Итого получилось, что уличная ProMini получает данные с датчиков, через NRF24 передает массив из 8 чисел на домашнюю ProMini , а та, как slave, отдаёт этот массив на ESP по I2C. Попробовал на одну master ESP повесить одновременно три slave ProMini (в примерах, соответственно, оставил работу только с одним slave ). Вся эта связка работает без сбоев. Осталось подружить с Вашим проектом. Кстати, уличные датчики на ProMini (с NRF24 и SHT31) получаются весьма непрожорливыми - в режиме сна потребляют от двух батареек АА около 5мкА. И работают они стабильно до напряжения примерно в 2,1В. Так что батареек должно на долго хватить, если передвать данные раз в неколько минут. Еще раз благодарю за помощь!
  28. 2 балла
    Описанный ниже велосипед является продолжением одной из моих статей на другом, интересном мне, ресурсе. Продолжение и все последующие обновления будут происходить только на it4it.club Для начала, хочу процитировать самого себя и тем самым дать пояснения: почему, зачем и для кого это нужно. Данная тема получила большую популярность у коллег и не раз выручила Вашего покорного слугу, не дав разгореться стулу на котором он сидит. Но имеющегося функционала стало не хватать, требовалось не только слышать и иногда видеть, а еще получать удаленный доступ к оборудованию и лицезреть всю картину в целом. Задача поставлена, идем исполнять, но с начало забегу немного вперед и продемонстрирую текущий функционал. Общее окно программы переработано и теперь отображает список всех групп из Zabbix с их хостами. Список активных триггеров переехал в нижнюю часть окна и отображает дополнительную информацию об узлах с которыми не все гладко. Сам список можно увеличивать, если все совсем плохо, или уменьшать если выражение "Хьюстон у нас проблемы" Вы слышите только в фильмах. Также появились цветные маркеры важности триггера. По двойному клику по активному триггеру мы перемещаемся в соответствующую группу где находится проблемный узел. Не забыли и про то, ради чего вся начальная песня и писалась - трей с всплывающими оповещениями и звуковым сигналом. Основное окно сворачивается именно туда, чтобы не залеживаться на панели где ценится каждый свободный пиксель. Хосты в группах стали кликабельны, правда пока только ПКМ, и имеют всплывающее меню позволяющее выполнять банальные действия: Подключение к узлу: Telnet SSH RDP VNC Проверка соединения: Ping Traceroute Естественно его можно расширить, добавив всяких вкусностей по мере возрастания аппетита IT отдела. Программа по прежнему имеет серверную и клиентскую часть, что позволило организовать кэширование запросов и осуществлять оповещения в момент определения проблемы сервером, а не по таймеру обновления, как это организовано в dashboard zabbix. Раньше узнали о проблеме, раньше приступили к устранению. Естественно и устаревшие триггеры убираются также оперативно. Также это позволило избавить программу от информации о доступе к серверу, что мне кажется не приемлемым для оповещалки. Чем меньше дырок, тем крепче сон. Приступим к реализации. Ну и естественно, Ваш покорный слуга еще не научился писать на C++ ничего более сложного чем "Hello World", поэтому клиент и сервер будет написан на PHP. За исключением того момента, что клиентская часть (при помощи магии Гарри Поттера) станет бинарным файлом. Бог с ним, серверная часть не доступна обывателю, а это самое важное!!! Для начала, нужно придумать безопасный и понятный алгоритм не нагружающий сервер т.к клиентов может быть 100и или 1000и, всякое бывает. Все не безопасные команды обязаны выполняться на сервере без участия клиента. Дальнейшая работа клиента: обработка данных, выполнение действий с триггерами и т.п должно выполняться только у клиента, не затрагивая сервер. При обращении клиента к серверу по http происходит проверка его ip на наличие в списках разрешенных. В противном случае показываем фигу. Проверяем, наличие актуального кеша, и отдаём его. Если кеша нет, генерируем новый. Если запрос прилетел от zabbix: принудительно считаем кеш устаревшим, генерируем новый и после этого рассылаем всем клиентам оповещения по UDP протоколу. Это позволит свести расход ресурсов базы данных к нулю т.к все клиенты ринутся забирать новые данные, а все уже в кеше. Супер, все дешево и сердито. Серверная часть представляет из себя файл index.php где-то на Вашем web сервере. Актуально для Zabbix 2.4 (скорее всего будет актуальна и для последующих версий, будем проверять по мере возрастания аппетита). Для дополнительной безопасности рекомендую создать отдельную учетную запись в базе данных с правами только на чтение и только к базе zabbix. Это актуально в наши дни. Переходи в zabbix Первым делом переходим в Настройка -> Действия -> Источники события: Триггеры и создать новое действие. Назовем случайным образом, например Report problems to ZabbixTrigger. В условиях выставляем Значение триггера = ПРОБЛЕМА Значение триггера = OK Это все необходимо, чтобы проблемы в GUI появлялись и исчезали точно именно тогда, когда это происходит в Zabbix (не путать с dashboard). Вкладка "Операции" должна выглядеть следующим образом. Естественно что путь до php скрипта должен быть вашим. Вуаля! Если Вы все сделали правильно (без кардинальных изменений), то я рад приветствовать нового ездока моего велосипеда. Поедем тандемом! Сам клиент прикреплен в конце поста. Для тех, кто читает титры в кинотеатре При запуске будет создан файл config.ini в корне программы. При необходимости, измените его настройки, благо их не много. [server] url="http://zabbix/zabbix-gui" update="60" [client] showalarm="20" Параметр url отвечает за http путь до скрипта на сервере, update за интервал (в секундах) обновления данных с сервера, а showalarm вроде как должен влиять на время отображения всплывающей подсказки в трее. Теперь немного структуры. В каталоге sounds находится звук оповещения о новом триггере, формат ogg Каталог icons содержит маркеры триггеров. trigger00 - для нормального состояния, а все последующие соответствуют начальным настройкам zabbix во вкладке Администрирование -> Общие раздел Важность триггеров. Можете изменить на свои цвета, программа все подхватит при перезагрузки. Ну и на закуску каталог ext, это как говорится для меломанов, содержит фри программы для обработки внешних действий клиента. Вы можете заменить их на свои при условии, что стандартные имена параметров запуска и их последовательность совпадают. PS: На этом все, спасибо тем кого это заинтересовало. Предлагайте свои идеи или способы доработки велосипеда. А если найдется программист на C++ так милости просим. В любом случае, функционал будет в дальнейшем расширяться. zabbixTrigger.zip
  29. 2 балла
    @Dark FeniX если необходимо добавить что-то свое (без модификаций основного кода), то действуйте точно также как если бы писали все с нуля. Работайте с основным файлом. Подключайте необходимые библиотеки, объявляйте переменные, дорабатывайте содержимое setup и loop, в общем делайте все как обычно опираясь на примеры, идущие в комплекте с используемыми библиотеками. Что касаемо упоминаемого кода, то он не действителен для текущей версии проекта поэтому давайте рассмотрим, как это должно выглядеть на текущий момент. Допустим Вас интересует библиотека https://github.com/ThingPulse/esp8266-oled-ssd1306, будем опираться на её примеры для дисплея ssd1306 подключенного по i2c шине. Все работы будем проводить в основном файле проекта (.ino) Подключаем библиотеку и объявляем переменные #include "SSD1306Wire.h" // Подключаем интересующую нас библиотеку SSD1306Wire display(0x3c, 4, 5); // Объявляем переменную через которую будем работать с дисплеем Сделать это можно в любом месте, например, после подключения уже используемых библиотек Чтобы все выглядело красиво создадим собственную функцию, которая будет выводить информацию на дисплей, пусть это будет температура void displayWeather() { display.clear(); // Очищаем дисплей display.setFont(ArialMT_Plain_10); // Устанавливаем шрифт display.setTextAlignment(TEXT_ALIGN_CENTER); // Указываем выравнивание display.drawString(64, 22, "Temperature " + String(sensors.get("out_temperature"))); // Выводим температуру display.display(); // Производим отрисовку данных } Сделать это можно, например, сразу перед функцией Setup или в любом месте файла если Вы используете актуальную версию Arduino IDE В функции Setup описываем инициализацию дисплея display.init(); // Инициализация дисплея display.flipScreenVertically(); // Переворачивает дисплей верх ногами (если требуется) Сделать это можно прямо в конце этой функции И следом после этого, также в функции Setup, добавляем новую задачу в планировщик задач cron.add(cron::minute, displayWeather, true); Новое задание подразумевает вызов вашей функции displayWeather каждую минуту и имеет отложенный запуск, то есть первый её вызов произойдет также через минуту после запуска контроллера. Отложенный запуск требуется для того, чтобы датчики произвели калибровку (если это требуется), а микроконтроллер успел наполнить медианный фильтр для каждого сенсора. В свою очередь это подразумевает, что данные на дисплее появятся через минуту после подачи питания на микроконтроллер и в последующем будут обновляться каждую минуту. Выглядеть это будет примерно так (все работы произведены в одном файле). И еще хочу добавить, что я просто взял первую попавшуюся библиотеку и основываясь на одном из примеров и описанию методов от разработчика набросал вышеупомянутый список. Проверить полную работоспособность не могу т.к у меня попросту нет данного дисплея. Но суть и принципы реализации должны быть понятны. Таким же образом можно организовывать работу с другой периферией, например, управлять внешним освещением на дачном участке, выводить информацию на дисплей 16x2 (или любой другой), собирать данные с других готовых устройств и т.д и т.п
  30. 2 балла
    Файлы 3D модели для печати будки Стивенсона идут в дополнительном архиве вместе с прошивкой, также в первом посте есть ссылка на эти же файлы но от самого автора модели. Я заказывал печать просто по объявлению, найденному в одной из социальной сети, главным критерием было производство на территории моего города. Цена вопроса 100р за каждую секцию, итого 600р. Думаю, что вам стоит поступить точно также и найти печать в своем регионе. Это также избавляет от рисков повреждения во время транспортировки, как работает почта России объяснять не нужно. Но уж если будут сложности, тогда пишите в приват, договоримся о заказе в моем городе и переправке к Вам. Да, я поспешил и упустил из внимания, что для ключевых элементов хранения логов выделен тип byte, что приводило к переполнениям и в последствии к сбоям в расчетах. И так, необходимо внести еще ряд правок в файле sensors.h В классе device имеется одноименная функция (конструктор) device в описании параметров которого имеется параметр byte log, тип byte необходимо заменить на uint16_t device(knob_t *knob, list_t list, byte address, const char *name, initFn_t init, dataFn_t data, uint16_t log, device *next) { /* код убран для уменьшения размера блока */ } Аналогичную операцию замены типа необходимо провести в классе device у переменной byte logPosition и привести её к следующему виду uint16_t logPosition = 0; В классе sensors проводим аналогичную операцию с приватной переменной byte logSize uint16_t logSize = 144 * 3; В примере я указал три дня, Вы выставляете свое значение. В классе sensors имеется функция json sensors::log(device *sensor) отвечающая за формирование списка в формате json для передачи его в WEB интерфейс, её необходимо привести к следующему виду. json sensors::log(device *sensor) { String log; if (sensor) { if (sensor->log) { for (uint16_t i = sensor->logPosition; i < this->logSize; i++) { log += (log.length() ? "," : "") + this->clear(sensor->log[i]); } for (uint16_t i = 0; i < sensor->logPosition; i++) { log += (log.length() ? "," : "") + this->clear(sensor->log[i]); } if (log.length()) log = "\"" + String(sensor->name) + "\":[" + log + "]"; } } return log; } По сути мы просто в двух циклах for изменили тип переменной i с byte на uint16_t и позволили циклам проходить по всему диапазону данных. В файле index.htm дату формирования первой точки вычисляем по первоначальной формуле new Date().getTime() - obj.timeAdjustment - (144 * 3 - 1) * 10 * 60 * 1000, Все должно получиться, но на всякий случай прикладываю файл sensors.h со всеми правками. Естественно файл устареет со временем, что может повлиять на работоспособность при совместной работе в будущих версиях, если конечно обновления будут востребованы сообществом. sensors.zip
  31. 2 балла
    А я часики добавил. Спасибо за виджет погоды, там и солнышко анимированное) только погода не точная, подвирает. На смарте пользуюсь "foreca" по СПб там более точно показывает прогноз Скрин делал с телефона, не все влезло)
  32. 2 балла
  33. 2 балла
    У меня была подобная проблема с Mosquitto неполной передачи. Решение if (tMQTT != 0) { if (millis() - tMQTT > 1000 or tMQTT > millis()){ mqttAPI.disconnect(); tMQTT = 0; } } Вызов функции mqttAPI.disconnect(); после окончания передачи через 1с. Все заработало. У меня передача на Mosquitto идет каждые 5s. Далее полученная информация архивируется в СКАДА системе. (с периодичностью 5с) У меня к ESP (Nodemcu) подключено 2хBME + 10x ds18b20 и все передается в Mosquitto реализованное на виртуальной машине как и web скада
  34. 2 балла
    На данный момент я предполагаю, что проблема проявляется при изменении кодировки в файлах проекта. Изначально все файлы, в том числе и web сервера, имеют кодировку utf-8. Данные между контроллером и web интерфейсом также передаются в этой кодировке. Arduino IDE также работает с utf-8. Возможно, где-то в этой цепочке произошла смена кодировки. Над этим стоит подумать. Это говорит о том, что у Вашего компьютера или иного устройства нет поддержки MDNS протокола, но не беда. Место espws.local наберите ip выданный контроллеру. На странице Вы должны увидеть json строку по данным с которой web интерфейс добавляет сенсоры. Вы можете скопировать текст в "кривой" кодировки и воспользоваться услугами любого онлайн анализатора кодировки. Надеюсь он подскажет в какую сторону копать. Безусловно будут отображены все объявленные датчики т.к на данный момент данные о структуре списка устройств объекта sensors забираются у микроконтроллера всего один раз при открытии/обновлении страницы. Я обновил архив, там есть небольшие изменения в web сервере, теперь он добавляет заголовок кодировки utf-8 при ответе клиенту через API. Проверьте как у Вас это будет работать. Да, у меня работает, и Вы абсолютно правы. Вам необходимо создать канал в своем профиле, далее перейти в раздел API Keys и скопировать ключ Write API Key. этот ключ необходимо указать в соответствующем поле в web интерфейсе. Данные должны начать поступать в течении 5 минут. Какие данные будут отправляться зависит только от Вас. Пример используемый по умолчанию и описанный в файле services.h отправляет данные об освещенности, температуре, влажности и давлении на поля field1-4 соответственно. Статус отправки запроса отображается в консоли.
  35. 2 балла
    Может быть, в проекте приживется идея с индикацией скорости изменения атм. давления? Ведь, как правило, интересно именно это значение, а не абсолютное. Например, на дисплее HD44780 я реализовал это в виде четырех стрелок, указывающих либо вверх, либо вниз. Диапазоны для скорости изменения взял с часов CASIO ProTrek PRG-40. Получился такой код. Отлично работает. Очень информативно получается. Видишь на экране две-три стрелки - жди изменения погоды. Четыре - еще не видел ни разу ни на часах CASIO, ни на своей поделке. Первые два часа вместо стрелок выводится слово "wait". В общем, такой вариант отображения информации с барометра (на мой взгляд!) несет гораздо больше смысла, чем абсолютное значение. И даже крутизну графика давления оценить гораздо сложнее, чем четыре стрелки или, например, четыре цветовых уровня... Как уж это реализовать в интерфейсе - вопрос вкуса. Думаю, что в данном проекте это получилось бы красиво. if(((Q2 - Q1) >= 0.64)&((Q2 - Q1) < 1.27)){ //Если разность между измерениями давления с интервалом в 2 часа от 0.64 до 1.27 мм.рт.ст. Press[0] = '\1'; //Зажигаем ОДНУ стрелку ВВЕРХ Press[1] = ' '; Press[2] = ' '; Press[3] = ' '; } if(((Q2 - Q1) >= 1.27)&((Q2 - Q1) < 2.54)){ //Если разность между измерениями давления с интервалом в 2 часа от 1.27 до 2.54 мм.рт.ст. Press[0] = '\1'; //Зажигаем ДВЕ стрелки ВВЕРХ Press[1] = '\1'; Press[2] = ' '; Press[3] = ' '; } if(((Q2 - Q1) >= 2.54)&((Q2 - Q1) < 3.81)){ //Если разность между измерениями давления с интервалом в 2 часа от 2.54 до 3.81 мм.рт.ст. Press[0] = '\1'; //Зажигаем ТРИ стрелки ВВЕРХ Press[1] = '\1'; Press[2] = '\1'; Press[3] = ' '; } if((Q2 - Q1) >= 3.81){ //Если разность между измерениями давления с интервалом в 2 часа от 3.81 мм.рт.ст. и более Press[0] = '\1'; //Зажигаем ЧЕТЫРЕ стрелки ВВЕРХ Press[1] = '\1'; Press[2] = '\1'; Press[3] = '\1'; } if(((Q2 - Q1) <= -0.64)&((Q2 - Q1) > -1.27)){ //Если разность между измерениями давления с интервалом в 2 часа от -0.64 до -1.27 мм.рт.ст. Press[0] = '\2'; //Зажигаем ОДНУ стрелку ВНИЗ Press[1] = ' '; Press[2] = ' '; Press[3] = ' '; } if(((Q2 - Q1) <= -1.27)&((Q2 - Q1) > -2.54)){ //Если разность между измерениями давления с интервалом в 2 часа от -1.27 до -2.54 мм.рт.ст. Press[0] = '\2'; //Зажигаем ДВЕ стрелки ВНИЗ Press[1] = '\2'; Press[2] = ' '; Press[3] = ' '; } if(((Q2 - Q1) <= -2.54)&((Q2 - Q1) > -3.81)){ //Если разность между измерениями давления с интервалом в 2 часа от -2.54 до -3.81 мм.рт.ст. Press[0] = '\2'; //Зажигаем ТРИ стрелки ВНИЗ Press[1] = '\2'; Press[2] = '\2'; Press[3] = ' '; }; if((Q2 - Q1) <= -3.81){ //Если разность между измерениями давления с интервалом в 2 часа от -3.81 мм.рт.ст. и более Press[0] = '\2'; //Зажигаем ЧЕТЫРЕ стрелки ВНИЗ Press[1] = '\2'; Press[2] = '\2'; Press[3] = '\2'; }; if(((Q2 - Q1) < 0.64)&((Q2 - Q1) > -0.64)){ //Если разность между измерениями давления с интервалом в 2 часа от 0.64 до -0.64 мм.рт.ст. Press[0] = ' '; //Не зажигаем ни одной стрелки Press[1] = ' '; Press[2] = ' '; Press[3] = ' '; }
  36. 2 балла
    Все доброго времени суток. Ваша ошибка единична и вызвана внешними факторами. Если она повторится, и в web интерфейс начнет себя вести не адекватно, то перейдите в "Инструменты разработчика" и просмотрите список ошибок во вкладке "Console". В описании ошибки имеется отсылка на исполняемый файл и часть кода в котором она произошла. Это информация поможет разобраться на чьей стороне проблемы и, какие действия стоит предпринять с Вашей стороны. @EndWar @Alex_DIY Друзья, давайте перестанем заниматься спорами, это пустая трата времени. Не буду загадывать, но постараюсь в следующем месяце выложить большое обновление для метеостанции. Оно пока в разработке и в основном связано с исправлением кучи косяков и багов. В планах следующее (часть кода уже реализована): Перебрать весь код, исправить много ошибок и разбить его на модули Вынести из основного файла все лишнее, что мешает пользователям быстро внедрить свои наработки в проект Упростить систему выбора датчиков. Избавиться от системы комментариев и перейти на понятные людям ON/OFF или что-то подобное. Упростить, для пользователей, работу с файлом конфигурации и свести к минимуму доработки кода для добавления собственных параметров. Уйти от зоопарка констант и кучи кода отслеживающих наступления того или иного события. Реализовать не сложный планировщик задач, по идеологии напоминающий cron в unix системах, способный обрабатывать любые пользовательские функции с указанным интервалом времени и корректно отлавливающим переполнение uint32_t (unsigned long). Переработать web сервер для ускорения его работы с клиентами. Быстро передавать информацию и освобождать соединение. Уже имеется x10 кратный прирост скорости передачи, что в совокупности с системой кэширования дает возможность отказаться от дублирования ресурсов web сервера микроконтроллера на стороне. Лабораторные тесты, если их можно так назвать, с отключенной системой кэширования, показали загрузку всего Web интерфейса из spiflash менее чем за 3 секунды, а с eTag менее 1 секунды. Модернизировать систему работы с сенсорами. Как минимум, перенести все вычисление в один объект т.к по сути, структура и класс, это одно и тоже. Так зачем, например, держать расчеты для графиков вне объекта самого сенсора...? (риторический вопрос) Пересмотреть систему работы с внешними серверами - одно соединение на всех. Возможно добавить работу с thingspeak (под вопросом). Добавить поддержку скрытых домашних беспроводных сетей. ... Постараюсь не затрагивать web интерфейс, на тот случай, если вы вносили собственные доработки при условии эксплуатации базового API. Цель - изменение идеологии проекта. Довести присутствие в нем метеостанции к минимуму и показать, что Вы можете использовать его для своих уникальных целей. И помните, что мы работаем над проектом вместе и если Вы будите конфликтовать, то ничего хорошего из этого не выйдет. PS: я старался не упоминать об обновлении в постах, но раз уж Вы стремитесь куда-то направить свою энергию, то делайте это в благих целях. И я предлагаю Вам направить её для проработки Ваших идей и предложений. Возможно стоит что-то внедрить или доработать. Но не кидайте сырые идеи, обдумайте предложения, я буду Вам признателен. Спасибо!
  37. 2 балла
    @LogOFF доброе время суток. Исходник: ESP8266_WS_iT4iT.CLUB_LogOFF.7z
  38. 2 балла
    @wildray последовательность Ваших действий для получения работоспособной метеостанции должна быть следующей: ... перенесено в первый пост темы
  39. 2 балла
    Друзья, в очередной раз приветствую Вас. Сегодня мы доведем до ума нашу идею с дружбой Zabbix и MQTT (Message Queue Telemetry Transport) протокола. Все описанные ранее варианты также жизнеспособны, но хотелось чего-то большего и в первую очередь, избавиться от задержки, из-за которой клиентам приходилось рассылать сообщения с параметром "-r, --retain". То есть была такая ситуация, что Zabbix сервер получал сообщения не тогда, когда они по факту приходили брокеру, а через какое-то время, равное интервалу между запросами к брокеру через вызов /usr/bin/mosquitto_sub. И именно из-за такой логики работы, клиентам приходилось выставлять флаг "сохранить" при отправке сообщения. Ну и пусть, скажете Вы, подождем, но как всегда есть нюансы: Сервер получает последнее сообщение в топике, а значит, в промежуток между их сбором, данные могут обновиться несколько раз, и мы потеряем часть информации. Это может быть актуально в некоторых случаях, например, если требуется контролировать состояние двери в серверной комнате (открыта/закрыта) ну или в других более серьезных задачах. Если требуется оперативно поднять соответствующий триггер, особенно если на него опирается логика других триггеров. Просто хочется поддержки MQTT протокола в реальном времени. Это действительно важный пункт и если предыдущие можно проигнорировать, то этот ни в коем случае. Долой слоупока, обучаем Zabbix работать с MQTT протоколом в реальном времени! Стоит понимать, что сам по себе Zabbix сервер не способен работать с данным протоколом и именно из-за этого нам требуются различные посредники. Раньше мы обращались к ним самостоятельно через Zabbix агента или внешнюю проверку (скрипт) и сообщали, что и как мы хотим получить. Теперь мы пополним арсенал сервера внешним демоном/сервисом/службой, нужное подчеркнуть. Именно на этот самостоятельный процесс ляжет задача по поддержанию постоянного соединения с MQTT брокером, и при появлении нового сообщения, он будет передавать его серверу через Zabbix траппер. Ну, что же, на словах все просто, как это будет на деле. При написании демона я использовал язык Python в силу его популярности, простоты и доступности некоторого набора готовых библиотек. Но это моя первая в жизни программа на Python и, возможно, Вы захотите её доработать. Также на моем сервере установлена операционная система Linux Ubuntu 18.04 и дальнейшее описание будет именно под неё, но я уверен, что Вам не составит труда установить следующие пакеты под любой ОС: python3 python3-pip библиотека paho-mqtt для python https://pypi.python.org/pypi/paho-mqtt zabbix-sender Получить список установленных пакетов, связанных с python и Zabbix, можно так dpkg -l | grep -E "python|zabbix" Устанавливаем пакеты (уже установленные можно выкинуть из списка) sudo apt install python3 python3-pip zabbix-sender Подгружаем библиотеку pip3 install paho-mqtt Далее нам понадобится сама программа, скачать её можно в конце этого поста Копируем её в любое удобное Вам место, но, чтобы пользователь, от которого будет запускаться программа, имел туда доступ, например, /media/zabbixMqttClient.py и выставляем права ограниченного пользователя, пусть это будет пользователь Zabbix sudo chown zabbix:zabbix /media/zabbixMqttClient.py sudo chmod 0700 /media/zabbixMqttClient.py Далее необходимо добавить программу в автозагрузку. Сделаем это через планировщика задач crontab и опять же от имени пользователя zabbix sudo crontab -u zabbix -e Добавляем следующую запись @reboot /media/zabbixMqttClient.py start Запускаем демона от имени пользователя zabbix sudo -u zabbix /media/zabbixMqttClient.py start Далее переходим к разбору настроек программы Они разбиты на несколько секций """ Настройки MQTT """ mqtt_server = "mqtt.it4it.club" mqtt_port = 1883 mqtt_login = "" mqtt_password = "" mqtt_client_id = "zabbixServer" mqtt_short_names = True Все параметры должны быть интуитивно понятны, кроме mqtt_short_name. Данный параметр заставит программу производить разбор топика с целью поиска в нем имени хоста, на который будут отсылаться сообщения Zabbix серверу. Если параметр будет выставлен в False, то в качестве параметра ключа будет использовано полное имя топика. Мы рассмотрим этот механизм подробнее ниже, при разборе механизма подписки на интересующие нас топики. Также по умолчанию мы используем TCP соединение т.к поддержка webSocket не предусматривалась, но программу можно легко доработать. """ Настройки Zabbix """ zabbix_server = "127.0.0.1" zabbix_port = 10051 zabbix_sender = "/usr/bin/zabbix_sender" #zabbix_sender = "C:\\ZabbixAgent\\bin\\win64\\zabbix_sender.exe" С настройками подключения к Zabbix серверу также все просто. Подключаться мы будем с помощью утилиты zabbix-sender, поэтому необходимо указать полный путь до неё. Скрипт также можно запускать из-под Windows, но только в оконном режиме и с параметром window. При использовании параметра start, получите шлак ошибок т.к она отвечает за запуск программы в качестве демона в Unix подобных системах. """ Настройки общие """ pid_file = "/tmp/zabbixMqttClient.pid" В общих настройках описано только расположении pid файла. Можно оставить без изменений. """ Список топиков для подписки и идентификаторы Zabbix хостов на которые требуется их переслать """ subscribe = { '$SYS/#': 'broker', 'kitsum/espWeatherStation/#': 2, 'log/+/#': 2, } Ну вот мы и добрались до самого главного - оформление подписки на топики. Я долго ломал голову над тем, как угодить всем и организовать переправку любых сообщений на те Zabbix хосты, для которых они предназначены. И сделать это без внесения транспортной информации в само тело сообщение, лично я считаю это плохой практикой, но судя по сообщениям, за которыми я наблюдал на некоторых популярных брокерах, люди считают это хорошей идеей. Просто какое-то безумие... Думаю, что Арлен Ниппер и Станфорд-Кларком, разработчики протокола, это не одобрили, хотя сам протокол не несет никаких ограничений на передаваемую информацию. Но давайте отталкиваться от идеологии протокола. Сам по себе топик представляет: стандартизированный, упорядоченный и интуитивно понятный набор информации, а также является адресом получателя. То есть, если адрес топика будет соответствовать адресу проживания реального человека, то вид его будет похож на что-то подобное <страна>/<штат или область>/<город>/<район или улица>/<дом>/<квартира>/<имя получателя> Думаю, что Вы согласитесь со мной, ведь нет смысла писать только половину адреса, а оставшуюся часть вкладывать в сообщение. Проще, после имени получателя, дописать адрес, но уже в контексте той нагрузки, которую несет сообщение. <имя получателя>/<помещение>/<источник информации> <имя получателя>/<группа>/<подгруппа>/<источник информации> ... building/serverRoom/door/1/state ... building/serverRoom/zone1/smokeDetectors/1 building/serverRoom/zone2/smokeDetectors/1 building/serverRoom/zone3/smokeDetectors/5 ... building/serverRoom/+/smokeDetectors/# Все понятно и даже задумываться не нужно, о чем идет речь. Также стоит обратиться к принципу работы zabbix-sender, той самой утилиты, которая и будет финальной в цепочке передачи. Вот еще немного подробностей про неё. Как видим, кроме параметров подключения мы обязаны передать: Имя узла сети, которому адресовано сообщение Ключ элемента данных Сами данные И если с последним параметром все понятно, то два предыдущих я предлагаю брать из самого топика, а также не брезговать принудительным указанием имени узла сети для конкретного топика. Синтаксис правил следующий 'адрес топика в формате mqtt': 'имя узла сети в zabbix', В таком случае, все сообщения, подпадающие под установленное правило будут адресованы заранее указанному узлу сети. Но что делать, если имя узла неизвестно, и мы ожидаем данные от любых источников с адресом топика подпадающим под установленную маску? В таком случае мы можем указать порядковый номер субтопика, который содержит это самое имя. Указывать его нужно в виде целого числа, как положительного, так и отрицательного. В зависимости от знака, отсчет будет начинаться с начала конца адреса топика. Saint Petersburg/office1/temperature Saint Petersburg/office213/Wi-Fi/signalStrength Эти два топика могут подпадать под правило 'Saint Petersburg/+/#': 2, Таким образом, второй элемент с начала топика выпадает на субтопик "+" и, следовательно, имя узла сети будет соответствовать номеру офиса: office1 и officce213. Тоже самое можно делать и в обратном порядке, то есть с отрицательными значениями номера субтопика, но при этом, Вы должны быть уверены в длине адреса топика, а точнее, в количестве его субтопиков. Moscow/Odintsovo/+/temperature Этот шаблон может подпадать под два разных правила 'Moscow/Odintsovo/+/temperature': 3, 'Moscow/Odintsovo/+/temperature': -2, Что в итоге будут опять ссылаться на субтопик "+" и соответствовать его любому значению. И последнее правило 'NewYorkCity/+/gasSensors/+/#': 4, Которое соответствует второму значению "+" (четвертый субтопик), что совпадет с разными топиками и может не соответствовать нашим ожидания т.к мы получим два разных значения ссылающиеся на один узел сети "sensor 3". NewYorkCity/office16/gasSensors/sensor3/value/current NewYorkCity/office85/gasSensors/sensor3/value/current В таком случае мы должны быть уверены, что нумерация датчиков уникальна для всего набора зданий или на стороне Zabbix сервера мы ожидаем увидеть полный адрес топика, а значит, для второго варианта развития событий переменная mqtt_short_names должна быть выставлена в Flase. Таким образом мы можем кардинально поменять логику работы при построении ключей и выглядеть они будут следующим образом. Но отправлены на один узел - "sensor3" mqtt_short_names = True # отправлено хосту sensor3 (значения перезаписывают друг друга) topic[value/current] topic[value/current] mqtt_short_names = False # отправлено хосту sensor3 (ключи уникальны) topic[NewYorkCity/office16/gasSensors/sensor3/value/current] topic[NewYorkCity/office85/gasSensors/sensor3/value/current] Или исправить правило на следующее 'New York City/+/gas sensors/+/#': 2, И при mqtt_short_names = True, данные будут переданы на разные узлы сети с именами office16 и office85 соответственно, но при этом ключи будут выглядеть одинаково и не будут пересекаться. topic[gasSensors/sensor3/value/current] # отправлено хосту office16 topic[gasSensors/sensor3/value/current] # отправлено хосту office85 Возможно в теории все не так явно, но на практике это очень удобно. И важный момент - все описанные Вами правила будут рассматриваться аналогично правилам любого межсетевого экрана (firewall). Вышестоящее правило в списке имеет приоритет над нижестоящим. И если топик попал под действие одного из шаблонов, то все нижестоящие правила будут проигнорированы. Поэтому будьте внимательны. Вот пример того явной ошибки построения правил. # ошибочная конфигурация правил subscribe = { '#': 'rubbish', '$SYS/#': 'broker', 'log/+/#': 2, } Как мы видим, под первое (жадное) правило будут подпадать абсолютно все топики и данные будет получать только узел с именем rubbidh. Два оставшихся правила никогда не будут выполнены т.к уже имеют более низкий логический приоритет. Чтобы исправить данную ситуацию, опустим самое "жадное" правило в конец списка. # правильная конфигурация правил subscribe = { '$SYS/#': 'broker', 'log/+/#': 2, '#': 'rubbish' } Что мы получим теперь. Правила не пересекаются Все данные с системного топика $SYS (данные по работе брокера) будут переданы Zabbix и адресованы узлу broker Все данные с топика log (условный раздел для логов) будут переданы узлам c именами соответствующими второму субтопику Все остальное (вообще все) будет передано узлу rubbish Также хочу отметить, что если, при использовании коротких имен топиков (mqtt_short_names = True), имя имя узла сети не будет найдено в адресе топика, то в ключе будет использован полный адрес топика, как будто бы короткие имена топика не используются вовсе (mqtt_short_names = False). mqtt_short_name = True subscribe = { 'serverRoom/rack2/zone4/temperature': 'zabbixServer', 'serverRoom/rack3/zone4/temperature': 'rack3', } В первом правиле будет использован полный путь топика т.к имя узла не будет найдено, а вот во втором правиле совпадение найдено будет и имя топика будет преобразовано в его короткий вариант. topic[serverRoom/rack2/zone4/temperature] # отправлено узлу zabbixServer topic[zone4/temperature] # отправлено узлу rack3 Короткие имена очень удобны в том случае, если требуется избавиться от лишних элементов в ключе. Например, если данные явно адресованы и сам узел сети несет информацию, связанную непосредственно только с ним. Это может быть, как сам брокер, так и набор различных сенсоров, определенных на Zabbix сервере как самостоятельные единицы. Рассмотрим это на примере шаблона для мониторинга MQTT брокера Mosquitto. Саму процедуру установки и настройки брокера я рассматривать не буду т.к предполагается, что брокер у Вас уже имеется. Мониторинг MQTT брокера Mosquitto В первую очередь нам понадобится сам шаблон, найти его можно в конце статьи. Импортируем его на Zabbix сервере, создаем узел сети, описывающий наш брокер и подключаем шаблон. Переходим в раздел "Мониторинг -> Последние" данные, выбираем наш узел и смотрим, что прилетает нам. Если Вы все сделали правильно, то увидите все данные по работе брокера. И как мы можем наблюдать, все ключи имеют короткие имена. Чтобы создать собственные элементы данных необходимо: Хость на, который отправляются данные, существовал на Zabbix сервере. Обращение идет по полю "Имя узла сети" Элемент данных был с типом "Zabbix траппер" Адрес обязан быть заключен в ключ topic[], например, topic[bytes/received] На этом все. Файлы проекта PS: Приятного использования и обязательно делитесь своими наработками и идеями.
  40. 2 балла
    Заметка о создании само подписанного сертификата для Apache под Linux Ubuntu сроком на 100 лет. Само подписанный сертификат "не есть плохо", учитывая, что со своими задачами он справляется также хорошо, как и его платные братья. Конечно, если использовать его в публичных проектах, то доверие пользователей к ресурсу начинает катастрофически падать, но если речь идет о внутренних ресурсах, организованных для небольшой группы лиц, то это решение выглядит очень аппетитно. Выбираем самый короткий путь, логинимся на сервере под пользователем root Создаем сертификат сроком на 100 лет. Почему на такой долгий? Да потому, что через год никто не вспомнит о том, что его надо пересоздать, да и важность ресурса далеко не банковского уровня. openssl req -x509 -nodes -days 36500 -newkey rsa:1024 -keyout /etc/ssl/private/apache.key -out /etc/ssl/certs/apache.pem Таким образом, сертификат стандарта X509 и сроком на 100 лет будет записан в файл /etc/ssl/private/apache.key, а его 1024 битный ключ в файл /etc/ssl/certs/apache.pem В процессе создания сертификата будут сыпаться различные вопросы от утилиты, можно пропускать все (прожимаем <ENTER>), кроме имени домена для которого этот сертификат и предназначается. Отметим, что пароль к сертификату запрашиваться не будет, об этом мы позаботились с помощью параметра -nodes. Да и пароль нам и не нужен, в противном случае его придется вводить при каждом запуске Apache. Теперь необходимо поправить ssl профиль для Apache. nano /etc/apache2/sites-available/default-ssl.conf Нам необходимо отключить поддержку SSLv2 и SSLv3 из-за проблем с безопасностью. Добавляем, а если он уже есть, то правим следующий параметр SSLProtocol all -SSLv2 -SSLv3 Указываем откуда подтянуть сертификат с ключом и сохраняем профиль SSLCertificateFile /etc/ssl/certs/apache.pem SSLCertificateKeyFile /etc/ssl/private/apache.key Выбираемся обратно в консоль и подключаем модуль SSL к Apache, а заодно подключаем наш обновленный профиль a2enmod ssl a2ensite default-ssl.conf Финалом торжества станет перезапуск сервера /etc/init.d/apache2 restart Если понадобится принудительно перенаправлять потребителей трафика с http на https протокол, то самым простым способом будет использование mod_rewrite a2enmod rewrite /etc/init.d/apache2 restart После идем в нужный каталог Apache и создаем там конфигурационный файл .htaccess со следующим содержимым RewriteEngine On RewriteCond %{SERVER_PORT} !^443$ RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R,L] Если не отрабатывает ни одно из правил, описанных в .htaccess, то вероятнее всего, в конфигурации Apache стоит запрет на его чтение. Идем в файл конфигурации nano /etc/apache2/apache2.conf Ищем описание настроек безопасности для корневого каталога Вашего web сервера <Directory /var/www/> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> И разрешаем всем описанным в фале .htaccess директивам отмену ранее установленных правил доступа AllowOverride All И снова перезапускаем Apache. Не забудьте обновить сертификат после окончания срока его действия, если здоровье еще будет позволять.
  41. 2 балла
    @Anykey дело в том, что снимаемые показания будут напрямую зависеть от качества проработки и исполнения устройства. Чем они хуже, тем больше мы будем получать устройство измеряющее частоту собственного вращения, никак не связанную с реальными показаниями скорости ветра, да и про линейность можно забыть. В итоге, на выходе может получиться устройство, которое дает только моральное удовлетворение от его же наличия и немного каких-то показаний которым, возможно, можно доверять только для фактического определения наличия ветра или других факторов заставляющих эти самые показания изменяться. На мой взгляд, необходимо учитывать все, начиная от радиуса окружности описывающей траекторию движения "чашек", заканчивая сопротивлением подшипника или другого устройства скольжения и силой которую необходимо приложить для того, чтобы эти самые чашки заставить сдвинуться с места. Опять же под вопросом, сохраниться ли линейность при разбросе температуры эксплуатации ±30 градусов Цельсия. И многое другое. PS: это мое личное мнение и оно ни в коем случае не претендует на истину в последней инстанции.
  42. 2 балла
    Вобщем, кое чё наваял. При падении узла (группы узлов) прога бомкает пока не жмякнешь на кнопку. Если через пять минут не поднялся - бомкает один раз. Через 20ть - жужжит один раз. Поднялся - пиликает один раз. И так по кругу. Автор (топикстартер) зачем-то не стал показывать ещё одну крутую возможность, которую он наваял - показ карт сетей. Видимо из-за того, что при повторном двойном клике на карту (после закрытия её), картинка не обновлялась. Проблему эту я решил топорно (а может и нет ) - просто делаю unset объекта. А php скрипт, передающий в прогу карты, банально переделал из найденного в гугле скрипта отрисовки графиков. Комментами и красотой кода особо не заморачивался. Так что не пинайте. А. И ещё - иконка в трее меняет цвет (ну это было ваще просто ). P.S. Насчёт карт - оказывается объяснение тут (тока заметил ) - zab.zip
  43. 2 балла
    @Small_d Приветствую, автор дополнения немного поспешил и допустил ошибку в программе микроконтроллера. Был не указан порядковый номер адреса ключа. Должно быть так. // Читаем ключ for(byte i=0; i<4; i++) key += mfrc522.uid.uidByte[i]; Все изменения от @svchekalin не проверял. Будем разбираться по мере необходимости. Что касаемо кодировок, попробуйте изменить php файл таким образом, чтобы html разметка была похожа не что-то подобное. <html lang="ru-RU" dir="ltr"> <head> <title>Заголовок</title> <meta charset="utf-8"> </head> <body> Тут само тело или PHP сценарий </body> </html>
  44. 2 балла
  45. 2 балла
    Извиняюсь за назойливость! Приятно когда всё работает как хотелось!
  46. 2 балла
    Доброе время суток. Хочу поделиться опытом автоматизации изобретения Джона Уэбстера - Жалюзи, что в переводе с Французского звучит как Ревность! Скажу честно, что мой опыт обуздать это не хитрое устройство имеет как положительный, так и отрицательный результат. И я буду очень рад поделиться им с Вами, дабы Вы не совершали моих ошибок, и результат Вашей работы вызывал настоящую Ревность у всех, кто её видит! Первое с чего стоит начать это изучить конструкцию механизма Ваших жалюзи. У меня дома внедрен и плотно эксплуатируется в спальне механизм с вертикальным расположением ламелей. Сам механизм прост как две копейки. Веревка с расположенными на ней пластиковыми шариками вращает вал, который производит поворот всех секций с ламелями. Ничего лишнего, устройство работает как часы. Второе, и самое главное (на чем я прокололся), это выбор привода для управления механизмом. Я правильно подумал, что для поворота всех секций необходимо довольно большой крутящий момент и дать его мне может сервопривод. Решено было взять серву MG995 с металлическими шестернями, крутящим моментом 13 кг. на сантиметр и переделать её в сервопривод постоянного вращения. Сама процедура модернизация "мускул" проекта очень проста. Аккуратно разбираем привод (внутри много смазки) и запоминаем его устройство. На основной шестерни расположен ограничитель хода (простой цилиндр из другого метала, отличается цветом от шестерней), удаляем его (без усилия вытягивается плоскогубцами). Вынимаем всю электронику и запоминаем расположения контактов переменного резистора необходимого для позиционирования устройства. Удаляем переменный резистор и заменяем его двумя обычными и равными половине номинала удаленного органа (в моем случае это два резистора по 2.5 кОм). Полагаю, что можно воспользоваться любыми резисторами одинакового номинала до 10 кОм. Но это стоит перепроверить! Собираем все обратно. К сожалению, у меня не сохранились фотографии всего процесса извращения над сервоприводом. Запечатленным остался лишь момент замены не нужного переменка на делитель из постоянных резисторов. Далее идет примерка сервы к поворотному шкиву Жалюзи и соответственно попытки приколхозить привод к нему. Ничего сложного в этой операции нет. Можно использовать один из рычагов идущих в комплекте с сервоприводом. Но я решил заменить подходящий пластиковый рычаг, на железный, купленный отдельно. Пара минут манипуляций и союз между шкивом и рычагом (хотя второй тоже выглядит как шкив, тфу... масло масляное...) заключен. Позже, было принято решение перевернуть крепежные болты дабы сохранить возможность установки фиксирующей крышки от Жалюзи. На самом деле позже было принято очень много решений. После теста возможностей сервопривода был выявлен один крошечный недостаток, но он убивал на корню всю возможность автоматизации. Это был дребезг (другого слова я подобрать не могу) который заставлял привод совершать еле заметные и слышимые дерганья в произвольном направлении, но иногда постоянно в одном, что могло привести к натяжению поворотного вала Жалюзи в одном из крайних положений. Причина крылась в неидеальности нашего мира. Создать идеальный резистор не подверженный окружающей среде способна только задача из учебника по физике. А в результате, как только в комнате изменялась температура, даже на короткий миг, один из резисторов менял свои свойства. Вот тут и проявлялись те самые 1%, 5%, 10% погрешностей которые обещал производитель. Мириться с этим я не мог! Решений было два: Разобраться в устройстве мозгов сервопривода и заложить эту погрешность в программу микроконтроллера сервы. Купить заводскую серву постоянного вращения. И как Вы угадали, я сделал единственно верный выбор! Заказал новую серву и ею стало произведения Китайского искуства - модель DS04-NFC. Пластиковые шестерни, крутящий момент 5,5 кг. на сантиметр. Взяв её в руки, и сравнив с предшественницей, я отчетливо испытал чувство со столь красивым названием Жалюзи! Да это была Ревность! Как можно променять MG995 на DS04-NFC, каааакккк! Каарррлл скажииии, каааааккк! Ладно, боль стихла, выбор сделан. Необходимо проверить её в деле. И забегая вперед, я обязан сказать, что новая серва была подвержена той же болезни, что и переделанная MG995. Фокус не удался, но исправить проблему получилось программно в самом скетче! Тут стоит сделать небольшой отступ и для Новичков вроде меня дать пояснение. Питать сервопривод от самого контроллера невозможно т.к привод высасывает все соки из питающей линии. Контроллер начнет задыхаться и уйдет в ребут. Для исправления данного недостатка я посадил параллельно нестабилизированного входа Arduino преобразователь AMS-1117-5.0 (Китайский клон LM-1117-5.0). Таким образом, я могу подавать питание (рекомендую 7-9V) на вход платы c контроллером и иметь раздельное стабилизированное питание, как самого контроллера, так и сервопривода. Фокус удался... Думаю, что схему параллельного соединения приводить нет смысла. Добавлю лишь обвязку преобразователя (два танталовых конденсатора по 10mF). Для первого раза было решено использовать управление от старого пульта TV-тюнера. Ну, раз пошла такая пляска, то в довесок выдернуть из TV-тюнера IR приемник и гнездо для него. Если быть честным, то я не собирался потрошить тюнер, но один из моих Китайских поставщиков электроники решил меня обмануть кинуть (скажу по секрету, это был не его день!). Пару тройку минут с паяльником и в руках красуется изделие способное произвести неимоверное впечатление на средневекового человека, но не на нас. Выглядит этот колхоз следующим образом. Согласен, не очень красиво но, что я могу поделать. Исправлю в следующей версии. Переходим к программной части По началу стоит определиться с командами, на которые будет реагировать контроллер. Это зависит только от используемого Вами пульта дистанционного управления. За основу я взял библиотеку Arduino-IRremote-master.zip В комплекте куча примеров чтобы научиться с ней дружить. Ну а итоговый скетч будет выглядеть следующим образом #include <IRremote.h> #include <Servo.h> byte PIN_IR = 8; byte PIN_SERVO = 9; IRrecv irrecv(PIN_IR); decode_results ir; Servo myservo; unsigned long timer = 0; unsigned long lSpeed = 0; unsigned long rSpeed = 0; byte Speed; int fullSpeedTime = 3000; // Время в миллисекундах, за которое серва выходит на полную скорость void setup() { Serial.begin(9600); irrecv.enableIRIn(); } void loop() { if (irrecv.decode(&ir)) { //Serial.println(ir.value); // Поворот направо if(ir.value == 117192113) { timer = millis(); if(rSpeed == 0) rSpeed = millis(); Speed = map(millis()-rSpeed<fullSpeedTime?millis()-rSpeed:fullSpeedTime, 0, fullSpeedTime, 100, 180); Serial.println("Servo turns to the right. Speed " + String(Speed)); myservo.attach(PIN_SERVO); myservo.write(Speed); } // Поворот налево else if(ir.value == 1819890863) { timer = millis(); if(lSpeed == 0) lSpeed = millis(); Speed = map(millis()-lSpeed<fullSpeedTime?millis()-lSpeed:fullSpeedTime, 0, fullSpeedTime, 100, 0); Serial.println("Servo turns to the left. Speed " + String(Speed)); myservo.attach(PIN_SERVO); myservo.write(Speed); } irrecv.resume(); } else { // Обнуляем все задействованные таймеры и отключаем серву if(timer != 0 and millis() - timer > 200) { rSpeed = lSpeed = timer = 0; myservo.detach(); // <- Именно этот костыль заставляет серву молчать Serial.println(F("Servo stop\n")); } } } В программе используется плавный разгон сервопривода до максимальных скоростей. За это отвечает переменная fullSpeedTime, принимающая значения в миллисекундах. Думаю, что трех секунд достаточно, чтобы плавно регулировать разгон и тем самым позволить, в случае необходимости, управлять поворотом ламелей на очень малый угол, используя кратковременные нажатия на кнопку пульта дистанционного управления. Углы поворота влияют на скорость: от 0 до 100 от 100 до 180 Это те значения, что получились у меня на двух сервах, и которые я использовал в скетче. Чтобы заставить сервопривод не дергаться во время простоя я произвожу его отключение с использованием метода myservo.detach(); Все прекрасно отработало. Серва крутит, а в простоях молчит и даже не думает дернуться. Привожу еще немного снимков всей получившейся конструкции Самый главный вывод - стоит подобрать очень тихий привод. Серва жутко шумит, и если днем это терпимо, то вечером или ночью... это будет ужасно. PS: В общем первая версия была проверена и зарекомендовала себя хорошо, правда выглядит ужасно. Планирую добавить пару датчиков освещенности и автоматически менять угол поворота ламелей в зависимости от освещенности в течении дня. И заменить серву на тихий шаговый двигатель c редуктором.
  47. 2 балла
    Точное время - всегда актуальный вопрос. В большинстве случаев высокая точность не нужна и настроить время на вашем оборудовании можно по наручным, кухонным или напольным с кукушкой часами, да хоть по положению солнца, и этого будет более чем достаточно для большинства людей. Но вот, что делать, если хочется высокой точности? Верно, начинаем синхронизироваться с любым попавшимся NTP сервером в интернете, он в свою очередь синхронизируется с другим (возможно даже более точным, а может быть и нет) сервером. Цепочка может быть достаточно длинной, но в один прекрасный день может появится желание убрать посредников и найти самые точные часы на планете и спрашивать время у них. А какие часы самые точные? Атомные! Кстати на wikipedia имеется отличная статья про время! И вот тут пораскинув мозгами, начинаем судорожно вспоминать, в каком это супермаркете мы последний раз видели их в продаже и желательно с USB интерфейсом, можно даже розового цвета... Вы тоже не видели? Печаль. А ведь у нас над головой, на высоте порядка 19400 км висят куча спутников систем позиционирования (GPS / ГЛОННАС), а чтобы они работали им нужно знать точное время. Именно для этой цели у каждого из этих трудяг на борту имеются атомные часы! Отлично, давайте узнавать время у этих ребят. И так, немного задержавшись на сайте MikroTik можно найти пакет gps-xx.xx.npk который позволяет расширить возможности маршрутизатора и позволит ему определять свои точные координаты на поверхности нашей планеты. Чтобы установить пакет, достаточно просто скопировать его на маршрутизатор (сделать это можно перетащив .npk файл в файловый менеджер WinBox) и перезагрузиться. Теперь нам нужен GPS приемник. Общение будет идти по протоколу NMEA 0183, PDF. Мой маршрутизатор собран на базе стационарного компьютера, а следовательно можно смело брать приемник с USB интерфейсом. В наличии имеется отличный экземпляр от GlobalSat - BU-353U4. После подключения приемника переходим к настройки маршрутизатора. [admin@Kitsum] > port print Flags: I - inactive # DEVICE NAME CHANNELS USED-BY BAUD-RATE 0 serial0 1 Serial Console 9600 1 3:2 usb2 1 4800 Отлично, маршрутизатор видит что-то на порту usb2, запоминаем его Flag (1) и выставляем настройки согласно техническим характеристикам от производителя. Естественно, что для Вашего "свистка" настройки могут отличаться. [admin@Kitsum] > /port [admin@Kitsum] /port> set numbers=1 baud-rate=4800 data-bits=8 parity=none flow-control=none stop-bitsrs=1 Все настройки с портами Вы можете провести через Web интерфейс или WinBox в разделе System -> Ports Теперь осталось дело за малым. Сообщим маршрутизатору, что на порту usb2 висит GPS приемник, и он может им овладеть, то есть воспользоваться, ... блин использовать! И естественно, мы желаем, чтобы время, полученное в телеграмме от спутников считалось эталонным и использовалось как системное. [admin@Kitsum] > /system gps [admin@Kitsum] /system gps> set enabled=yes port=usb2 set-system-time=yes Теперь мы может посмотреть, какими именно данными мы начали располагать в следствии, этих сверх сложных манипуляций! Внимание: естественно, что при холодном старте, данные начнут поступать не сразу. [admin@Kitsum] > /system gps [admin@Kitsum] /system gps> monitor date-and-time: feb/08/2016 14:44:42 latitude: N 00 18' 13.236'' longitude: E 00 54' 5.236'' altitude: 325.299988m speed: 0.000000 km/h destination-bearing: none true-bearing: 133.419998 deg. True magnetic-bearing: none valid: yes satellites: 9 -- [Q quit|D dump|C-z pause] В данном случае получилось поймать сигнал с 9 спутников. Каждый из них передает нам свои координаты, а самое главное - время со встроенных атомных часов. Большая часть информации вычисляется уже по месту (скорость, высота ...). Мы практически добились нужного результата. Естественно мы получаем время по Гринвичу (UTC+0), меня это не устраивает, видимо и Вас тоже. Необходимо подправить часовой пояс. Это можно сделать в System -> Clock [admin@Kitsum] > /system clock [admin@Kitsum] /system clock> set time-zone-autodetect=no time-zone-name=Europe/Moscow И так, теперь Ваш маршрутизатор знает самое точное время на планете и им стоит поделиться хотя бы со всеми желающими в локальной сети. А таких поверьте, будет не мало. В современном мире все устройства жаждут обладать этой информации. Как же без этого Вам кофеварка сварит благородный напиток, или телевизор выключится и оградит молодое поколение от всего того, что оно и так потом узнает, а пока должно делать уроки, ммм? Необходимо поднять собственный NTP сервер и делается это сверх сложной и длинной командой. [admin@Kitsum] > /system ntp server [admin@Kitsum] /system ntp server> set enabled=yes manycast=yes Ну, или просто выставлением соответствующей галочки в System -> NTP Server И все было бы просто великолепно, если бы устройства в сети знали, что мы владеем более точным временем, чем time.windows.com, time.nist.gov да и сотни других серверов. Первая мысль, которая посетила меня - просто подменю ip адреса в записях DNS и "вуаля", но я даже понятия не имею с чем синхронизируется мой телефон, телевизор и у кого, после очередного обновления, захочет узнать время мой компьютер. Мы знаем, что NTP протокол использует 123 UDP порт для общения. Предлагаю перехватывать все запросы, из нашей локальной сети, адресованные на этот порт во внешний мир и заворачивать их на внутренний IP маршрутизатора! У меня все сетевые интерфейсы локальной сети объедены в Bridge и весь трафик ходит во внешний мир через через NAT и masquerade, внутренний адрес маршрутизатора 10.10.10.1 Добавим новое правило в NAT [admin@Kitsum] > /ip firewall nat [admin@Kitsum] /ip firewall nat> add action=dst-nat chain=dstnat dst-port=123 in-interface=bridge1 protocol=udp to-addresses=10.10.10.1 to-ports=123 На этом все. PS: зачем? потому что хочется и есть возможность!
  48. 2 балла
    Ко мне обратился товарищ с просьбой уменьшить размер данного скетча т.к. места в его проекте уже совсем нет, а авторизация необходима как воздух. Мое мнение, что стоило бы сменить контроллер, было отвергнуто в силу долгого ожидание посылки из поднебесной и хочется прямо здесь и сейчас. Необходимо выбросить лишнее и сэкономить крошки на ATmega328p устанавливаемой в Arduino UNO / NANO Компилируем изначальный скетч (под чип W5100) и смотрим, сколько он весит, это будет отправной точно. Sketch uses 15 908 bytes (49%) of program storage space. Maximum is 32 256 bytes. Global variables use 524 bytes (25%) of dynamic memory, leaving 1 524 bytes for local variables. Maximum is 2 048 bytes В ходе быстрого кромсания выкидываем: библиотеку Base64, функцию auth_update() и все переменные, связанные с авторизацией. Хочу заметить, что изначально подразумевалось все это использовать для возможности изменять учетные данные в Web морде и хранить их в EEPROM. В угоду экономии места логин и пароль будет жестко задан в программе. Проверка авторизации осуществляется в 40 строке кода, в неё же зашит хэш Base64 - login:password if (readString.lastIndexOf(F("Authorization: Basic bG9naW46cGFzc3dvcmQ="))>-1) { После повторно компилируем программу и сравниваем вес. Sketch uses 14 756 bytes (45%) of program storage space. Maximum is 32 256 bytes. Global variables use 414 bytes (20%) of dynamic memory, leaving 1 634 bytes for local variables. Maximum is 2 048 bytes Получаем экономию: Скетч уменьшился на 4%, что составляет 1152 байта Оперативка освободилась на 5%, что составляет 110 байт Не густо, но этого оказалось достаточно, по этой же причине данный пост получил право на жизнь. Остается только придумать логин и пароль и самостоятельно получить из них хеш Base64, а затем вписать его в скетч. Напоминаю, что логин и пароль пишутся одной строкой через разделитель двоеточие ":". Если для примера взять логин Admin, а пароль СhIcKeN, то должна получится строка Admin:СhIcKeN Пишем её в наш online конвертер Base64 и получаем на выходе необходимый нам хеш QWRtaW46Q2hJY0tlTg== Base64 online converter Текст в Base64 (encode) Base64 в Текст (decode) PS: идея онлайн конвертера Base64 взята с сайта http://webtoolkit.info, в связи с этим я обязан разместить на них ссылку.
  49. 2 балла
    Данный пост является шпаргалкой из собранных в сети различных материалов связанных с распиновкой (pinout) распространенных микроконтроллеров и плат на их основе. Микроконтроллеры ATmega328p-pu ATmega328p-au ATmega2560 ATmega32u4-au Attiny Платы Arduino UNO Arduino NANO Arduino PRO-MINI Arduino MICRO Arduino MEGA Arduino LEONARDO Arduino Yun Arduino Esplora Arduino Fio
×
×
  • Создать...