Русский
Русский
English
Статистика
Реклама

Raspberrypi

KODI собираем удобный и функциональный медиацентр для дома. Часть 6. Синхронизация медиатеки. MariaDB

12.04.2021 02:07:50 | Автор: admin

Лирическое отступление

Уже более года в качестве медиацентра использую KODI. Начиналось всё с каких-то базовых вещей, но даже от такого функционала я был в полном восторге. Просмотр ТВ, фильмов и сериалов теперь не выглядит каким-то квестом, а все мои домашние также полюбили KODI, и я даже не представляю, как раньше могли справляться без него.

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

Если вы пропустили предыдущие публикации обязательно загляните в них, возможно и для вас найдется что-то интересное. Если в двух словах установили и настроили с нуля ОС и KODI, настроили просмотр торрент-контента, YouTube, IPTV. Поговорили об управлении с других устройств, резервном копировании, анализе трафика и даже научили KODI запускать ретро-игры.

Все предыдущие публикации:

KODI: собираем удобный и функциональный медиацентр для дома. Часть 1
KODI: собираем удобный и функциональный медиацентр для дома. Часть 2
KODI: собираем удобный и функциональный медиацентр для дома. Часть 3. Ретро-игры
KODI: собираем удобный и функциональный медиацентр для дома. Часть 4. Архив IPTV
KODI: собираем удобный и функциональный медиацентр для дома. Часть 5. Яндекс.Музыка

Зачем это все затевалось?

Среди медиаустройств, в моем домашнем обиходе два телевизора. Основной в гостиной работает с KODI, второй на кухне под управлением Tizen OS. Мысль о том, что последнего также нужно посадить на KODI возникла спустя пару недель после запуска медиацентра на основном телевизоре. Но руки все никак не доходили

Каждый раз, переключая ужасного качества каналы кабельного ТВ на кухне, я вспоминал о своей затее. И вот пришло время воплотить ее в жизнь. Для этой задачи в поднебесной был заказан Raspberry Pi 3 и все та же аэромышь, как и для основного телевизора (подробнее о ней в первой части).

Итого, в гостиной KODI на базе неттопа с Kubuntu 20.04 на борту, на кухне LibreELEC на базе третьей малинки.

Кухонный медиацентр должен выполнять всего две задачи:
просмотр IPTV. Буду использовать все тот же сервис ilook и дополнение PVR IPTV Simple Client. К слову, сервис позволяет использовать плейлист на двух устройствах без дополнительной платы за тариф.
просмотр торрент-видео. Потому как локальной библиотеки фильмов и сериалов у меня нет.

О том, как установить LibreELEC на малинку описывать, думаю, не стоит. А как подключить IPTV и Elementum для просмотра торрентов я рассказывал в другой публикации.

Общее понимание архитектуры есть, причем же здесь MariaDB в заголовке? Представьте, вы смотрите фильм в гостиной, идете обедать на кухню и продолжаете просмотр ровно с того места, на котором остановились. Здорово, не правда ли?

KODI позволяет реализовать синхронизацию медиатеки на разных устройствах. Для этого потребуется MySQL-сервер, на котором и будет храниться эта медиатека. Сервер может быть поднят на совершенно сторонней машине, хоть под управлением Windows. В моем случае, основной медиацентр работает 24/7, аппаратные ресурсы позволяют сервером назначает его, на нем и будем поднимать базу данных.

Надеюсь, суть и прелести такой архитектуры домашних медиацентров понятна.

Подготовка серверной части. MariaDB

Прочитав Wiki на официальном сайте KODI, решил, что все довольно просто и понятно бери и делай. Но на практике оказалось все иначе БД не наполняется моей медиатекой, в логах ошибки не поддаются пониманию или записей нет вообще, от того понять, что сделано не так достаточно трудно. Второе устройство подключать к БД смысла нет синхронизировать нечего.

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

Особенности:

  • Использовать MariaDB;

  • Медиатека должна быть размещена в сетевом каталоге;

  • Все пути к медиатеке на всех устройствах должны быть абсолютные;

  • Сетевые каталоги NFS или SMB, если вынуждены использовать NTFS, то только с авторизацией по учетной записи с паролем;

  • Версии KODI на всех устройствах должны быть одинаковы.

С задачей и подводными камнями разобрались приступаем к работе. Напомню, сервером у нас будет KODI на неттопе с Kubuntu 20.04.

Устанавливаем сервер MariaDB

sudo apt updatesudo apt install mariadb-server

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

Запускаем скрипт безопасности

sudo mysql_secure_installation

Откроется серия диалогов, где можно внести некоторые изменения в параметры безопасности установки MariaDB. Параметры установите, исходя из собственной безопасности. Учитывая, что моя БД будет наполняться лишь медиатекой и находится она в изолированной домашней сети сделал так:

root@kodi-pc:/# sudo mysql_secure_installationNOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB      SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!In order to log into MariaDB to secure it, we'll need the currentpassword for the root user.  If you've just installed MariaDB, andyou haven't set the root password yet, the password will be blank,so you should just press enter here.Enter current password for root (enter for none):

Пароль не задаем, нажимаем ENTER.

Setting the root password ensures that nobody can log into the MariaDBroot user without the proper authorisation.Set root password? [Y/n]

Отклоняем (N).

By default, a MariaDB installation has an anonymous user, allowing anyoneto log into MariaDB without having to have a user account created forthem.  This is intended only for testing, and to make the installationgo a bit smoother.  You should remove them before moving into aproduction environment.Remove anonymous users? [Y/n]

Удаляем (Y).

Normally, root should only be allowed to connect from 'localhost'.  Thisensures that someone cannot guess at the root password from the network.Disallow root login remotely? [Y/n]

Отклоняем (N).

By default, MariaDB comes with a database named 'test' that anyone canaccess.  This is also intended only for testing, and should be removedbefore moving into a production environment.Remove test database and access to it? [Y/n]

Удаляем (Y).

Reloading the privilege tables will ensure that all changes made so farwill take effect immediately.Reload privilege tables now? [Y/n]

Соглашаемся (Y).

Теперь создадим пользователя, из-под которого будут работать с БД наши медиацентры. Для создания пользователя kodi с паролем kodi запускаем оболочку MariaDB и выполняем команду

sudo mariadbGRANT ALL ON *.* TO 'kodi'@'localhost' IDENTIFIED BY 'kodi' WITH GRANT OPTION;

Разрешаем доступ с любого хоста ко всем базам данных на сервере для пользователя kodi

GRANT ALL PRIVILEGES ON *.* TO kodi@'%' IDENTIFIED BY 'kodi';

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

FLUSH PRIVILEGES;

Оболочку MariaDB можно закрывать, выполнив команду

exit

Для организации доступа вне локального хоста, необходимо указать порт 3306 и bind-address 0.0.0.0. Открываем конфигурационный файл MariaDB

sudo mcedit /etc/mysql/mariadb.conf.d/50-server.cnf

Раскомментировать параметр

port = 3306

Для параметра bind-address установить 0.0.0.0 (вместо 127.0.0.1)

bind-address = 0.0.0.0

Для применения изменений перезапускаем MySQL-сервер

sudo service mysql restart

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

Как вариант - MySQL Workbench.

Создаем новое подключение:
Connection Method - Standart (TCP/IP)
Hostname 192.168.0.50 (заменить на адрес вашего сервера)
Port 3306
Username kodi (имя пользователя, если создавали своего)

Нажимаем Test Connection, вводим пароль и в случае, если все корректно получаем соответствующее сообщение:

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

Подготовка серверной части. KODI

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

Библиотеку мы настраивали еще в первой части. Никуда ее не переносим, пути оставляем прежние:
/mnt/kodi/library/Movies библиотека фильмов
/mnt/kodi/library/Shows библиотека сериалов

Необходимо лишь расшарить каталог /mnt/kodi/library. Конфигурируем samba

sudo mcedit /etc/samba/smb.conf

В конец конфигурационного файла вставляем:

[library]comment = librarypath = /mnt/kodi/library/browsable = yeswritable = yesguest ok = yesread only = noforce user = nobodyforce group = nogroupforce create mode = 0777force directory mode = 0777

И перезапускаем сервис samba

sudo /etc/init.d/smbd restart

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

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

Переходим в Настройки/Медиа/Медиатека/Видео и в существующих источниках Movies и Shows изменяем пути на нужные, выбрав Добавить сетевой адрес. В качестве логина и пароля используйте данные вашей учетной записи в Kubuntu.

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

Теперь дадим понять KODI, что мы хотим работать с базой данных. Для этого в файле advancedsettings.xml (/home/имя_пользователя/.kodi/userdata/) добавить:

<advancedsettings>  <videodatabase>    <type>mysql</type>    <host>192.168.0.50</host>    <port>3306</port>    <user>kodi</user>    <pass>kodi</pass>  </videodatabase>  <videolibrary>    <importwatchedstate>true</importwatchedstate>    <importresumepoint>true</importresumepoint>  </videolibrary></advancedsettings>

Если файл advancedsettings.xml отсутствует создайте его вручную. Параметры изменить в соответствии с вашими настройками, где:
Host IP-адрес вашего MySQL-сервера;
User имя пользователя MariaDB;
Pass пароль пользователя MariaDB.

На стороне сервера всё готово. Можно проверить. Перезапускаем KODI и, в зависимости от объема вашей медиатеки, ждем какое-то время, пока KODI ее обработает.

Информация о моей медиатеке:
Фильмов 322
Сериалов 68

Размер - 380 Кб

Общее количество файлов (nfo и strm) 3826

Моя медиатека обрабатывалась порядка 10 минут. По завершении обновления медиатеки давайте посмотрим на нашу БД. Снова подключаемся к серверу с помощью MySQL Workbench.

Как видим, KODI самостоятельно создал БД MyVideos119 и наполнил ее всеми нашими фильмами и сериалами. Например, в таблице Movie - фильмы. Значит, мы все сделали правильно.

После завершения импорта медиатеки в БД, можно еще оценить и ее ресурсопотребление. Моя медиатека заняла в ОЗУ чуть более 100 Мб. Это дает понять, что, даже значительный рост количества фильмов и сериалов, не скажется на производительности основного моего медиацентра.

Настройка клиентской части

Настройки других устройств, которые необходимо синхронизировать с сервером, очень просты:

  • advancedsettings настраиваем, также как на сервере;

  • добавляем источники в Настройки/Медиа/Медиатека/Видео также, как и на сервере, указывая абсолютные сетевые пути;

  • если вы, как и я используете дополнение Elementum в его настройках также изменить пути на абсолютные до сервера (путь к библиотеке и путь к торрент-файлам). Таким образом, где бы вы не начали смотреть (скачивать) фильм, сохранится он на сервере. Да и в моем случае, не рационально было бы для малинки иметь свое файловое хранилище.

Для упрощения настройки своей малинки я просто перенес конфигурационные файлы с основного медиацентра:

/home/kodi/.kodi/userdata/advancedsettings.xml
/home/kodi/.kodi/userdata/sources.xml
/home/kodi/.kodi/userdata/addon_data/plugin.video.elementum/settings.xml
/home/kodi/.kodi/userdata/addon_data/script.elementum.burst/settings.xml

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

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

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

Всем хорошего времяпрепровождения с медиацентром KODI!

Подробнее..

О чем спорят строители Умных Домов, Бань, Дач и Гаражей

29.04.2021 08:22:29 | Автор: admin

Я Community Manager и у меня есть зависимость. Ну хорошо, не зависимость, но хобби: я увлекаюсь автоматизацией собственной квартиры с помощью того, что принято теперь называть Умным Домом. Начинал я пару-тройку лет назад с чистого Apple HomeKit, затем расширил его возможности с помощью Homebridge и далее полностью погрузился в дебри HomeAssistant.

Но поскольку я Community Mananger, мне интересна та часть моего хобби, которая касается вопроса коммуникации сообщества людей, имеющих такое же увлечение, как и моё.

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

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

Предыстория

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

Мой путь начался с того, что в один прекрасный момент я внезапно осознал, что имеющийся в хозяйстве AppleTV 4K может служить шлюзом для построения Умного Дома на базе Apple HomeKit. Было приобретено и успешно подключено несколько HomeKit ready устройств. Все было прекрасно, стабильно, но дорого. Хотелось дальнейшего расширения, но за меньшие деньги.

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

Так, с помощью внимательного чтения и вопросов к коллективному разуму я влился в обширное и очень эффективное русскоязычное сообщество строителей Умных Домов, Бань, Дач и прочих Гаражей. Мир DIY и OpenSource решений захлестнул меня и, нужно заметить, я был к этому подготовлен. Я уверенно обращался с паяльником и имел очень долгий опыт работы с Linux. Мне было легко и приятно быть среди единомышленников.

С каждой новой итерацией своего продвижения по этому пути все новые и новые ресурсы открывались мне, с великими Гуру можно было спокойно общаться в телеграм группах практически на одном языке и порой даже осмеливаться их критиковать. Я узнал, что большинство самых ценных сообществ живет в профильных телеграм каналах, что сообщество на форуме 4PDA живет какой-то своей жизнью, что известный всем русскоговорящим умнодомщикам Спрут портал раскинул свои щупальца настолько широко, что даже проник на территорию подкастов и инстаграма, что адепты св.Квазиса повсюду и что AlexxIT, Jager, Илья Киров и Иван Бессарабов настолько же доброжелательны и приветливы в общении, насколько круты в своем профессионализме. А для владеющих английским открываются поистине бездонные кладези знаний на Reddit, YouTube и, например, официальном форуме HomeAssistant.

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

OpenSource против готовых решений

Xiaomi MiHome стал уже символом консьюмерской системы Умного ДомаXiaomi MiHome стал уже символом консьюмерской системы Умного Дома

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

На чем строить свой Умный Дом? На готовых решениях от Miija, Sonoff, Tuya, Apple, Aqara, Rubetek, Yandex, Google и прочих и прочих? Или же построить его самому на базе OpenSource решений типа HomeAssistant, NodeRed, OpenHub, IOBroker и так далее?

NodeRed очень популярное OpenSource решение для Умного ДомаNodeRed очень популярное OpenSource решение для Умного Дома

Тем, кто стоит перед таким выбором приходят на помощь авторитетные прожженные линуксоиды и начинают говорить о непревзойденной гибкости автоматизаций и отвязки от коварных "китайских облаков" в OpenSource решениях. Они будут говорить о том, что все будет контролироваться только лично тобой и что ты сможешь использовать почти весь доступный на рынке зоопарк устройств Умного Дома, да еще и DIY устройства. Стоит лишь купить "малинку", установить на нее Linux, потом поколдовать в командной строке, чтобы установить этот самый альтернативный Умный Дом, а потом еще потратить месяцы на настройку и понимание что вообще тут к чему.

И вот новичок, который про Linux только на уроках информатики слышал, а командную строку видел только в голливудских блокбастерах про геройских хакеров, обалдев от такого объема информации, мало ему понятной, принимает решение переплатить, но сделать свой Умный Дом легко и просто на базе существующих на рынке готовых решений. Или вообще ничего не делать. И правильно сделает, кстати.

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

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

Малинка против Intel NUC, Gigabyte BRIX и прочих x86

Та самая знаменитая "Малинка" Raspberry Pi 4 Та самая знаменитая "Малинка" Raspberry Pi 4

Итак, новоявленного строителя Умного Дома затащили на темную сторону OpenSouce и перед ним встает первый из ключевых вопросов: а на что мне все это хозяйство устанавливать?

Популярность использования платформы Rapberry Pi для сервера Умного Дома я могу объяснить лишь пресловутыми "исторически сложившимися причинами", а так же, не в последнюю очередь, мощью авторитета Алекса Квазиса и его YouTube канала.

При всех своих недостатках, "малинка" остается самой популярной платформой и поныне. А недостатки у нее серьезные:

  1. Использование в качестве накопителя медленной и очень ненадежной SD карты

  2. Необходимость в хорошем охлаждении

  3. Склонность к троттлингу при недостаточно качественно обеспеченном питании

  4. Слабый встроенный Bluetooth

  5. Довольно слабая производительность ARM процессора, которой, впрочем, в большинстве случаев достаточен для систем Умного Дома

  6. Важная для многих необходимость в приличном корпусе

Для устранения части этих недостатков потребуется покупка SSD или eMMC накопителя, мощного корпуса-радиатора, внешнего Bluetooth донгла, корпуса вроде Argon One. Все эти дополнительные покупки приводят к значительному удорожанию вашего сервера Умного Дома на базе "малинки".

И тут на авансцену выходят опытные члены сообщества с вполне резонным вопросом: А почему бы вам сразу не купить компактное, бесшумное и быстрое решение на базе гораздо более производительных процессоров x86 с встроенным SSD диском, расширяемой памятью? Ну, например, что-нибудь подходящее по цене из обширного семейства миниатюрных компьютеров Intel NUC или Gigabyte BRIX?

Очень популярный Intel NUCОчень популярный Intel NUC

В действительности цены на подобные новые минисерверы довольно высоки и далеко не каждый будет готов потратится. Но на просторах интернет барахолок, вроде Avito, вполне можно найти приличные варианты за вменяемые деньги. Я, например, купил там немного устаревшую модель Gigabyte BRIX с процессором Celeron N3000, 4GB RAM, 120GB SSD и пассивным охлаждением всего за 5 тысяч рублей. И машинка эта прекрасно работает в круглосуточном режиме с HomeAssistant на борту вот уже больше года. Некоторые домовладельцы покупают на Авито даже подержанные HP Microserver Gen8 под свой домашний сервер, на котором, кроме системы Умного Дома, работает еще и медиасервер, торрент-качалка, NAS и что-нибудь еще. Многие используют в качестве сервера Умного Дома уже имеющиеся в хозяйстве NAS от Synology или реже Qnap с поддержкой Docker. Но в этом варианте много подводных камней, которые вызывают множество вопросов и дискуссий. Этот вариант сервера, на мой взгляд, подходит только уверенным пользователям Linux с достаточно глубокими знаниями Docker.

На мой взгляд, если говорить о сервере только для Умного Дома, наиболее целесообразным вариантом сейчас является использование миникомпьютеров на базе процессоров x86 (не Atom!). Это могут быть не обязательно Intel NUC или Gigabyte BRIX, а любой подходящий на базе Celeron и выше, и желательно с пассивным охлаждением, особенно для тех, кто строит Умный Дом в городской квартире и для кого уровень шума сервера является критическим параметром. Наличие именно SSD диска не обязательно, но крайне желательно для общего быстродействия. Памяти в большинстве случаев достаточно 2-4Gb. Подключать к сети такой сервер рекомендую по более надежному Ethernet, но и по WiFi 5Ггц у многих работает вполне стабильно.

Zigbee против WiFi (BLE mesh, Zwave, Thread пока не в счет)

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

У всех дома есть WiFi роутер и, как правило, Умный Дом начинает разрастаться за счет недорогих WiFi устройств от производителей вроде Sonoff, Yeelight, DIY устройств на базе ESP8266 и прочих. Действительно, WiFi прост, есть у всех, дополнительно что-то приобретать и настраивать не нужно. Отсюда в сообществе происходят иногда не то чтобы споры, но оживленные дискусси с основным посылом - зачем мне вообще этот ваш "зигбее" (варианты написания бывают порой очень забавными, "zig been" как-то попадался), мне и на WiFi хорошо и все отлично работает. Мне кажется это мнение происходит от недостаточно хорошего представления о преимуществах протокола Zigbee новичками. Давайте их перечислим:

  • Низкое энергопотребление конечных устройств (где вы найдете WiFi датчик двери или, например, датчик движения, датчик протечки, который работал бы от батарейки годами?)

  • Самоорганизующаяся Mesh сеть, в отличие от звездообразной WiFi сети, где роутер является центром звезды. Например, так выглядит моя домашняя Zigbee сеть, где хорошо видно, как устройства-роутеры (синие) являются точками подключения физически далеко расположенных устройств:

  • Наличие класса конечных устройств-роутеров с постоянным питанием позволяет строить сеть на очень большой территории. Да, WiFi тоже умеет строить Mesh сети, но не с помощью исполнительных устройств-роутеров, а с помощью дополнительных WiFi роутеров подключенных в mesh сеть.

  • Огромный выбор доступных устройств на рынке. На данный момент Zigbee Alliance насчитывает сотни членов, а на рынке существует тысячи разнообразных решений с заявленной поддержкой Zigbee.

  • Безопасность. С 128-битным алгоритмом AES, используемым для шифрования данных и аутентификации, и тремя типами ключей, используемых для управления безопасностью, конечным пользователям не стоит беспокоиться об опасности взлома.

  • Относительно низкие цены на устройства.

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

Лично для меня преимущества Zigbee очевидны и я строю свой Умный Дом почти полностью на этой технологии. Конечно, у меня еще есть несколько WiFi устройств, например, кондиционер управляемый WiFi USB стиком на ESP8266, датчик потребления фильтрованной воды на Wemos D1 mini, настольная лампа Yeelight. Среди активных сторонников Zigbee такой неоспоримый авторитет в сообществе, как Алекс Квазис, который в подкасте Спрута однозначно высказывался о преимуществах Zigbee перед Wifi. Кстати, кто не слышал подкаст, то рекомендую:

Если говорить о Zigbee дальше, то всплывает еще одна горячая тема: USB Zigbee стик, шлюз Xiaomi Gateway 3 (возможно перепрошитый Sonoff шлюз) или SLS использовать в качестве координатора сети Zigbee. Или еще одна, касающаяся пользователей HomeAssistant: что лучше, Zigbee2mqtt или ZHA? Это настолько объемные темы, что заслуживают отдельной статьи. Скажу лишь за себя - я за использование Zigbee USB стика в союзе с Zigbee2mqtt. В двух словах почему: стабильность, количество поддерживаемого оборудования, независимость от прихотей производителей шлюзов или SLS, при необходимости возможность самостоятельно обеспечить поддержку неподдерживаемого устройства с помощью zigbee2mqtt external converter. Но если вы уже имеете Xiaomi Gateway 3 шлюз и хотите использовать его в качестве координатора вашей Zigbee сети, а также, возможно и для BLE mesh сети, то очень рекомендую вам послушать подкаст с AlexxIT, авторитетнейшим участником сообщества и автором интеграции этого шлюза в HomeAssistant, чтобы узнать все нюансы из первых рук:

Говорить о распространенности других протоколов для Умного Дома можно, но на мой взгляд, пока рано. Отличный протокол Zwave живет своей жизнью уже очень давно, но из-за дороговизны устройств и географического разделения рабочих частот протокола мало распространен в русскоговорящем сообществе. Хотя есть пользователи очень давних реализаций Умных Домов на Vera или Homey, у которых осталось Zwave оборудование, например от Fibaro, и которые в рамках HomeAssistant, где поддержка этого протокола очень развита, успешно используют эти устройства и поныне.

Протокол BLE mesh выглядит очень многообещающим и поддерживается последними версиями шлюзов Xiaomi. Кроме того, явно заметно разделение направлений, если устройства для Умного Дома от Aqara практически все выпускаются для протокола Zigbee, то последние новинки от Xiaomi выпускаются почти исключительно для BLE mesh. И уже сейчас вполне реально активно использовать этот протокол, покупая доступные на рынке устройства.

Что касается протокола Thread, то его в последнее время стали продвигать в Apple, включив его поддержку в HomePod Mini и новой версии AppleTV. Солидные производители вроде Eve или Nanoleaf тоже стали включать поддержку Thread в своих новых устройствах. Я думаю, маркетинговая мощь Apple может продвинуть популярность этого протокола достаточно далеко и стоит не упускать из вида этот очевидный тренд.

Но пока протокол Zigbee в Умных Домах безусловно доминирует. И меня это устраивает. Я за Zigbee, как самое сбалансированное решение на рынке на данный момент.

Красивый GUI против текстовых конфигов и чистых автоматизаций

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

  • Как настраивать систему и писать автоматизации - через предоставленные возможности GUI или редактированием текстовых файлов конфигураций?

  • Зачем заморачиваться с красивым и удобным интерфейсом, делая его похожим на пульт управления космолета? Ведь настоящий Умный Дом тот, в интерфейс которого вообще не нужно заходить - все работает через точно и тонко настроенные многочисленные автоматизации.

Начнем с первого. В последних версиях HomeAssistant тренд на уход от правки yaml конфигурационных файлов в сторону настройки всего и вся через GUI был настолько очевиден, что многие старожилы сообщества загрустили о старых добрых временах, когда все настраивалось вручную. Кроме того, в свое время весомый вклад в популяризацию правки yaml конфигов внес не раз уже упомянутый Алекс Квазис со своими видео уроками по настройке HomeAssistant. Но его продвижение этого метода дало и обратный результат. Вместо того, чтобы вникать в код его примеров и пытаться в нем разобраться, начинающие, неопытные пользователи стали просто бездумно копипастить код из его уроков и слепо следовать его рекомендациям, как истине в последней инстанции. Я уверен, что Алекс не подразумевал изначально такого эффекта, но теперь в сообществе сложился устойчивый мем "так было у Квазиса в его уроке" или "я делал все по урокам Квазиса". Опытные участники сообщества лишь саркастически ухмыляются, отсылая вопрошающих с их проблемами к чтению документации и к пониманию того, что и как они делают.

Многие не любят HomeAssistant именно из-за его формата конфигураций yaml. Жесткая требовательность к форматированию, отступам многих раздражает. Написать вручную, к примеру, такую автоматизацию света на кухне с учетом датчиков движения, датчика освещенности и времени суток с множеством условий, без серьезной подготовки и опыта очень сложно:

alias: Kitchen Lighttrigger:  - platform: state    entity_id: binary_sensor.kitchen_motion_group    to: 'on'  - platform: state    entity_id: binary_sensor.kitchen_motion_group    to: 'off'    for: '00:02:03'condition: []action:  - choose:      - conditions:          - condition: template            value_template: '{{ trigger.to_state.state == "on" }}'          - condition: time            after: '09:20'            before: '23:00'          - condition: numeric_state            entity_id: sensor.lux_kitchen_illuminance_lux            below: '23'        sequence:          - service: switch.turn_on            target:              entity_id:                - switch.relay_switch_l1                - switch.relay_switch_l2                - switch.switch_kitchen_switch_center          - service: light.turn_on            data:              transition: 4              color_name: crimson            target:              entity_id: light.led_strip      - conditions:          - condition: template            value_template: '{{ trigger.to_state.state == "off" }}'          - condition: time            before: '23:40'            after: '09:20'        sequence:          - service: switch.turn_off            target:              entity_id:                - switch.relay_switch_l1                - switch.relay_switch_l2                - switch.switch_kitchen_switch_center                - switch.switch_kitchen_switch_right                - switch.switch_kitchen_switch_left          - service: light.turn_off            target:              entity_id: light.led_strip      - conditions:          - condition: template            value_template: '{{ trigger.to_state.state == "on" }}'          - condition: time            after: '01:00'            before: '05:30'        sequence:          - service: switch.turn_on            target:              entity_id: switch.relay_switch_l2      - conditions:          - condition: template            value_template: '{{ trigger.to_state.state == "off" }}'          - condition: time            after: '01:00'            before: '05:30'        sequence:          - service: switch.turn_off            target:              entity_id: switch.relay_switch_l2    default: []mode: single

Но с другой стороны, эту же автоматизацию можно собрать в GUI автоматизаций HomeAssistant. А в последних версиях еще и появилась возможность визуального дебага автоматизаций в GUI:

Дебаг автоматизаций в HomeAssistantДебаг автоматизаций в HomeAssistant

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

Второй пункт нашего списка касается опять HomeAssistant и настройке его интерфейса Lovelace. Да, сейчас его можно настраивать исключительно средствами интерфейса, предоставленного HomeAssistant и не думать о правке вручную файла ui-lovelace.yaml в режиме Lovelace "yaml", как было в уроках Квазиса. Но лично я предпочитаю ручную полировку интерфейса. Весь интерфейс моих дашбордов как для десктопа, так и для мобильных устройств полностью написаны вручную. Сделать два разных дашборда очень просто, достаточно в configuration.yaml прописать что-то вроде:

lovelace:  mode: yaml  resources:  - url: /hacsfiles/mini-graph-card/mini-graph-card-bundle.js    type: module  - url: /hacsfiles/mini-media-player/mini-media-player-bundle.js    type: module  - url: /hacsfiles/ha-yandex-icons/yandex-icons.js    type: module  - url: /hacsfiles/lovelace-card-mod/card-mod.js    type: module  - url: /hacsfiles/lovelace-auto-entities/auto-entities.js    type: module  - url: /hacsfiles/button-card/button-card.js    type: module  - url: /hacsfiles/vertical-stack-in-card/vertical-stack-in-card.js?v=0.4.0    type: module  - url: /hacsfiles/simple-thermostat/simple-thermostat.js    type: module  - url: /hacsfiles/simple-weather-card/simple-weather-card-bundle.js    type: module  - url: /hacsfiles/text-element/text-element.js    type: module  dashboards:    lovelace-generated: # Needs to contain a hyphen (-)      mode: yaml      filename: mobile-ui.yaml      title: Mobile UI      icon: mdi:cellphone-text      show_in_sidebar: true      require_admin: true

и уже в файле mobile-ui.yaml конфигурировать ваш отдельный Lovelace для мобилок. Для десктопа мой интерфейс сейчас выглядит примерно вот так:

Версия для десктопаВерсия для десктопа

Для мобильных устройств примерно так:

Версия для мобильного телефонаВерсия для мобильного телефона

Ну и наконец, резонный вопрос - зачем этот пульт управления космическим кораблем, если настоящий идеальный Умный Дом не должен подразумевать ручного вмешательства, управления и контроля, а все должно работать как надо автоматически?

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

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

HomeAssistant против Node Red. Или вместе с ним.

Эта тема характерна для споров между уже опытными и продвинутыми строителями Умных Домов, Бань, Дач и Сараек. Она не так остра и популярна, но написать о ней мне все же хочется. Хочется, потому, что когда-то этой теме было посвящено немало споров в уютном лампово-теплом сообществе телеграм чата Homever.

Примерный вид обычного Node RedПримерный вид обычного Node Red

Скажу сразу, я попробовал Node Red и он мне не зашел. Визуальное создание автоматизаций перетаскиванием и связыванием каких-то прямоугольников различного назначения лично мне не показалось удобным и интуитивным. Мне гораздо проще и понятнее описывать автоматизации текстом, в yaml, в HomeAssistant. В общем, опыт с Node Red у меня небольшой, судить о нем авторитетно я не могу. Я запустил и отладил несколько флоу, но не более того.

Логотип HomeAssistantЛоготип HomeAssistant

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

Почему-то принято считать, что возможности и гибкость автоматизаций в Node Red значительно превосходят таковые в HomeAssistant с чем я совершенно не согласен. Я не знаю ни одного сценария автоматизации, который можно было бы реализовать в Node Red и нельзя было повторить средствами автоматизаций HomeAssistant. На этот неоднократно заданный адептам Node Red вопрос я так ни разу и не получил убедительного примера такого сценария.

Таким образом, целесообразность такой связки двух систем мне кажется избыточной и нерациональной хотя бы с точки зрения стабильности. Каждая из этих двух систем вполне самодостаточна, разве что в Node Red нет такого красивого интерфейса, как в HomeAssistant. Но это важно далеко не всем. Ну и возможности подключения огромного разнообразия устройств у Node Red значительно скромнее. Для чего нужен конгломерат двух серьезных и мощных систем, мне непонятно. Знаю пользователей таких симбиозов, которые используют подключения устройств и там и там, да еще и автоматизации создают средствами обоих систем. Представляете, какая каша из сущностей и связей там образуется? Надежность и стабильность такой связки двух систем вызывает у меня большие сомнения.

Мое мнение: максимально глубоко изучите возможности Node Red или HomeAssistant и используйте что-то одно. Каждая из этих систем в отдельности способна полностью удовлетворить все ваши требования к Умному Дому. Хотя, с другой стороны, я могу понять тех, кто имеет устройства, которые не поддерживаются в Node Red, но подключаются в HomeAssistant и он используется в качестве некоей прослойки для проброса подобных устройств в Node Red, а также, возможно, для красивых дашбордов для настенных панелей в виде вмонтированного планшета, например.

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

Заключение

На самом деле я затронул лишь малую часть горячих тем в сообществах строителей Умных Домов. Их гораздо больше по самому широкому кругу вопросов. Например, есть популярная тема о том, что лучше и надежнее - проводное или беспроводное подключение устройств? Или тема о том, каким воспользоваться способом для настройки подключения SSL сертификатов и проброса HomeAssistant наружу в интернет.

Если вас интересует тема Умных Домов и вы готовы погрузиться в нее с головой, подписывайтесь на профильные телеграм чаты по HomeAssistant, этот, или этот. На чат обо всем, касающемся темы Zigbee. На персональный канал большого авторитета Ивана Бессарабова, где найдете кладезь полезной информации. Ну и на упомянутый выше ламповый чат сообщества Homever

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

Подробнее..

Малиновый киноцентр или как сделать неубиваемый смарт-ТВ

01.09.2020 02:06:58 | Автор: admin

Предыстория

Шёл 2018 год. У меня сломался старый DVD-магнитофон компании BBK. Выглядел он, примерно, так:

Умерший дивидюшникУмерший дивидюшник

Знаю, что скажут 90% читателей: "Зачем тебе магнитофон? Смарт-ТВ купи и счастье". Я отвечу. Проблема в том, что ещё в 90-ых был куплен шикарный телевизор с 5.1 звуком и Full-HD монитором, правда не стандартного разрешения (не 4:3 и не 16:9). Менять телевизор и попадать минимум на 40 тысяч из-за дивидюшника за 3 тысячи - как-то не разумно. В планах сделать экран с проектором и звуком, но вот покупать смарт-ТВ, который не поковыряешь - для меня слишком больно. Купил Sony - мучайся с их смартом и так с любой фирмой.

Так вот. Пошёл я в магазин и увидел 3 варианта DVD-магнитофонов:

  • Panasonic, Philips, Sony и т.п. за 10 тысяч

  • Шлакоблок-ноунейм за 500 рублей

  • Ну и банально, мой умерший BBK за 2,5 тысячи

Проведя серьёзное исследование вопроса (нет), я понял, что есть ряд косяков в каждом варианте. По порядку:

  • Магнитофон за 10 тысяч - вещь очень капризная и нудная. Читает только конкретный формат видео (в основном .avi), капризен к размеру файла - до 4 ГБ, а где-то и до 1,2 (шёл 2018 год, а видео больше 1,2 гигов не читаются), да и цена вопроса - печаль-тоска. Плюшки в виде записи телепрограмм или же Blu-ray привода - очень условны, так как запись читается (в плане без костылей и страданий) только на этом магнитофоне. ПК - в пролёте (2018 год!). А хвастать Blu-ray приводом - это как-то совсем уж печально.

  • Шлакоблок работает 3 раза, да и ставить не известно что к хорошему телевизору - печаль.

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

Тут меня посетила идея сделать всё самому.

Подготовка

В моём распоряжении был старый комп-башня и куча старых деталей, который валялись по квартире и офису. Тестил всё на этом железе в разных конфигурациях: от сборки с интегрированной видюхой от интел с 1 ГБ оперативы и пентиумом на борту, до GTX 660 с 8 ГБ оперативы и i5 во главе. Разница есть, но только в загрузке файлов - то есть не критичная. Картинка в FullHD выдаётся ровно без крашей всю дорогу. Имея задумку повесить экран с проектором, делать громоздкую станцию - не вариант.

Выбор пал на малинку (на тот момент - 3 Model B+). Чтобы не заморачиваться с поиском деталей на алике - я использовал стартовый набор за 5 тысяч. Бюджет вполне утраивал.

Комплектация:

  • Малинка

  • Корпус под плату

  • 3 радиатора с термопастой-двойным скотчем

  • Карта на 16 гигов с переходником

  • Кабель питания

  • HDMI на пол метра

Комплектация малинки Комплектация малинки

Комплект не жирный, но всё что нужно на месте. Брал тут, но сейчас ценник явно завышен.

Если будете брать сейчас - берите 4 Model B. Смысл тот же, но сама плата помощнее. Набор на том же сайте. Разница 600 рублей, но сейчас цены завышены.

Проблема 2

Если коротко - проблема ниже

ТюльпанТюльпан

Во всех старых телевизорах старые RCA-разъёмы (тюльпаны), а это большая проблема, так как разъём аналоговый, а малинка работает только в цифре.

Задача - найти переходник в FullHD с отдельным выходом на питание. Дело в том, что малинка - энергоэкономичное устройство и она не может сама запитать по HDMI переходник.

Боже храни AliExpress.

ПереходникПереходник

170 рублей и нет проблем. Питание по USB всё от той же малинки.

Операционная система

У меня было 2 варианта операционной системы - костыльный Android и система Kodi. Я выбрал Kodi с сиcтемой LibreELEC. Во-первых, это система рассчитана именно под мою задачу - создание киноцентра, а во-вторых, система полностью настраиваемая.

Установка проста как мир. Загружаем установщик -> на шаге 1, выбираем платформу (в моём случае, Raspberri Pi 3) и версию системы (просто, последнюю версию) -> жмём Download на шаге 2 -> вставляем microSD с переходником из комплекта -> на шаге 3 выбираем карту -> жмём "Write" на шаге 4.

Установщик системыУстановщик системы

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

Базовые настройки

До меня многие люди делали примерную настройку системы. Мы же сделаем всё от и до.

Итак, система на базе UNIX, а значит настроить можно всё. Система встречает нас на русском языке и это победа!

Экран настроекЭкран настроек

Калибровка

Напомню, мой ТВ не формат (не 4:3 и не 16:9). Чиниться всё легко. Идём в настройки системы.

СистемаСистема

Переходим во вкладку "Экран". Там автоматом стоит 1920х1080 и это хорошо, так как переходник на RCA вещает в 1080 (если подключали по HDMI, система сама определит оптимальное разрешение). Идём в самый низ меню во вкладку "Калибровка дисплея". Если она не отобразилась сразу - переключитесь на "Экспертный режим" (кликаем внизу левого меню).

КалибровкаКалибровка

Калибруется всё 4 ползунками:

КалибруемКалибруем

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

Мы видим ровную картинку с любого ТВ/экрана/проектора.

Итак, результат. У нас полноценный магнитофон с запуском с USB и работа с клавиатурой/мышью.

Телефон - это пульт

Тут всё просто. Скачиваем на свой смартфон/планшет программу из AppStore или Google Play. Если вы с малинкой в одной сети - приложение схватит всё само.

DVD

Чтобы мы могли читать диски, необходимо докупить DVD-привод. Какой по душе. Я не поскупился и купил бесшумную модель - Hitachi-LG GP60NB60. Минус 2 тысячи из бюджета.

DVD-приводDVD-привод

Итого, магнитофон, который читает любые файлы, управляется с телефона и читает DVD. Не плохо, но для 7 тысяч - маловато функционала.

Продолжим!

Дополнения до смарта

Идём во вкладку "Дополнения" и скачиваем все указанные:

Дополнения 1Дополнения 1Дополнения 2Дополнения 2Дополнения 3Дополнения 3

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

Bing-обои

Эта штука мне понравилась ещё в заставках Windows. Когда вы отойдёте от малинки, а она включена - через 2 минуты будет появляться еженедельно обновляемые фото-победители на Bing. Всё что нужно - дополнение "Bing: Photos of the Week".

Переходим во вкладку "Интерфейс".

ИнтерфейсИнтерфейс

Выбираем вкладку "Заставка".

ЗаставкаЗаставка

В этой вкладке выбираем наше дополнение

BingBing

Модно, стильно, молодёжно. Едем дальше.

Региональные настройки

Если что-то нужно поменять - переходим во вкладку "Интерфейс".

ИнтерфейсИнтерфейс

Вкладка "Региональные" и меняем как удобно. У меня выставлены следующие настройки:

Региональные натсройкиРегиональные натсройки

Изменение настроек системы

Если что-то не устраивает в системе глобально - перейдите во вкладку "LibreELEC".

LibreELECLibreELEC

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

Wi-FiWi-Fi

Погода

Я пользуюсь приложение Gismeteo и оно весьма точно предсказывает погоду. Баловство, конечно, в ТВ, но пусть будет :)

Вкладка "Службы".

СлужбыСлужбы

Кнопка погоды и приложение Gismeteo.

ПогодаПогодаGismeteoGismeteo

IPTV-сила

Настроем IPTV. Вкладка дополнения и в ней приложение "PVR IPTV Simple Client".

PVR IPTV Simple ClientPVR IPTV Simple Client

Жмахаем на неё и настраиваем напрямую.

Настройки IPTVНастройки IPTV

Тут всё просто. Вписывает ссылку на M3U. Далее в разделе"Установка EPG", можно указать путь до программы передач. Для этого выберите пункт"Ссылка на XMLTV".

Ссылка на M3UСсылка на M3U

Выбор IPTV

Тут дилемма: бесплатно и так себе или платно и хорошо. Решать вам, но я расскажу об обоих вариантах.

Бесплатное IPTV

Лучшее, что я смог найти - Самообновляемый плейлист "ONE". Это бесплатный самообновляемый плейлист в формате m3u. Разрабы обещают, что плейлист будет всегда бесплатным.

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

Платное IPTV

Тут, на мой взгляд, лучший вариант - sharavoz. За 3 бакса (т.е. 250 рублей) вы получите все каналы НТВ+, стандартное вещание и кучу плюшек. У ребят 1 день бесплатного теста. Попробуйте. Я остановился на этом варианте.

YouTube жив!

Почему так пафосно? Дело в том, что в прошлом году пришли какие-то черти и сломали YouTube. Доступ к API в Kodi закрыли и система потеряла смысл.

Однако! Ребята в Kodi смогли придумать способ обхода блокировки и этот способ хоть и не прост, но вечен.

Итак. Переходим по ссылке. Вводим логин-пароль.

Заходим в настройки YouTube через дополнения.

YouTubeYouTubeНастройкиНастройки

Далее, по инструкции ниже.

Ввод в системе, а не через SSHВвод в системе, а не через SSH

Аналоги на рынке

Аналог сделанного нами устройства - Xiaomi Mi Box.

Xiaomi Mi BoxXiaomi Mi Box

Цена вопроса - 5000 рублей. Без дисковода - цена один в один, но есть 2 весомых косяка:

  1. Android, который работает весьма кривенько

  2. Невозможность подстроить экран по разрешение (калибровка в Kodi)

Из-за этих двух весьма сильных косяка - устройство для меня стало абсолютно бесполезно, хотя если экран будет стандартного разрешения 16 к 9 - будет всё нормально, но это только в таком раскладе и с андроидом в коробке

Итоги

Надеюсь, статья смогла чем-то помочь. В результате работы имеем следующую картину:

  • Подстройка под нестандартные экраны

  • Работа как по цифре (HDMI), так и по аналогу (тюльпан)

  • Настроено IPTV

  • Выносной DVD-привод

  • Приятное оформление

  • Настроен YouTube, который пытались вырезать из системы

  • Цена - 7 000 рублей

  • Устройство можно перетаскивать с собой в поездки и при возвращении и подключении к домашнему ТВ - настройки сохраняются

Подробнее..

Софтовый датчик присутствия на Linux AP ESP8266

12.01.2021 16:20:24 | Автор: admin

TL;DR

Наблюдение за изменением уровня Wi-Fi сигнала от стационарно расположенных по дому IoT устройств позволяет сделать полностью программный (выделенное железо отсутствует) обьемный датчик движения в квартире, достаточно точно показывающий наличие активно перемещающихся (фактически, не спящих) людей.

Предыстория

Есть обычная "квартира айтишника" с системой "умный дом" на базе Home Assistant:

  • Самодельные выключатели освещения на базе ESP8266 + MSP430

  • Несколько датчиков температуры/влажности, СО2 и качества воздуха.

  • Контроллер вентиляторов в ванной/туалете

  • пара Sonoff Mini для остального.

Общение девайсов между собой - по Wi-Fi + MQTT. Для минимизации влияния низкоскоростных ESP на "рабочую" Wi-Fi сеть - на отдельном Raspberry Pi 3 запущена отдельная Wi-Fi сеть для IoT, на базе стандартного hostapd. В сумме в IoT Wi-Fi сети - 12 устройств.
Там же на RPi запущен MQTT брокер, рядом на "домашнем сервере" - Home Assistant.

Идея

Уровень сигнала Wi-Fi достаточно зависим от наличия и расположения препятствий между точкой доступа и клиентами. Даже открытая/закрытая деревянная межкомнатная дверь может вызвать заметные изменения в RSSI, не говоря уже о прошедшем человеке. При этом, так как сами wi-fi клиенты стационарны - изменения сигнала от других факторов достаточно минимальны.

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

Реализация

Запустив команду iw dev wlan0 station dump, можно получить достаточно детальную информацию по подключенным клиентам:

Station 60:01:94:21:f8:4c (on wlan0)        inactive time:  8000 ms        rx bytes:       11269629        rx packets:     91423        tx bytes:       6159821        tx packets:     70707        tx failed:      0        signal:         -53 [-53] dBm        tx bitrate:     1.0 MBit/s        rx bitrate:     54.0 MBit/s        ...        connected time: 763375 secondsStation 18:fe:34:98:dc:81 (on wlan0)        inactive time:  4000 ms        rx bytes:       11388688        rx packets:     92101        tx bytes:       6143200        tx packets:     70205        tx failed:      39        signal:         -40 [-40] dBm        tx bitrate:     1.0 MBit/s        rx bitrate:     18.0 MBit/s        ...        connected time: 763378 seconds

Значение RSSI ("signal: -40 [-40] dBm") обновляется в реальном времени, и вызывая iw достаточно часто - можно собрать статистику уровня сигнала.

Запуская iw два раза в секунду и усреднив RSSI за минуту - можно получить значения с более высокой точностью:

Уже по этому графику видно что ночью сигнал остается стабильным, а днем отдельные клиенты отклоняются от "спокойного" состояния на +/- 10 dBm. Однако представление результата можно улучшить, посчитав среднеквадратичное отклонения сигнала для всех клиентов от "спокойного" уровня.

Средние значения

Первым вариантом алгоритма было:

  • Собрать статистику по уровням сигналов в отсутствие людей ("базовый уровень")

  • Сохранить базовый уровень в файле конфигурации

  • Посчитать среднеквадратическое отклонение от базового уровня, которое и будет сигналом "обнаружено движение"

После имплементации такого алгоритма оказалось, что базового уровня не существует. После прохода человека по квартире и возврата в первоначальную точку - сигналы стабилизируются, но на других значениях.
Рассмотрим например тот же график в окресностях 4 утра:

Можно заметить ночной поход в ванную в ~4:30. После него сигналы вернулись к стабильности, но некоторые из них - сместились от предыдущих значений. Отсюда можно сделать вывод, что система в целом - метастабильна, и одного фиксированного "состяния покоя" не существует.

Для решения этой проблемы "состояние покоя" тоже нужно считать как среднее - но за значительно более продолжительный промежуток времени.

Финальный алгоритм

  • Раз в 500мс собираем значения RSSI из вывода iw dev wlan0 station dump.
    Сама команда достаточно легковесна, чтобы не нагружать Raspberry Pi выполнением с такой частотой.

  • Для каждого из клиентов считаем скользящее среднее за последние 1024 сэмпла в качестве "базового уровня":

$RSSI = -65; # Значение из iw dev dump$baseline = ($RSSI + 1023 * $baseline) / 1024;
  • Опять же для каждого считаем скользящее среднее за 256 сэмплов по аналогичной формуле в качестве "текущего значения".

  • Итоговый показатель "активность движения в доме" считается как корень из суммы квадратов отклонений "текущего" от "базового" для каждого из wi-fi клиентов.

Результат уже намного более нагляден:

Здесь синий график ("IW Signal Distance") и является среднеквадратическим отклонением. Остальное - индивидуальные отклонения от скользящего среднего.

Эмпирическим путем можно предположить, что значения IW Signal Distance >1 (зеленая горизонталь) соответствуют активности людей в помещении. Но эта граница, скорее всего, будет отличаться для других конфигураций помещения и количества устройств.

Результаты

Система работает в таком виде уже более двух лет, и достаточно надежно показывает активность внутри квартиры, с минимальным влиянием соседей.
Моя реализация алгоритма доступна на гитхабе (http://personeltest.ru/aways/github.com/k-korn/misc-scripts/tree/main/iwmon), но она достаточно специфична (Perl + Zabbix + визуализация в Grafana) - и потому готовым решением "plug and play" все же служить не может.

Подробнее..

Я сделаю свою умную колонку with blackjack and hookers!

23.01.2021 22:04:46 | Автор: admin

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

На самом деле никакая она неумная, грубая и не особо полезная, но зато весёлая и с характером.

За мной сама идея, программирование, железо (подбор и настройка).

От брата 3D-модель, 3D-печать, железо (подбор и электромонтаж).

Статья по-большей части описывает то, что делал я, лишь немного касаясь 3D-модели.

"Ты на самом деле хочешь дружить с роботом?"

Будучи большим фанатом известного мультсериала Футурама, однажды (где-то в 2018 году)мне захотелось заиметь самодельную голову робота Бендера Родригеса. В голове, в том числе крутились дурацкие варианты сделать её из какой-нибудь кастрюли. В силу своей глупости идея была забыта и заброшена ровно до того момента пока у одного хорошего человека, моего брата, товарища xbostа не появился 3D-принтер (весна 2019 года). И тут эта идея снова ожила

Обсудив эту идею за пивом, принялись за работу. Брат начал делать 3D-модель, а я искать, что из электронного хлама в ящике стола можно задействовать в проекте.

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

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

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

Первые попытки

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

В силу своей природной хм невнимательности, я упустил существование более подходящей для моей задачи версии pocketsphinx, и начал с большого CMU Sphinx на Java.

Создал простенькие JSGF-грамматику и программу на Яве. Взял несколько наиболее известных цитат для проигрывания(with blackjack and hookers, bite my shiny metal ass, kill all humans и т.п.). Пробовал изначально на достаточно мощном компьютере(MacBook Pro 13-го года), был доволен результатом производительности, но понимал, что на Галилео меня ждёт нечто другое. Но дело оказалось совсем плохо.

Вообще Галилео уже давно заброшен Интелом. Стандартный Линукс, шедший с ним мне в принципе особенно не нравился. Поэтому попробовал с последней доступной для него сборкой Дебиан.

Туда с проблемами(подробности уже честно не вспомню) был поставлен JRE. В качестве устройства ввода/вывода аудио была использована USB-гарнитура. И Результат был крайне печален в плане производительности. Сейчас опять же не вспомню, возможно неправильную акустическую модель использовал на ней, но на реакции уходило 30-60 секунд. Плюс брат начал разрабатывать 3D-модель, и сказал, что габариты Галилео большеваты. Плюс отсутствие встроенного Wi-Fi. В общем Галилео опять отправилась в стол.

Решено было попробовать на гораздо более популярной Малинке, и выбор пал на слабую, но самую компактную версию Raspberry Pi Zero W. А также, прокачав внимательность, узнал о pocketsphinx (отличная статья для старта), перешёл на него, и переписал программу на Питоне.

При переходе на Малину, с подачи xbostа, родилось название для проекта Pinder (Raspberry Pi + Bender). Да, я прекрасно помню историю с Pidora в русскоязычном сегменте, но в данном случае намеренно выбрал такое лулзовое для русского уха название.

И так предыстория завершена, можно переходить непосредственно к описанию Пиндера.

Внутренняя железная часть

Перечень использованных компонентов:

  • Raspberry Pi Zero W собственно основа всего.

  • UPS-Lite for Raspberry Pi Zero

    Маленький ИБП для Малинки. Его штатный выключатель был выпаян, и к его контактам был припаян микропереключатель (см. далее по списку).

  • RGB адресная светодиодная лента на WS2812B, 60 светодиодов на 1 метр

    Для подсветки и анимации зубов(18 штук) и глаз(2 штуки).

  • USB-аудиокарта

    В принципе подойдёт любая, работающая в Линуксе. Подключается через OTG-кабель в единственный доступный для этого порт на Малине Зеро.

  • Усилитель и один динамик от таких колонок

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

  • Микрофон HBC10A

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

  • Микропереключатель с лапкой KLS7-KW10

    Замыкается/размыкается при вставлении/вынимании "антенны" Бендера. Включает/выключает питание от UPS к Малине.

  • 3,5мм разъём и гнездо jack. Для подключения микрофона к аудиокарте (микрофон находится наверху Бендера, в антенне).

В общем внутри всё достаточно колхозно.

Схема подключений очень простая:

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

3D-модель, корпус

Здесь я не смогу рассказать многого, так как эта часть работы полностью брата.

3D-модель и небольшая инструкция доступны здесь.

Зубы и глаза напечатаны фотополимерной смолой на Anycubic Photon. Все остальные части PLA на Creality Ender 3.

Если будут какие-то вопросы по 3D-модели и печати можно задать мне, я их передам, либо попробовать напрямую спросить у xbostа на thingiverse (но не уверен будет ли он на них отвечать).

Краткая схема сборки:

Фото

Фото в процессе сборки и полностью собранном виде:

Программная часть 1

В качестве ОС используется штатный Raspbian (теперь Raspberry Pi OS).

За распознавание, как уже писалось выше, отвечает pocketsphinx. В качестве аудиоподсистемы используется Alsa (Pulseaudio выпилен).

Подсветка управляется с помощью библиотеки Adafruit_Blinka.

Данные о заряде/напряжении читаются из UPS-Lite посредством SMBus.

При разработке никакими лучшими практиками не руководствовался, поэтому код попахивает.

Код лежит здесь.

Поддерживается два языка: английский и русский. Для каждого языка своя JSGF-грамматика, набор аудио-сэмплов(сэмплов в репозитории нет, по соображениям авторских прав) и синтез речи. Русский дорабатывался(и дорабатывается) с некоторым опозданием.

Основной целью была просто возможность отвечать фановыми фразами из серий. Задаешь ему вопросы типа Как дела?, Где ты родился?, Что думаешь о Сири?. Ищется и воспроизводится ответ из сэмплов (в случае отсутствия сэмпла используется синтез речи, но об этом чуть позже).

Изначально скорость ответов на Малине была не очень шустрой (4-6 секунд до ответа):

Покопавшись у себя в коде, были найдены и уничтожены необязательные паузы. То же самое касалось и сэмплов (были пустые места вплоть до 1 секунды в начале файлов). А также прочитана информация о параметрах оптимизации pocketsphinx. Получилось уже получше:

Далее начал добавлять кое-какие полезные функции. Первой стала проигрывание музыки с локальной ФС или интернет-радио с помощью MPD. При этом докричаться до Бендера при проигрывании музыки на приличной громкости сложновато:

После достаточно долгого перерыва, живя на даче, была добавлена первая функция умного дома- управление освещением в своём углу через ModBusTCP. Вот только Бендера недостаточно иногда просто попросить включить свет, нужно обязательно сказать "пожалуйста". Работает достаточно шустро:

Программная часть 2

Потом однажды захотелось добавить читалку RSS-новостей. Это уже было невозможно без синтеза речи, но при этом хотелось, чтобы синтезатор звучал как, или хотя бы похоже на голос Бендера. Такой синтез речи на Малине Зеро представляется малореальным и поэтому в этом моменте пришлось сдаться и задействовать онлайн-сервис.

Почитав информацию и попробовав разные варианты остановился на Microsoft Azure Custom Speech.

При создании пользовательского голоса на выбор есть три варианта:

  • Statistical Parametric стандартное качество, нужно небольшое количество(для английского языка) сэмплов для обучения.

  • Concatenative высокое качество, нужно 6000 сэмплов для обучения.

  • Neural премиум-качество. По факту недоступно(доступно из США, при написании челобитной в Майкрософт зачем тебе это нужно и выкладывании 100000$).

Более подробно по технологиям синтеза речи можно почитать например на Википедии.

У меня не было большого количества сэмплов, поэтому сначала поигрался со Statistical Parametric. Результат был неплох, голос конечно не был похож(такой тип синтеза для сильной похожести и не предназначен), но интонации передавал сносно. В итоге на основе набора данных созданного с помощью этой модели я создал оффлайновую модель для CMU Flite, используемую в случае отсутствия связи с MS Azure.

Но всё же хотелось большей похожести и я решился попробовать собрать 6000 сэмплов для Concatenative модели, использующей отрывки из сэмплов настоящего голоса. Очень помог некий хороший человек, выложивший на YouTube 7 видео The Best of Bender. Надёргав оттуда сэмплов, приплюсовав к ним те что уже были и натравив на них майкрософтовский же Text-to-Speech (здесь у меня набор тулзов вспомогательных), получил что-то около 2000 транскрибированных сэмплов. Было принято решение просто скопировать это всё три раза под разными именами, чтобы получить 6000.

В итоге всё это было залито на обучение модели, и результат получился следующим:

Да конечно не идеально, но меня результат трудов устроил.

В итоге синтез речи используется не только для чтения новостей, но и в случае отсутствия оригинального сэмпла. Сначала ищется сэмпл. Если его нет, проверяется связь с порталом MS Azure, если есть синтезируется с помощью него. Если же связи с Azure нет используется локальная модель Flite(а для русского языка роботизированный голос eSpeak).

В сумме периодическими волнами и рывками разработка шла с весны 2019-го по весну 2020-го, в свободное время(хорошо видно по коммитам на гитхабе). Далее уже даже не волнами, просто отдельными всплесками.

Будущее

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

Но для начала надо изобрести удлинитель пальца.

Заключение

Исходный код ПО и 3D-модель выложены под открытыми лицензиями, так что если у кого-то есть желание сделать своего Бендера, добавить свои функции и улучшить буду рад.

На этом статья подошла к концу. Спасибо, что прочитали!

Всем хороших новостей!

Подробнее..

Метеостанция на максималках

05.03.2021 10:06:07 | Автор: admin

Про метеостанцию на Хабре писали не раз и не два, и наверное не с десяток раз. И вот настало моё время. Решил с вами поделиться своей.

Постановка задачи

Зачем вообще нужна метеостанция? Сегодня в мире хватает погодных сервисов, в том числе с локальными сводками погоды. Однако помимо контроля внешних параметров мне нужно было получить данные и с датчиков температуры и влажности внутри помещения. Помимо просто информационной составляющей, зная температуру в доме и снаружи, можно, например, управлять котлом или вентиляцией, и поддерживать комфортный микроклимат (погодозависимая автоматика). Кроме того, мне очень хотелось бы отслеживать тенденции и тренды погоды на длительных промежутках времени, например в год-два. То есть, данные нужно где-то хранить.

Из всего того делаем выводы:

  • Нужно хранилище данных (сервер)

  • Датчики будем использовать разные и в разных местах, поэтому проще сделать систему модульной (IoT)

  • Помимо локального сервера данные, хотя бы текущих показаний хорошо бы скидывать в облако

  • Так как мы будем собирать достаточно много данных, можно данными поделиться

Архитектура

Самым простым и популярным решением для метеостанции является Arduino, однако подружить с его домашней сетью - это дополнительные девайсы\шилды, лишние деньги и сложность, а значит - время. Поэтому из коробки проще использовать модуль уже со встроенным Wi-Fi, например ESP8266 (NodeMCU) с подключенными сенсорами. Это достаточно удобно, что один и тот же модуль можно использовать и дома, и за окном. При желании даже можно его использовать в качестве сервера.

Но почему бы не проставить в центр системы лучше что-то помощнее? Благо у меня пылится без дела Raspberry Pi первой ревизии (но и любая другая подойдёт). Внутренние датчики можно подключить, в принципе через GPIO и к малинке напрямую, но у меня роутер с малинкой в одной комнате установлен, а мониторить нужно другую. Если у вас такой проблемы нет - то можно от одной NodeMCU избавиться. Малинка будет получать данные от датчиков, сохранять их в базе данных и при необходимости отображать. Так же к GPIO Raspberry Pi можно подцепить LoRa - приёмник и получать данные от удалённых за пределами Wi-Fi сети датчиков (и вот они Arduino). Ну, и наконец, малинка будет отправлять данные в облако.

Итого, нам понадобится:

  • Raspberry PI

  • ESP8266 (2шт. + 1шт. опционально)

  • BME280 (2 шт.)

  • Часы реального времени DS1302 (опционально)

  • OLED-дисплей 128х64 на SH1106 (опционально)

  • Датчик дождя на компараторе LM373 (опционально)

  • УФ-датчик GY-VEML6070 (опционально)

  • Raspberry Pi Camera (опционально)

  • Arduino Nano (2 шт., опционально)

  • SX1278 (3 шт., опционально)

  • Магнитный компас с чипом QMC5883L/HMC5883L (опционально)

  • Датчик освещённости (светодиодный) с компаратором LM737 (опционально)

  • Датчики напряжения до 25V (опционально)

  • Датчики тока ACS712 (опционально)

Подключение SX1278 к Raspberry Pi

Для начала подключим к малинке радиомодуль.

Raspberry Pi

SX1278

3.3V

3.3V

GROUND

GROUND

GPIO10

MOSI

GPIO9

MISO

GPIO11

SCK

GPIO8

NSS/ENABLE

GPIO4

DIO0

GPIO22

RST

Соединяем пины Raspberry Pi и SX1278 как на картинке:

Замечание: для разных ревизий Raspberry Pi используются разное количество пинов, а значит и распиновки, смотрите документацию.

По поводу использования LoRa-модулей хочу обратить внимание на несколько моментов:

  • Перед подачей питания на модуль LoRa обязательно убедитесь, что к нему подключена антенна, иначе есть риск, что модуль сгорит!

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

Установка сервера

На Raspberry Pi загружаем Raspberry Pi OS Lite.

Далее устанавливаем статический адрес для нашей малинки:

sudo nano /etc/dhcpcd.conf

Добавляем\правим строки на наш желаемый IP и IP наш роутер

interfaceeth0# или wlan0 если малинка подключена по Wi-Fistaticip_address=192.168.0.4/24staticrouters=192.168.0.1staticdomain_name_servers=192.168.0.1. 8.8.8.8

Теперь включаем удалённый доступ через SSH, SPI (нужен для подключения LoRa), а так же Camera, если планируем её использовать.

sudo raspi-config

Включаем:

  • SSH (если собираемся подключаться по SSH, а не только через клавиатуру)

  • SPI (если собираемся использовать LoRa)

  • Camera (если собираемся использовать камеру)

Убеждаемся, что стоит автологин при загрузке:

Boot Options -> Console Autologin

Выходим из raspi-config, перезагружаем:

sudo shutdown -r now

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

Вся логика сервера написана на Python3, поэтому ставим его:

sudo apt-get install python3.7

Теперь осталось загрузить собственно мой проект H.O.M.E.:

cd ~git clone https://github.com/wwakabobik/home.git

В качестве веб-сервера я выбрал flask, на Хабре есть отличная серия статей, поэтому я не буду останавливаться на подробностях при работе с ним.

Копируем контент из папки с сервером:

mkdir web-servercp -r home/home_server/* /home/pi/web-server/

Устанавливаем все зависимости:

cd web-serversudo python3.7 -m pip install-rrequirements.txt

Создаём базу данных из шаблона:

cat db/schema.sql | sqlite3 flask_db

Собственно всё, теперь можем запустить сервер:

cd /home/pi/web-server && sudo python3.7 app.py

Но мы же хотим, чтобы сервер запускался при загрузке Raspberry Pi?

Тогда в конце /etc/rc.local, перед exit 0, добавляем вызов bash-скрипта:

/home/pi/flask_startup.sh &

Копируем этот скрипт на место:

cd ~cp ~/home/bash/flask_startup.sh .

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

cp ~/home/bash/check_health.sh .

Добавляем в планировщик cron:

sudo crontab -e

задание:

1-59/5 * * * * /home/pi/check_health.sh

Немного о софте сервера

За запуск сервера отвечает app.py.

#!/usr/bin/env python3.7from multiprocessing.pool import ThreadPoolfrom flask import Flaskfrom db.db import init_appfrom lora_receiver import run_loraapp = Flask(__name__, template_folder='templates')  # firstly, start Flask# import all routesimport routes.apiimport routes.pagesimport routes.single_pageif __name__ == '__main__':    # Start LoRa receiver as subprocess    pool = ThreadPool(processes=1)    pool.apply_async(run_lora)    # Start Flask server    init_app(app)    app.run(debug=True, host='0.0.0.0', port='80')    # Teardown    pool.terminate()    pool.join()

Обратите внимание, что помимо запуска сервера, в отдельном процессе запускаем LoRa ресивер, который будет получать данные от датчиков и пересылать их на сервер.

В остальном архитектура типична для flaska: все возможные routes вынесены в отдельные файлы, все страницы хранятся в pages, а шаблоны в templates. Логика базы данных лежит в db, статичные файлы (картинки) в static, ну а в camera будем складывать картинки с камеры.

В итоге, текущие показания можно увидеть на dashboard страницах,

а графики и данные - на отдельных (графики рисует plotly).

Софт LoRa-ресивера

home_server/lora_receiver.py

from time import sleepimport requestsfrom SX127x.LoRa import *from SX127x.board_config import BOARDendpoint = "http://0.0.0.0:80/api/v1"class LoRaRcvCont(LoRa):    def __init__(self, verbose=False):        super(LoRaRcvCont, self).__init__(verbose)        self.set_mode(MODE.SLEEP)        self.set_dio_mapping([0] * 6)    def start(self):        self.reset_ptr_rx()        self.set_mode(MODE.RXCONT)        while True:            sleep(.5)            rssi_value = self.get_rssi_value()            status = self.get_modem_status()            sys.stdout.flush()    def on_rx_done(self):        self.clear_irq_flags(RxDone=1)        payload = self.read_payload(nocheck=True)        formatted_payload = bytes(payload).decode("utf-8", 'ignore')        status = self.send_to_home(formatted_payload)        if status:            sleep(1)  # we got the data, force sleep for a while to skip repeats        self.set_mode(MODE.SLEEP)        self.reset_ptr_rx()        self.set_mode(MODE.RXCONT)    def send_to_home(self, payload):        if str(payload[:2]) == '0,':            requests.post(url=f'{endpoint}/add_wind_data', json={'data': payload})        elif str(payload[:2]) == '1,':            requests.post(url=f'{endpoint}/add_power_data', json={'data': payload})        else:            print("Garbage collected, ignoring")  # debug            status = 1        return statusdef run_lora():    BOARD.setup()    lora = LoRaRcvCont(verbose=False)    lora.set_mode(MODE.STDBY)    # Medium Range  Defaults after init are 434.0MHz, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 13 dBm    lora.set_pa_config(pa_select=1)    assert (lora.get_agc_auto_on() == 1)    try:        lora.start()    finally:        lora.set_mode(MODE.SLEEP)        BOARD.teardown()

В этом коде главное - это получение пакета в событии on_rx_done - если пакет получен, нужно его декодировать.

Проверяем в send_to_home что payload[:2] равен ожидаемому коду датчика (я для простоты использую значения 0, и 1,), то отсылаем на сервер и спим секунду, чтобы пропустить повторные пакеты.Если нет, продолжаем получать пакеты.

API


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

Именно через Flask REST API мы будем посылать или получать данные от сенсоров.

home_server/routes/api.py

@app.route('/api/v1/send_data')def send_weather_data():    return send_data()@app.route('/api/v1/add_weather_data', methods=['POST'])def store_weather_data():    if not request.json:        abort(400)    timestamp = str(datetime.now())    unix_timestamp = int(time())    data = request.json.get('data', "")    db_data = f'"{timestamp}", {unix_timestamp}, {data}'    store_weather_data(db_data)    return jsonify({'data': db_data}), 201

Данные пишутся в лог:

В моём случае, если мы получили данные от датчика (получили POST запрос с верным JSON), то мы их сохраняем в БД. Так же, если мы получили GET запрос на отправку данных (send_data), то данные отправляем данные на облако.

home_server/pages/weather_station/send_data.py

def send_data():    data = get_last_measurement_pack('0', '1')    image = take_photo()    wu_data = prepare_wu_format(data=data)    response = str(send_data_to_wu(wu_data))    response += str(send_data_to_pwsw(wu_data))    response += str(send_data_to_ow(data))    response += str(send_data_to_nardmon(data))    send_image_to_wu(image)    copyfile(image, f'{getcwd()}/camera/image.jpg')    return response

Ах да, забыл упомянуть камеру. Если мы подключили камеру к Raspberry Pi, то можем отправлять или сохранять изображения погоды за окном. Для этого есть отдельный метод:

home_server/pages/shared/tools.py

from picamera import PiCamera<...>camera = PiCamera()<...>def take_photo():  camera.resolution = (1280, 720) # lower resolution to fit in limits  camera.start_preview()  sleep(5)  image = f'{getcwd()}/camera/image_{int(time())}.jpg'  camera.capture(image)  camera.stop_preview()  return image  

Внешние датчики

полные скетчи можно найти в home/iot

Самым удобным и простым модулем для любительской метеостанции является модуль BME280, объединяющий в себе термометр, датчик влажности и давления. Подключаем его по I2C к ESP8266:

Прошивать будем через Arduino IDE (как добавить ESP8266 написано, например, в этой статье).

iot/esp8266/weatherstation_in/weatherstation_in.ino

#include <ESP8266WiFi.h>#include <ESP8266HTTPClient.h>#include <Wire.h>#include <SPI.h>#include <Adafruit_BME280.h>#include <Arduino_JSON.h>Adafruit_BME280 bme; // use I2C interfaceAdafruit_Sensor *bme_temp = bme.getTemperatureSensor();Adafruit_Sensor *bme_pressure = bme.getPressureSensor();Adafruit_Sensor *bme_humidity = bme.getHumiditySensor();// Датчик не сказать, чтобы очень точный, поэтому добавляем корректирующие значенияfloat correction_temperature = -0.5;float correction_pressure = 15;float correction_humidity = 10;// подключаем Wifivoid connect_to_WiFi(){ WiFi.mode(WIFI_STA); WiFi.begin(wifi_ssid, wifi_password); while (WiFi.status() != WL_CONNECTED) {   delay(500); } Serial.println("WiFi connected"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); #endif}/* <> */// собираем данные с датчиковfloat get_temperature(){  sensors_event_t temp_event, pressure_event, humidity_event;  bme_temp->getEvent(&temp_event);  return temp_event.temperature + correction_temperature;}/* <> */// также точку росы можно вычислить до отправки на сервер, делаем это:float get_dew_point(){  float dew_point;  float temp = get_temperature();  float humi = get_humidity();  dew_point = (temp - (14.55 + 0.114 * temp) * (1 - (0.01 * humi)) - pow(((2.5 + 0.007 * temp) * (1 - (0.01 * humi))),3) - (15.9 + 0.117 * temp) * pow((1 - (0.01 * humi)), 14));  return dew_point;}/* <> */// Форматируем в строкуString get_csv_data(){  String ret_string = DEVICE_ID;  ret_string += delimiter + String(get_temperature());  ret_string += delimiter + String(get_humidity());  ret_string += delimiter + String(get_pressure());  ret_string += delimiter + String(get_dew_point());  return ret_string;}// Отправляем через HTTP, упаковав строку в JSON:void post_data(){  check_connection();  HTTPClient http;  //Declare object of class HTTPClient  String content = get_csv_data();  int http_code = 404;  int retries = 0;  while (http_code != 201)  {    http.begin(api_url); // connect to request destination    http.addHeader("Content-Type", "application/json");    // set content-type header    http_code = http.POST("{\"data\": \"" + content +"\"}");  // send the request    http.end();                        // close connection    retries++;    if (retries > max_retries)    {          Serial.println("Package lost!");      break;    }  }}// cобственно, повторяем это время от времени:void loop(){  post_data();  delay(cooldown);}

По умолчанию у меня стоит интервал в 5 минут, и я считаю, что DEVICE_ID = "0" внутренний датчик, а DEVICE_ID = "1" внешний.

Датчик дождя LM393+YL83Датчик дождя LM393+YL83

К внешнему датчику можно подключить так же датчики ультрафиолета (
GY-VEML6070) и датчик дождя (на компараторе LM393). YL-83 достаточно игрушечный вариант для реального измерения уровня осадков, по крайней мере без калибровки, но, на какое-то время сгодиться, потому что мне актуальность по уровню осадкам не сильно интересует. Ну, точнее интересует на уровне "на улице дождь" или "сухо". Так же, альтернативно, можно использовать аналоговый датчик ультрафиолета GY-8511, но тогда придётся выбирать между ним и датчиком дождя, так как аналоговый вход на NodeMCU только один. Датчик ультрафиолета можно использовать, например, для оценки эффективности солнечных панелей. Ну и просто показывает дни, когда лучше воспользоваться солнцезащитным кремом во время покоса газона.

Схема подключения к ESP8266 ниже:

Для этих датчиков соответственно добавим три функции:

iot/esp8266/weatherstation_out/weatherstation_out.ino

#include "Adafruit_VEML6070.h"Adafruit_VEML6070 uv = Adafruit_VEML6070();#define VEML6070_ADDR_L   (0x38) ///< Low addressRAIN_SENSOR_PIN = A0;/* <...> */#ifdef UV_ANALOG_SENSORvoid get_uv_level(){    int uv_level = averageAnalogRead(UV_PIN);    float uv_intensity = mapfloat(uv_level, 0.99, 2.8, 0.0, 15.0);    return uv_intensity;}#endif#ifdef UV_I2C_SENSORvoid get_uv_level(){return uv.readUV();}#endif#ifdef RAIN_SENSORvoid get_rain_level(){    int rain_level = averageAnalogRead(RAIN_SENSOR_PIN);    return rain_level;}#endif

NodeMCU удобно использовать, когда есть устойчивый Wi-Fi в зоне их действия. Конечно, ставить внешние датчики для погодной станции на крыльце - плохая идея, но оборудованная точка, отнесённая пару-тройку метров от дома - то, что нужно, а сигнала роутера в доме хватает за глаза.

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

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

  • Датчик ветра - на высоте 10-12 м над землёй (именно над землёй, а не на крышах зданий; в исключительном случае разрешается размещение дачтика ветра на крыше одноэтажного дома, так чтобы датчик возвышался над верхним краем крыши не менее чем на 2-3 м, а над поверхностью земли на 10-12 м).

  • В худшем случае (при этом велик риск погрешностей, особенно в ночное время) датчик Т и влажности может быть установлен с теневой стороны здания, на высоте 2 м над землёй, на штанге длиной от стены как минимум метра 3 , над газоном (не над асфальтом!). Ни в коем случае не рекомендуется устанавливать их поблизости от сильно нагревающихся поверхностей, например крыш, стен и т.п.

  • Датчик атмосферного давления устанавливается в помещении вдали от окон и отопительных приборов. Атмосферное давление зависит от высоты над уровнем моря места, где производится измерение; поэтому требуется калибровка датчика давления перед его использованием. Для правильной установки прибора необходимо воспользоваться показаниями другого барометра или данными ближайшей метеостанции (с учётом разности высот, определённой по подробной топографической карте; 10 м подъёма соответствует уменьшению давления примерно на 1 мм рт.ст. или 1.3 гПа (мБ)).

Как опция, можем добавить ещё одно устройство на ESP8266, которое будет отображать данные с метеостанции. В моём случае - удобно не просто подключить дисплей к внутреннему датчику, а иметь независимое устройство, которое можно расположить где угодно. Для того, чтобы оно что-нибудь ещё делало - добавим к нему часы реального времени.

Затем загрузим на него скетч, который будет отображать текущее время (ЧЧ:ММ) и в бегущей строке данные с метеостанции:

iot/informer/esp8266/informer/informer.ino

#include <ESP8266WiFi.h>#include <ESP8266HTTPClient.h>#include <Wire.h>#include <U8g2lib.h>#include <virtuabotixRTC.h>  // https://ampermarket.kz/files/rtc_virtualbotix.zip// RTCvirtuabotixRTC myRTC(14, 12, 13);// OLEDU8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0);u8g2_uint_t offset;            // current offset for the scrolling textu8g2_uint_t width;             // pixel width of the scrolling text (must be lesser than 128 unless U8G2_16BIT is definedconst int string_length = 80;  // maximum count of symbols in marqueechar text[string_length];      // text buffer to scroll// Wi-Ficonst char* wifi_ssid = "YOUR_SSID";const char* wifi_password = "YOUR_PASSWORD";// APIconst String ip_address = "YOUR_IP_OF_SERVER";const String port = "YOUR_PORT";const String api_endpoint = "/api/v1/add_weather_data";const String api_url = "http://" + ip_address + ":" + port + api_endpoint;const int max_retries = 5;  // number of retries to send packet// Timers and delaysconst long data_retrieve_delay = 300000;const int cycle_delay = 5;unsigned long last_measurement = 0;void setup(void) {    Serial.begin(9600);    init_OLED();    init_RTC();}/* Init functions */void init_OLED(){    u8g2.begin();      u8g2.setFont(u8g2_font_inb30_mr); // set the target font to calculate the pixel width    u8g2.setFontMode(0);              // enable transparent mode, which is faster}void init_RTC(){    // seconds, minutes, hours, day of the week, day of the month, month, year    // раскомментируйте при прошивке, заполнив текущую дату и время, затем снова закомментируйте и прошейте ещё раз    //myRTC.setDS1302Time(30, 03, 22, 5, 19, 2, 2021); // set RTC time    myRTC.updateTime(); // update of variables for time or accessing the individual elements.}""" <...> """  String get_data(){    check_connection();    #ifdef DEBUG    Serial.println("Obtaining data from server");    #endif    HTTPClient http;    //Declare object of class HTTPClient      int http_code = 404;    int retries = 0;    String payload = "Data retrieve error";    while (http_code != 200)    {        http.begin(api_url);                // connect to request destination        http_code = http.GET();             // send the request        String answer = http.getString();   // get response payload        http.end();                         // close connection            retries++;        if (retries > max_retries)        {            break;            #ifdef DEBUG            Serial.println("Couldn't get the data!");            #endif        }                        if (http_code == 200)        {            payload = answer;        }    }    return payload;}void loop(void) {    // Check that new data is needed to be retrieved from server    if (((millis() - last_measurement) > data_retrieve_delay) or last_measurement == 0)    {        String stext = get_data();        stext.toCharArray(text, string_length);        last_measurement = millis();        width = u8g2.getUTF8Width(text);    // calculate the pixel width of the text        offset = 0;    }    // Update RTC    myRTC.updateTime();     // Now update OLED    u8g2_uint_t x;    u8g2.firstPage();    do     {        // draw the scrolling text at current offset        x = offset;        u8g2.setFont(u8g2_font_inb16_mr);       // set the target font        do         {                                       // repeated drawing of the scrolling text...            u8g2.drawUTF8(x, 58, text);         // draw the scrolling text            x += width;                         // add the pixel width of the scrolling text        } while (x < u8g2.getDisplayWidth());   // draw again until the complete display is filled            u8g2.setFont(u8g2_font_inb30_mr);       // choose big font for clock        u8g2.setCursor(0, 30);                  // set position of clock        char buf[8];                            // init bufer to formatted string        sprintf_P(buf, PSTR("%02d:%02d"), myRTC.hours, myRTC.minutes); // format clock with leading zeros        u8g2.print(buf);                        // display clock    } while (u8g2.nextPage());      offset-=2;                       // scroll by two pixels    if ((u8g2_uint_t)offset < ((u8g2_uint_t) - width))    {          offset = 0;                  // start over again    }      delay(cycle_delay);              // do some small delay}

В итоге результат работы выглядит так:

Соответственно в Raspberry Pi:

home_server/routes/api.py

@app.route('/api/v1/get_weather_data', methods=['GET'])def store_wind_data():    return send_data_to_informer()  

pages/weather_station/send.data

def send_data_to_informer():    data_in = get_last_measurement_pack('weather_data', '0', '0')    data_out = get_last_measurement_pack('weather_data', '0', '1')    pressure = int((data_in['pressure']+data_out['pressure'])/2)    formatted_string = f"IN: T={data_in['temperature']}*C, " \                       f"H={data_in['humidity']}% | " \                       f"OUT: T={data_out['temperature']}*C, " \                       f"H={data_out['humidity']}%, " \                       f"DP={data_out['dew_point']}*C | " \                       f"P={pressure} mmhg"    return formatted_string

Радиодатчики

Там, где не дотянуться Wi-Fi, нужно использовать альтернативные варианты передачи данных. В моём случае - это использование LoRa-модулей (в связке, например, с Arduino Nano.

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

SX1278

Arduino Nano

3.3V

3.3V

GROUND

GROUND

MOSI

D10

MISO

D2

SCK

D13

NSS/ENABLE

D12

DIO0

D11

RST

D9

И, код, соответственно:

iot/arduino/*_meter/*_meter.ino

// Required includes#include <SPI.h>#include <LoRa.h>// LoRA configconst int LORA_SEND_RETRIES = 5; // сколько раз посылать сообщениеconst int LORA_SEND_DELAY = 20;  // задержка между пакетамиconst int LORA_POWER = 20;       // мощность передатчика на максимум const int LORA_RETRIES = 12;     // сколько раз пытаться инициализировать модульconst int LORA_DELAY = 500;      // задержка между попыткой инициализации// Инициализируем модульvoid init_LoRa() {    bool success = false;    for (int i=0; i < LORA_RETRIES; i++)        {        if (LoRa.begin(433E6)) // используем 433Мгц        {            success = true;            break;        }        delay(LORA_DELAY);    }    if (!success)    {        #ifdef DEBUG        Serial.println("LoRa init failed.");        #endif        stop(4);    }        LoRa.setTxPower(LORA_POWER);  // aplify TX power    #ifdef DEBUG    Serial.println("LoRa started!");    #endif  }#endif// Посылаем пакет с данными строкойvoid LoRa_send(power_data data){    String packet = DEVICE_ID + "," + String(data.avg_voltage,2) + ",";    packet += String(data.avg_current,2) + "," + String(data.avg_power,2) + "," +String(data.avg_consumption,2);    for (int i=0; i < LORA_SEND_RETRIES; i++)    {        LoRa.beginPacket();  // just open packet        LoRa.print(packet);  // send whole data        LoRa.endPacket();    // end packet        delay(LORA_SEND_DELAY);    }  }

Достаточно просто, не правда ли?

Облачные сервисы

Изначально у меня не было цели делиться данными со сторонними сервисами, но во время отладки появилась мысль о том, что неплохо было бы иметь референсные данные с местных метеостанций, для контроля корректности работы своей. Первым, и с самой большой коллекцией примеров и API оказалась WeatherUnderground.

from wunderground_pws import WUndergroundAPI, unitsfrom secure_data import wu_api_key, wu_reference_station_id""" ... """wu_current = wu.current()""" ... """wu_humidity=wu_current['observations'][0]['humidity'],wu_pressure=int(int(wu_current['observations'][0]['metric_si']['pressure'])/1.33),wu_dew_point=wu_current['observations'][0]['metric_si']['dewpt'],wu_wind_speed=wu_current['observations'][0]['metric_si']['windSpeed'],wu_wind_gust=wu_current['observations'][0]['metric_si']['windGust'],wu_wind_direction=wu_current['observations'][0]['winddir'],wu_wind_heading=deg_to_heading(int(wu_current['observations'][0]['winddir']))

Однако, если была возможность быстро получать данные, то почему бы ими не поделиться, подумал я? Данные в WU передаются через GET-запрос, поэтому для удобства предварительно подготавливаем данные

def prepare_wu_format(data, timestamp=None):    payload = f"&dateutc={timestamp}" if timestamp else "&dateutc=now"    payload += "&action=updateraw"    payload += "&humidity=" + "{0:.2f}".format(data['humidity'])    payload += "&tempf=" + str(celsius_to_fahrenheit(data['temperature']))    payload += "&baromin=" + str(mmhg_to_baromin(data['pressure']))    payload += "&dewptf=" + str(celsius_to_fahrenheit(data['dew_point']))    payload += "&heatindex=" + str(celsius_to_fahrenheit(heat_index(temp=data['temperature'], hum=data['humidity'])))    payload += "&humidex=" + str(celsius_to_fahrenheit(humidex(t=data['temperature'], d=data['dew_point'])))    payload += "&precip=" + str(data['precip'])    payload += "&uv" + str(data['uv'])    return payload

затем отправляем:

import requests""" ... """def send_data_to_wu(data):    wu_url = "https://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?"    wu_creds = "ID=" + wu_station_id + "&PASSWORD=" + wu_station_pwd    response = requests.get(f'{wu_url}{wu_creds}{data}')    return response.content

В результате мы должны увидеть данные на своей метеостанции.

Тут нужно сделать ремарку, что все сервисы, включая WU требуют регистрации и часто получения API ключей. Вся конфиденциальная информация хранится в secure_data.py

# Geo Datalatitude =longitude =altitude =cur_location =# WEATHER UNDERGROUND DATAwu_api_key =wu_station_id =wu_station_pwd =wu_reference_station_id =# OPEN WEATHER DATAow_api_key =ow_station_id =# PWSWEATHER DATApwsw_station_id =pwsw_api_key =# NARODMON DATAnarodmon_name = narodmon_owner = narodmon_mac = narodmon_api_key = 

Заполняем значения и продолжаем :)

WeatherUnderground увы, работает на платной основе и полученный мной ключ действует всего лишь год. Поэтому, поискав альтернативы, я наткнулся на PWS Weather.

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

def send_data_to_pwsw(data):    pwsw_url = "http://www.pwsweather.com/pwsupdate/pwsupdate.php?"    pwsw_creds = "ID=" + pwsw_station_id + "&PASSWORD=" + pwsw_api_key    response = requests.get(f'{pwsw_url}{pwsw_creds}{data}')    return response.content

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

Ещё можно послать данные на OpenWeatherMap. Персональной страницы тут нет, а в ответ на исторические данные мы получим "средние" по больнице данные, но, почему бы и нет? Энтузиастам надо помогать. Для передачи показаний у OWM для PWS (personal weather station) своё API, но что-то я не нашёл готовой обёртки для него на python, поэтому написал свою.

В отличие американских WeatherUnderground и PWS Weather, использующих имперскую систему, разраработчики OpenWeatherMap из Латвии и используют метрическую систему (Си), поэтому для передачи показаний для них не используем конвертеры, а пишем данные сразу из базы данных, которые мы собрали с датчиков.

from openweather_pws import Stationdef send_data_to_ow(data):    pws = Station(api_key=ow_api_key, station_id=ow_station_id)    response = pws.measurements.set(temperature=data['temperature'], humidity=data['humidity'],                                    dew_point=data['dew_point'], pressure=data['pressure'],                                    heat_index=fahrenheit_to_celsius(heat_index(temp=data['temperature'],                                                                                hum=data['humidity'])),                                    humidex=humidex(t=data['temperature'], d=data['dew_point']))    return response

И, наконец, как вариант импортозамещения самый функциональный, позволяющий хранить в том числе данные с закрытых датчиков (например те же данные о температуре внутри дома) - Narodmon.

На сервисе достаточно богатое API, позволяющее не только передавать показания с датчиков, но и собирать информацию по геолокации, управлять самим устройством удалённо, так и социальные фишки вроде "поставить лайк" или отправить сообщение. Особо здорово, что сервис шлёт email'ы в случае проблем (например датчик не вышел на связь час), так и настраиваемые "проблемы" вроде превышения лимита на конкретном датчике. Но, как и в случае OWM я не нашёл полного API-wrapper для python, и опять написал свой. Теперь, чтобы отправить данные с датчиков, зовём:

def send_data_to_nardmon(data):    nm = Narodmon(mac=narodmon_mac, name=narodmon_name, owner=narodmon_owner,                  lat=latitude, lon=longitude, alt=altitude)    temperature = nm.via_json.prepare_sensor_data(id_in="TEMPC", value=data['temperature'])    pressure = nm.via_json.prepare_sensor_data(id_in="MMHG", value=(data['pressure']))    humidity = nm.via_json.prepare_sensor_data(id_in="HUM", value=data['humidity'])    dew_point = nm.via_json.prepare_sensor_data(id_in="DEW", value=data['dew_point'])    sensors = [temperature, pressure, humidity, dew_point]    response = nm.via_json.send_short_data(sensors=sensors)    return response

У данного сервиса есть одна дурацкая отличительная особенность, состоящая в том, что нельзя отправлять данные чаще чем раз в пять минут. Но на практике то ли у нас разные пять минут, то ли сайт подвисает, реально данные отправляются раз в 10-15 минут. Если всё сделано правильно, то увидим данные на сайте.

Немаловажным будет сказать, что для отправки данных следует "дёргать" ручку /api/v1/send_data пустым GET-запросом. Чтобы не изобретать велосипед, просто поручим это делать cron. Добавляем ещё одну строку:

*/5 * * * * /usr/bin/wget -O - -q -t 1 http://0.0.0.0:80/api/v1/send_data

А как же камера?

Пока никак. Сделанные фото можно передавать на WeatherUnderground. Это сделать несложно через ftp

from ftplib import FTPdef send_image_to_wu(image):    session = FTP('webcam.wunderground.com', wu_cam_id, wu_cam_pwd)    file = open(image, 'rb')    session.storbinary('image.jpg', file)    file.close()    session.quit()

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

Альтернативной является передача изображения на narodmon.ru,

Собственно, время от времени (раз в полчаса) дёргаем ручку /api/v1/capture_photo (которая зовёт take_photo). Например, будем звать через cron этот bash-скрипт:

#!/bin/bashPATH_TO_PHOTO=`/usr/bin/wget -O - -q -t 1 http://0.0.0.0/api/v1/capture_photo`REQUEST='curl -F YOUR_CAM_KEY=@'$PATH_TO_PHOTO' http://narodmon.ru/post'RESULT=`$REQUEST` >/dev/null 2>&1

На сервисе сразу появится снимок:

Плюс, не забываем время от времени (например раз в семь дней) чистить старые изображения:

#!/bin/bash bash# Notes:# This file will remove all files in camera folder older than 7 days, just run in via cron periodically (i.e. daily).find /home/pi/web-server/camera/ -type f -mtime +7 -name '*.jpg' -execdir rm -- '{}' \;

Что дальше?

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

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

Подробнее..

Умная камера на базе Raspberry Pi с управлением через Telegram-бота

06.03.2021 14:07:53 | Автор: admin

Привет, меня зовут Иван. Сразу отвечу на главный вопрос: почему стал собирать сам, а не взял готовое решение? Во-первых, стоимость готовых решений - Raspberry Pi со всеми датчиками и камерой вышла не больше $30, большая часть еще по курсу 60 рублей за доллар. Во-вторых, почти все части уже были - Raspberry Pi отдал брат, камера осталась еще с лохматых времен, диод тоже был - покупал для Arduino, а датчик движения на Aliexpress стоил не больше 100 рублей.

Повествование в статье будет построено следующим образом:

  1. Определим что нам потребуется;

  2. Поработаем с диодом;

  3. С датчиком движения;

  4. С камерой (фото);

  5. С камерой (видео);

  6. Разберем работу с Telegram-ботом (рассмотрим скелет);

  7. Создадим "Умную камеру";

  8. Посмотрим на работу "Умной камеры";

  9. Определим узкие места и возможные решения.

Итак, поехали

Что нам потребуется

На Raspberry должен быть настроен интернет, установлены:

  • ffmpeg - для записи видео с камеры;

  • Python 3.7.

У Python должны быть следующие библиотеки:

  • RPi.GPIO;

  • pygame;

  • telebot.

И понадобятся провода - F2F, что бы все это соединить.

Работа с диодом

import RPi.GPIO as GPIOimport timeLED_PIN = 3def setup():    GPIO.setmode(GPIO.BOARD)    GPIO.setwarnings(False)    GPIO.setup(LED_PIN, GPIO.OUT)def destroy():    GPIO.output(LED_PIN, GPIO.LOW)    GPIO.cleanup()def blink():    GPIO.output(LED_PIN, GPIO.HIGH)    time.sleep(1)    GPIO.output(LED_PIN, GPIO.LOW)def main():    setup()    blink()    destroy()if __name__ == '__main__':    main()

Импортируем библиотеку для работы с нодами Raspberry, определяем нод для диода. В методе настройки библиотеки указываем, что нумерация нодов будет в соответствии с номерами на самой Raspberry, отключаем все предупреждения библиотеки и сообщаем, что на нод диода ток будет выходить, а не считываться. В методе очистки ресурсов отключаем диод и очищаем библиотеку. В главном методе - blink подаем сигнал на нод диода, ждем 1 секунду и выключаем подачу сигнала на нод диода. В методе main вызываем все методы подряд и больше ничего не делаем. Светом диода будем отображать обнаруженение движения датчиком.

Работа с датчиком движения

Перед подключением датчика движения к Raspberry необходимо для начала определить какой провод за что отвечает, потому что на некоторых датчиках земля находится слева, на некоторых - справа и это будет кардинально влиять на работу датчика:

После этого можно подключать датчик и настраивать его физически - скорректировать значение delay и sensitivity для своих нужд, вот пример моей настройки:

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

В принципе, работа с датчиком движения сводится к одному методу - методу чтения сигнала с датчика (16 строка).

import RPi.GPIO as GPIOimport timePIR_PIN = 11def setup():    GPIO.setmode(GPIO.BOARD)    GPIO.setwarnings(False)    GPIO.setup(PIR_PIN, GPIO.IN)def destroy():    GPIO.cleanup()def sensorJob():    while True:        i = GPIO.input(PIR_PIN)                print("PIR value: " + str(i))                time.sleep(0.1)def main():    setup()    sensorJob()    destroy()if __name__ == '__main__':    main()

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

Работа с камерой (фото)

С "железом" разобрались и теперь можно переходить к съемке фото и видео. Подключаем камеру к любому USB-порту, по необходимости, настраиваем. Вероятнее всего, операционная система сама подцепит нужные драйвера и дополнительной настройки не потребуется. Если у вас подключена 1 камера она будет называться /dev/video0. Также важно определить разрешение камеры, потому что можно получить фотографии сплошным черным цветом.

from datetime import datetimeimport pygameimport pygame.camerapygame.init()pygame.camera.init()pygame.camera.list_cameras() cam = pygame.camera.Camera("/dev/video0", (640,426))def saveCapture():    filename = datetime.now().strftime('%d-%m-%Y %H:%M:%S') + '.jpg'        cam.start()    pygame.image.save(cam.get_image(), filename)    cam.stop()def main():    setup()    saveCapture()    destroy()if __name__ == '__main__':    main()

Импортируем библиотеку для работы с камерой. Инициализируем библиотеку, инициализируем расширение для работы с камерой, выводим список доступных камер, сохраняем нужную нам камеру в переменную, во втором параметре указываем разрешение камеры. В методе saveCapture определяем название файла, вызываем метод start у камеры, через метод get_image() у камеры получаем объект со снимком, сохраняем его методом pygame.image.save, в завершение останавливаем работу камеры методом stop. Очень важно останавливать работу камеры через библиотеку pygame, потому что библиотека ffmpeg будет пытаться использовать камеру и в случае, если мы ее не освободим будет завершаться ошибкой.

Работа с камерой (видео)

Для съемки видео мы будем отправлять в терминал сообщение следующего вида:

ffmpeg -f v4l2 -framerate 25 -video_size 640x426 -i /dev/video0 -t 5 -c copy <filename>

Где будем указывать формат видео - v4l2, количетсво кадров, разрешение съемки, главный аргумент -c copy, если у вас медленная камера, с этим параметром съемка и сохранение файла будет происходить в десятки раз быстрее, но будет отсутствовать preview у видео и в Telegram не будет отображаться количество времени, которое длится видео. Также, нельзя будет просмотреть видео прямо из Telegram, потребуется отдельный плеер.

Каркас Telegram-бота

Перед рассмотрением работы с Telegram-ботом предполагаем, что вы уже получили ключ от BotFather и выполнили настройку бота на стороне Telegram, там нет ничего сложного, поэтому не будем на этом останавливаться. Также, мы будем работать сразу с InlineKeyboard у Telegram-бота, потому что это удобно и не нужно переживать о том, как правильно писать ту или иную команду. Кроме того, в самом начале будем делать проверку на ID пользователя, чтобы никто случайно (или специально) не подглядывал в нашу камеру.

from telebot.types import InlineKeyboardMarkup, InlineKeyboardButtonimport telebotTOKEN = '99999999999:xxxxxxxxxxxxxxxxxx'ADMIN_USER_ID = 999999999bot = telebot.TeleBot(TOKEN)@bot.message_handler(commands=['start'])def start(message):        telegram_user = message.from_user        if telegram_user.id != ADMIN_USER_ID:        bot.send_message(message.chat.id, text="Hello. My name is James Brown. What do i do for you?")                return               keyboard = [        [            InlineKeyboardButton("Send capture", callback_data='sendCapture'),            InlineKeyboardButton("Send video", callback_data='sendVideo')        ],    ]    bot.send_message(chat_id=message.chat.id,                         text="Supported commands:",                         reply_markup=InlineKeyboardMarkup(keyboard))def sendCapture(chat_id):    bot.send_photo(chat_id, photo=open('<filename>', 'rb'))def sendVideo(chat_id):    bot.send_video(chat_id, open('<filename>', 'rb'))@bot.callback_query_handler(func=lambda call: True)def button(call):    globals()[call.data](call.message.chat.id)def main():    setup()    bot.polling(none_stop=False, interval=5, timeout=20)    destroy()if __name__ == '__main__':    main()

Импортируем классы для InlineKeyboard, импортируем библиотеку Telegram-бота. В переменной TOKEN указываем ключ от BotFather. Сохраняем ADMIN ID. С помощью нотаций указываем команду для метода start. В методе start делаем проверку на USER ID и если это не мы, то выводим сообщение и выходим из метода, если же это мы, то отправляем InlineKeyboard с доступными командами. При отправке клавиатуры можно также сразу отправлять и текст. В методах sendCapture и sendVideo показаны примеры команд для отправки фото и видео через Telegram-бота. Далее нам нужно указать метод, который будет обрабатывать нажатия на InlineKeyboard, тоже через нотацию, но теперь нотация немного другая, вызов метода по нажатию на кнопку делаем по имени этого метода. В методе main вызываем bot.pooling, который в бесконечном цикле проверяет наличие входящих сообщений боту. Если у вас быстрая Raspberry и интернет, то можете не указывать параметры у этого метода и оставить их по-умолчанию. У меня стабильность отправки сообщений была низкой из-за чего пришлось добавить interval = 5. В конце статьи расскажу на что это влияет.

"Умная камера"

Подключаем диод и датчик движения к нужным GPIO нодам, камеру к USB.

Нумерация нодов

У меня это выглядит вот так:

Теперь соберем все куски логики, описанные ранее и получим "Умную камеру" с управлением через Telegram-бота.

from datetime import datetimefrom telebot.types import InlineKeyboardMarkup, InlineKeyboardButtonimport telebotimport loggingimport pygameimport pygame.cameraimport RPi.GPIO as GPIOimport threadingimport timeimport osTOKEN = '99999999999:xxxxxxxxxxxxxxxxxxxxxx'ADMIN_USER_ID = 999999999999LED_PIN = 3PIR_PIN = 11VIDEO_FILE_FORMAT = '.mkv'# Enable Logginglogging.basicConfig(        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',        level=logging.INFO)logger = logging.getLogger(__name__)logger.setLevel(logging.DEBUG)isSensorEnabled = FalseisMuteNotifications = Falselast_chat_id = -1keyboard = []pygame.init()pygame.camera.init()pygame.camera.list_cameras() cam = pygame.camera.Camera("/dev/video0", (640,426))bot = telebot.TeleBot(TOKEN)def setup():    GPIO.setmode(GPIO.BOARD)     GPIO.setwarnings(False)    GPIO.setup(LED_PIN, GPIO.OUT)    GPIO.setup(PIR_PIN, GPIO.IN)def destroy():    GPIO.output(LED_PIN, GPIO.LOW)    GPIO.cleanup() def log_params(method_name, message):    logger.debug("Method: %s\nFrom: %s\nchat_id: %d\nText: %s" %                (method_name,                 message.from_user,                 message.chat.id,                 message.text))@bot.message_handler(commands=['start'])def start(message):    global keyboard        log_params('start', message)        telegram_user = message.from_user        if telegram_user.id != ADMIN_USER_ID:        bot.send_message(message.chat.id, text="Hello. My name is James Brown. What do i do for you?")                return               keyboard = [        [InlineKeyboardButton("Start sensor", callback_data='start_sensor')],        [            InlineKeyboardButton("Get capture", callback_data='get_capture'),            InlineKeyboardButton("Get video", callback_data='get_video')        ],    ]    bot.send_message(chat_id=message.chat.id,                         text="Supported commands:",                         reply_markup=InlineKeyboardMarkup(keyboard))def sendCapture(chat_id):    filename = datetime.now().strftime('%d-%m-%Y %H:%M:%S') + '.jpg'        if (os.path.exists(filename)):        bot.send_photo(chat_id, photo=open(filename, 'rb'))    else:        cam.start()        pygame.image.save(cam.get_image(), filename)        cam.stop()        bot.send_photo(chat_id, photo=open(filename, 'rb'))def get_capture(chat_id):    sendCapture(chat_id)    bot.send_message(chat_id=chat_id,                     text="Supported commands:",                     reply_markup=InlineKeyboardMarkup(keyboard))def sendVideo(chat_id):    filename = sorted(list(filter(lambda x: x.endswith(VIDEO_FILE_FORMAT), os.listdir())))[-1]    bot.send_video(chat_id, open(filename, 'rb'))def captureVideo():    filename = datetime.now().strftime('%d-%m-%Y %H:%M:%S') + VIDEO_FILE_FORMAT        os.system("ffmpeg -f v4l2 -framerate 25 -video_size 640x426 -i /dev/video0 -t 5 -c copy \"" + filename + "\"")        return filenamedef get_video(chat_id):    bot.send_message(chat_id=chat_id,                     text="Capturing video..")            filename = captureVideo()    bot.send_message(chat_id=chat_id,                     text="Sending video..")    bot.send_video(chat_id, open(filename, 'rb'))    bot.send_message(chat_id=chat_id,                     text="Supported commands:",                     reply_markup=InlineKeyboardMarkup(keyboard))def sensorJob():    global isSensorEnabled    global keyboard        isRecording = False        while isSensorEnabled:        i = GPIO.input(PIR_PIN)                GPIO.output(LED_PIN, i)                if (i == 1 and not isRecording):            isRecording = True                        if (not isMuteNotifications):                sendCapture(last_chat_id)                if (isRecording):            captureVideo()                if (i == 0 and isRecording):            if (not isMuteNotifications):                sendVideo(last_chat_id)                        isRecording = False                time.sleep(0.1)            if (isRecording):        sendVideo(last_chat_id)        keyboard = [        [InlineKeyboardButton("Start sensor", callback_data='start_sensor')],        [            InlineKeyboardButton("Get capture", callback_data='get_capture'),            InlineKeyboardButton("Get video", callback_data='get_video')        ],    ]    bot.send_message(chat_id=last_chat_id,                     text="Sensor stopped")    bot.send_message(chat_id=last_chat_id,                         text="Supported commands:",                         reply_markup=InlineKeyboardMarkup(keyboard))def start_sensor(chat_id):    global keyboard    global isSensorEnabled    global last_chat_id        last_chat_id = chat_id    isSensorEnabled = True        threading.Thread(target=sensorJob).start()        keyboard = [        [            InlineKeyboardButton("Stop sensor", callback_data='stop_sensor'),            InlineKeyboardButton("Mute notifications", callback_data='mute_notifications')        ]    ]    bot.send_message(chat_id=chat_id,                         text="Sensor started")    bot.send_message(chat_id=chat_id,                         text="Supported commands:",                         reply_markup=InlineKeyboardMarkup(keyboard))    def stop_sensor(chat_id):    global keyboard    global last_chat_id        last_chat_id = -1    isSensorEnabled = False        GPIO.output(LED_PIN, GPIO.LOW)        keyboard = [        [InlineKeyboardButton("Start sensor", callback_data='start_sensor')],        [            InlineKeyboardButton("Get capture", callback_data='get_capture'),            InlineKeyboardButton("Get video", callback_data='get_video')        ],    ]    bot.send_message(chat_id=chat_id,                         text="Sensor stop requested")def mute_notifications(chat_id):    global keyboard        isMuteNotifications = True        keyboard = [        [            InlineKeyboardButton("Stop sensor", callback_data='stop_sensor'),            InlineKeyboardButton("Unmute notifications", callback_data='unmute_notifications')        ]    ]    bot.send_message(chat_id=chat_id,                         text="Notifications muted")    bot.send_message(chat_id=chat_id,                         text="Supported commands:",                         reply_markup=InlineKeyboardMarkup(keyboard))def unmute_notifications(chat_id):    global keyboard        isMuteNotifications = False        keyboard = [        [            InlineKeyboardButton("Stop sensor", callback_data='stop_sensor'),            InlineKeyboardButton("Mute notifications", callback_data='mute_notifications')        ]    ]    bot.send_message(chat_id=chat_id,                         text="Notifications unmuted")    bot.send_message(chat_id=chat_id,                         text="Supported commands:",                         reply_markup=InlineKeyboardMarkup(keyboard))@bot.callback_query_handler(func=lambda call: True)def button(call):    globals()[call.data](call.message.chat.id)def main():    setup()    bot.polling(none_stop=False, interval=5, timeout=20)    destroy()if __name__ == '__main__':    main()

Работу сенсора будем запускать в отдельном потоке, поэтому импортируем необходимую библиотеку. Создаем переменную для хранения расширения видео. Логирование из библиотеки logging не влияет на работу "Умной камеры", поэтому не будем заострять на этом внимание. Создаем переменные для флагов о работе сенсора и необходимости отправки уведомлений. Создаем переменную для хранения последнего chat_id, зачем это - расскажу позже. Переменная для хранения клавиатуры нужна, чтобы можно было повторно отправлять нужную клавиатуру. Дальше идет знакомый нам код по инициализации библиотеки pygame и Telegram-бота. Методы setup и destroy нам уже знакомы, метод логирования можно проигнорировать. В методе start проверяем user_id, если пользователь - мы, то отправляем актуальную клавиатуру. В методе sendCapture определяем filename, создаем изображение с камеры и отправляем по chat_id. Метод get_capture нужен для отправки изображения и клавиатуры с актуальными коммандами. Метод sendVideo отвечает за отправку последнего записанного видео. В методе captureVideo определяем filename и в систему отправляем запрос на запись видео с помощью утилиты ffmpeg. Метод get_video служит для отправки видео с отправкой промежуточных статусов.

Дальше рассмотрим ключевой метод sensorJob: здесь в бесконечном цикле считываем сигнал с датчика движения, выводим его на диод и при наличии сигнала сразу отправляем фото и включаем запись видео. Когда работа цикла завершается - отправляем сообщение об отключении датчика движения и актуальную клавиатуру. Так как метод sensorJob работает из потока - здесь нам и понадобится переменная last_chat_id. В методе start_sensor запоминаем сhat_id, устанавливаем флаг работы датчика движения, запускаем поток с методом sensorJob и отправляем статус и актуальную клавиатуру. В методе stop_sensor чистим last_chat_id, устанавливаем флаг работы датчика движения в ложное состояние, отключаем диод и отправляем актуальную клавиатуру. В методах mute/unmute_notifications переключаем в соответствующее положение флаг и отправляем статус и актуальную клавиатуру. На этом логика "Умной камеры" на текущий момент заканчивается. Теперь посмотрим на "Умную камеру" в действии.

Работа "Умной камеры"

Обратите внимание на время начала записи и получения фото и видео - оно очень большое для реальных кейсов, больше 5 минут. Это связано с параметрами в bot.pooling в методе main, а именно с параметром interval. Если оставить его по-умолчанию, то задержка будет минимальна и, как минимум, фото будет приходить практически моментально, но тогда возможны сбои из-за "Connection timeout" в работе Telegram-клиента и надо как-то обрабатывать это дополнительно.

Узкие места и возможные решения

  1. Необходима быстрая флешка, чтобы успевать сохранять видео;

  2. Желательно запись видео инициировать из Python напрямую, например, через библиотеку pyffmpeg, чтобы уменьшить время на инициализацию библиотеки при каждой записи видео;

  3. Хорошая камера, чтобы можно было рязглядеть нарушителя;

  4. Наличие быстрого интернета для более быстрого получения актуального видео.

Подробнее..

100500-ая автоматика полива для растений

04.04.2021 16:09:41 | Автор: admin

Вступление с отступлениями. Задача первой итерации

Долго ли, коротко ли, решено было сделать шайтан-машину для полива растений, которая будет сама выращивать представителей флоры. Кавычки тут подразумеваются уместными в силу, на первый (а может и более) взгляд, необъятности задачи автономности подобных устройств (впрочем, любых роботов, начиная от пылесосов, заканчивая андроидами, которые, как известно, неизвестно, думают ли об электроовцах). Вобщем, для первой итерации было задумано дать растниям воду по расписанию, да не из бака куда её предусмотрительно налил пользователь, а прямо из водопровода (следует заметить, это требование, само по себе оказалось, по сложности реализации, сопоставимым с остальными функциями. Но об этом позже). Чтобы присматривать и корректировать поведение машины, был задуман интерфейс. Сначала локальный (дисплей 16х2, да кнопки), а затем удалённый, в браузере (интернет, локальная сеть).

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

За дело

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

Первый результат

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

пластиковый шаровый клапан для водыпластиковый шаровый клапан для воды

Отложим ардуину

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

STM32

Была приобретена STM32VL-Discovery и уже на ней был запущен тот шаровый клапан. Это был ещё один момент ликования. Работает мотор, щёлкает микрик, мотор останавливается, вода идёт. После годов работы в офисе с монитором, мышкой, да клавиатурой, эти новые звуки мотора, воды были настоящей музыкой.

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

Плата

К моменту разработки удалённого интерфейса устройство уже было оформлено в виде печатной платы. Последняя была отрисована в Eagle и был получен первый опыт производства своих плат на заводе. Это был тот ещё опыт. Одним из запомнившихся моментов стал лак паяльной маски, "внезапно" оказавшийся в местах пайки. Пришлось его скоблить ножом, чтобы припаять компоненты. В целом, плата была без слёз не взглянешь (если понимать в этом деле хоть каплю).

Удалённый интерфейс

Для реализации удалённого управления было решено использовать Raspberry Pi. А связать Pi с STM32 через UART. Писать простенькие сайтики к тому моменту я уже умел, опыт PHP и JS небольшой был.

Задачей посложней оказалось работать с последовательным портом как под Linux, так и на STM32. Под Linux для начала были использованы какие-то стандартные средства (типа, cat /dev/tty > dumpfile и echo -e "data" > /dev/tty), плюс на PHP написан парсер самодельных пакетов, идущих с STM32. Так появился первый протокол устройства. Одновременно с этим я узнал, что PHP годится не только для разовой отрисовки сайтов, но и для работы в бесконечном цикле, в стиле демона. Позже для решения этой задачи был написан демон на C. Разумеется, последний работает на порядки быстрей, прямей и весит меньше.

Поскольку опыт написания сайтов уже какой-то был, смастерить простейший интерфейс для управления железкой на STM32 теперь было не сложней версии с дисплейчиком 16x2. В этом интерфейсе появились кнопки ВКЛ/ВКЛ для ряда твердотельных реле, кнопки Открыть/Закрыть для четырёх клапанов и формочки для четырёх дозаторов удобрений, с длительностью работы оных и кнопкой запуска дозирования. Для визуального контроля результатов работы контроллера была использована веб-камера, подключенная в USB порт Raspberry Pi. Картинки выводились в тот же интерфейс

Дозаторы

Первыми были опробованы самые дешевые перильстатические насосы из Китая. Два вида.

один из типов недорогих дозатороводин из типов недорогих дозаторов

В ходе испытаний они показали себя с не лучшей стороны. Их клинило, дозирование было неравномерным. Следом за ними были опробованы дозаторы японского производителя Welco. Эти устройства оказались значительно более качественными. Настолько, что используются и по сегодняшний день. Меняются только трубки, как расходный материал.

Клапаны

Тот шаровый клапан с мотором-актуатором со временем достаточно плотно сросся с контроллером STM32 и в итоге, вкупе с дальномером HC-SR04 получилось устройство, которое стало исправно поставлять чистую воду в систему полива. Клапан открывал подачу воды из водопровода в фильтр обратного осмоса, наполняя буферный (накопительный) бак. Затем, система полива брала воду уже из накопительного бака.

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

пластиковый соленоидный клапан, белыйпластиковый соленоидный клапан, белый

Главными отличительными особенностями клапанов-соленоидов от шаровых стали более высокое потребление электричества (около 0.4А при 12В, пока открыт) и необходимость создавать на входе повышенное давление воды, чтобы происходило их открывание. Вместе с этими клапанами были найдены более дорогие (тоже соленоидные, тоже пластик, нейлон), не менее китайские, так называемые чёрные клапаны.

черный пластиковый клапанчерный пластиковый клапан

Они потребляли ещё больше тока (до 2А, 12В), но открывались уже без внешнего давления. Чёрные клапаны ставились, к примеру, на входе из накопительного бака в систему полива.

Mixtank. Бак для смешивания растворов

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

Магистраль смешивания

Первые прототипы включали в себя гибкие шланги, выполняющие функции проводников воды. С появлением дозаторов шланги были заменены на жесткие трубки из ПВХ. Так появилась первая зафиксированная сначала на бумаге, а затем и в первом корпусе система трубопроводов. В этой системе трубопроводов одной из частей оказалась магистраль смешивания удобрений. Это был кусок ПВХ трубки диаметром 20мм, в котором были насверлены отверстия около 5мм и с усилием вставлены соединители для ирригационных трубочек 4/6мм. В месте стыка трубы и переходника была применена эпоксидная смола для герметизации стыка.

первая версия корпуса системы поливапервая версия корпуса системы полива

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

Системный насос

Насос, который использовался на начальных стадиях развития системы полива был самый простой, дешёвый, обязательным было только условие вход и выход имеют резьбу в пол-дюйма. Он выдавал в лучшем случае 0.3 атмосферы давления на выходе.

В ходе экспериментов с поливами выяснилось, что подводить трубочки из системы полива и поливать растения таким образом, без обратной связи по влажности почвы получается не очень качественно. Малейшее засорение, изгиб или различная длина трубок от системы полива к растению приводили к неравномерности полива. Один горшок получал больше воды, чем другой, за равное количество времени работы полива. Было найдено решение в виде компенсированных капельниц, которые используются в системах капельного полива. Это такие устройства, которые пропускают через себя фиксированный объём воды, при условии подачи последней под давлением в заданном диапазоне (типичный диапазон рабочих давлений составляет от 1 до 4 атмосфер). Для обеспечения такого давления используются принципиально иные насосы, нежели тот, который имелся. Потому был приобретён мембранный насос высокого давления. Сначала, тоже самый дешёвый, китайский. Он работал от 12В и потреблял до 5 ампер и при работе шумел и вибрировал так, что невольно, система полива, в числе прочих тестов, стала проходить вибрационные тесты, а соседи - тесты терпимости. Тем не менее, тот насос дал требуемое давление и даже с лихвой до 5 атмосфер до срабатывания механической отсечки. Отсечка, к слову, регулируемая винтом, но на тот момент я дополнительно взял датчик давления воды и сделал отсечку программную.

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

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

датчик давления из нержавейкидатчик давления из нержавейки


После стального был хромированный, с резьбой на четверть дюйма.

хромированный датчик давленияхромированный датчик давления


Этот ожидаемо стал ржаветь (соли в растворах не жалеют обычное железо). И уже после него, спустя часы поисков вариантов на алиэкспрессе, был найден пластиковый датчик с резьбой на четверть дюйма. Они оказались долговечными.

Опять насос

Самый дешевый мембранный насос в плане производительности был слабоват. В виду этого, входы и выходы доступных его вариантов имели максимальный размер резьбы 3/8 дюйма. Из которых, полезное сечение для прохода воды и того меньше. А трубки ПВХ и детали к ним имели диаметр 20мм и резьбы в пол-дюйма. Насос был однозначно слабоват. В результате были найдены варианты насосов покрупней и среди них выбран с минимальными шумами, тоже мембранный. Стоил он уже в несколько раз дороже. Такие используются, к примеру, в водопроводе домиков на колёсах, или в лодках для откачивания морской воды. Сам насос покрупней, потяжелей и, в соответствии с ценой, выглядит тоже внушительно.

мембранный насосмембранный насос


Прокачиваемый поток воды с прежних 4-5 поднялся до 10-12 литров в минуту. И насос, действительно, стал работать гораздо тише, с меньшими вибрациями.

Логика и силовая часть. Разделение

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

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

Покумекав над требованиями, набросал первую версию силового модуля и новый контроллер.
В первой версии силового модуля для управления нагрузками была неудачно выбрана микросхема L293. Неудачной она оказалась потому, что в её составе использованы биполярные ключи. Это даёт немалое собственное потребление (и, соответственно, тепловыделение) микросхемы в моменты работы нагрузок. Радиаторы, установленные на микросхемах работали на пределе. В следующем варианте схемы были выбраны драйверы L6205PD. Они выполнены на полевых транзисторах и грелись уже существенно меньше. При этом, позволяли нагружать на каждый канал значительно больше тока. Кроме того, корпус микросхем с окончанием PD в названии микросхемы имеет хорошее теплоотводящее основание, которое позволяет отводить тепло прямо в плату. В результате, в дизайн платы были заложены приличные площади меди как раз для этой функции. Испытания показали удовлетворительные результаты, без использования дополнительных радиаторов, в условиях пассивного охлаждения. Следует заметить, что крепилась плата управления нагрузками внутри пластикового короба, вместе с основным контроллером и Raspberry Pi. Последняя, справедливости ради, в таких условиях, в жаркие дни, в теплице, перегревалась до состояния зависания, в отличие от остальной электроники.

Поскольку разделение силовой и логической частей делалось ради снижения влияния помех от мощных нагрузок на логику, то здесь была применена гальваническая развязка. Выполнена она была на ADUM1250. Соответственно, на плате силового драйвера был поставлен I2C-декодер (экспандер) MCP23017. Рядом с ADUM разместилась сдвоенная оптопара, которая одним каналом делала декодеру сброс и вторым каналом включала/выключала питание на микросхемы драйверов через мощный полевой транзистор. Для питания MCP23017 изначально использовался MINI360, который впоследствии был заменен на LM317. Схема драйвера может работать начиная с около 10 вольт и выше. Потолок не проверял, но оценочно можно смело утверждать 24В, может 36В (теоретически, это разумный предел для LM317). Для L6205 заявлены вообще 50В. На практике вся система проверялась в работе на 12В.

На 4 микросхемы L6205, установленных на одной плате, получается 16 каналов управления для исполнительны устройств. Модульность позволяет подключать несколько плат. Для этого необходимо задать разные I2C адреса для MCP23017 при помощи трёх резисторов, предусмотренных на плате. Одиночные L6205 каналы можно сдваивать (согласно аппноту), чтобы получить больше пропускной способности. Именно так и были запитаны чёрные клапаны (наиболее прожорливые), на минимальной конфигурации системы полива, где одной платы управления нагрузками хватает в самый раз.

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

На основной, системный насос, поскольку он имеет приличную инерцию и мощность, в паре-другой сантиметров от мотора был поставлен ультрабыстрый диод в обратной полярности, чтобы гасить обратное напряжение (fly back diode). Насос, ввиду хорошего потребляемого тока, был запитан не напрямую в силовой драйвер, а через полевой транзистор, затвор которого уже подключен к силовому драйверу.

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

Измерительная техника

Поскольку аппарат сам готовит растворы, то одним из самых важных (после датчика уровня воды) приборов для измерений стал кондуктометр (он же, EC-метр, он же TDS-метр). В список измерительной техники так же попал измеритель кислотности (он же pH-метр), датчик давления воды и термометр. Таким был первоначальный и основной список сенсоров, поддерживаемых логикой основного контроллера.

EC-метр

Не мудрствуя лукаво, был опробован ряд схем, найденных в поисковике. Самая первая страдала недостаточной повторяемостью (половина собранных модулей почему-то не работала). Вторая схема не заработала в железе вообще. Третья заработала, четвертая была дорогая. Выбор пал на третий вариант, которым стал модуль на таймере 555. Суть проста измеряем частоту меандра, которая задаётся парой конденсатор плюс сопротивление. Сопротивление раствор воды с удобрениями. Датчики электропроводности поначалу были сделаны самопальные. Чтобы снизить коррозию электродов, последние были сделаны из позолоченных пинов. Весь датчик был сделан из эпоксидной смолы, что позволило залить сразу в него термодатчик. В роли последнего был выбран DS18B20.

самодельный датчик электропроводностисамодельный датчик электропроводности

Впоследствии эта конструкция заливалась в деталь из ПВХ - переход с трубы 20мм на резьбу пол-дюйма.


Это позволяет вкручивать его в остальную гидросистему аппарата.

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

pH-метр

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

В итоге, была найдена микросхема LMP91200. Этот кандидат требовал минимальной обвязки, в виде того же АЦП и развязки, что и в варианте выше. В качестве ADC был поставлен ADS1110, для развязки - ADUM1250 и всё сразу заработало. Показания с модуля, при свежем сенсоре кислотности обладали завидной стабильностью.

Питание модуля гальванически развязал недорогими (около доллара за штуку) DC-DC преобразователями, типа 0505, на 1 ватт.

Опять EC

Отсутствие развязки по EC модулю на таймере 555 не давали спать спокойно. Кроме того, вода проникала в под эпоксидку и иногда достигала встроенного датчика DS18B20. Это приводило к печальным последствиям в виде ржавчины и почернения проводов датчика температуры. Иногда металл позолоченных пинов съедался вовсе. Помогала их лакировка.

Тем не менее, к тому времени в загашниках уже имелся модуль EVAL-0349.

EVAL-0349 от AnalogEVAL-0349 от Analog

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

В очередной итерации схемы и платы контроллера был заменен блок измерения EC со старого (с таймером 555) на примерно тот, который предлагался в EVAL-0349. Добавлена та же ADUM1250 для изоляции сигнала, 0505 по питанию и показания электропроводности воды вместе с её температурой стали электрически отделены от контроллера. Вместе с этим были испробованы относительно дешевые сенсоры EC из Китая. За два цикла испытаний нареканий не обнаружено.

По ходу дела был также обнаружен весьма экзотический способ измерения солей в воде - индуктивный. Это когда наматывается катушка, изолированная от воды, а в роли сердечника выступает измеряемая вода. Индуктивность получившейся системы, очевидно, зависит от электропроводности воды-сердечника. Таким образом осуществляется измерение. Такие сенсоры обладают повышенной (в сравнении с традиционными, контактными) долговечностью. На али был обнаружен карманный экземпляр за 70 долларов, однако пределы измерений и точность годятся для морской воды, нежели слабых растворов, применяемых в растениеводстве. Мои мимолётные эксперименты намотать катушку на трубу с водой пока не дали положительных результатов.

Влажность субстрата

Скорость, с которой растения потребляют залитый под корень объём жидкости, кроме прочего, зависит от погодных условий (температура, влажность, количество света на листьях). Влажность почвы (или иного субстрата) влияет на состояние корней и, следовательно, также влияет на скорость потребления раствора растением. Перелив плохо, недолив тоже не очень. Чтобы учитывать этот фактор, было решено добавить датчиков. Чтобы минимизировать переделки платы контроллера и оставить её размеры в разумных пределах, было решено использовать беспроводные датчики влажности. Поначалу были интегрированы Bluetooth датчики Xiaomi. Спустя некоторое время по почте пришла ещё пара этих датчиков, с иной прошивкой. Шаманства с версиями прошивок не оставили равнодушным было решено сделать самодельные датчики. В очередной версии платы контроллера был добавлен беспроводной трансивер NRF24.

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

Беспроводные датчики влажности почвы

Подглядев, как китайцы делают за доллар датчики, в которых сенсором является часть платы (Capacitive soil moisture sensor на алиэкспресс), покрытой лаком, сделал аналогичный сенсор. В качестве контроллера был взят уже знакомый STM32, на 20 пинов, только серия уже F0. В качестве измерителя был взят уже знакомый таймер 555. И теперь сенсор стал не сопротивлением (как в EC измерителе), а ёмкостью. На практике изучая вопрос скорости опустошения получившимся датчиком батарейки CR2032, узнал, что есть версия таймера 555, построенная на полевых транзисторах, что означает меньшее энергопотребление (привет L293 и L6205). Называется LMC555.

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

Первые испытания таких датчиков показали, что генерируемая таймером 555 частота (которая расценивается как влажность субстрата) сильно зависит от температуры почвы/датчика. Справедливости ради, аналогичная ситуация и с датчиками кислотности и электропроводности, где для более корректных считываний значений аналогично применяются алгоритмы температурной компенсации показаний. Именно поэтому, подавляющее большинство датчиков EC уже снабжены термодатчиком.

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

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

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

Подробнее..

Edge платы для домашнего Computer Vision

13.04.2021 06:09:41 | Автор: admin

Я люблю делать всякие странные штуки с Computer Vision. Из того, что я выкладывал на Хабре - умная кормушку для птиц и камера для слежения за ребенком. По работе примерно тем же занимаюсь. Так что слежу за актуальным рынком embedded устройств для ComputerVision. Прошлый обзор я делал полтора года назад. Для Embedded это долго. В этом я сосредоточусь на устройствах которые вышли недавно + некоторый анализ что из этих устройств можно использовать дома/для хобби.

Рассказ будет построен следующим образом:

  • Продуктовые железки которые стали классикой продакшна / железки которые почти доросли до таких.Их можно взять и запустить из коробки. Большие OpenSource комьюнити/персональные фреймворки. Время развертывания обученной сети на такой железке в 1-2 дня.

  • Продуктовые железки которые почти стали классикой, но по которым слишком мало открытых проектов/документации/где часть проекта закрыта. В таких проектах сложно ожидать большой подставы, и скорее всего все будет более-менее будет работать. Но вот что нужно будет сделать для работы сети, и как её сконвертировать, как перенести - нельзя будет оценить заранее.

  • Железки которые выглядят интересно, но нет ни гайдов по ним, ни историй успехи, ни подробной документации.

  • Железка есть информации почти нет/нельзя получить без запросов. На рынке нет истории использования/успеха.

Сразу несколько дисклеймеров, чтобы не возвращаться к ним:

  • Далеко не все из перечисленного я лично использовал/тестировал

  • Далеко не все перечислено. Я уверен что забыл/не знаю многое. И очень надеюсь что в комментарии накидаете чего-нибудь интересного

  • Я фокусируюсь на устройствах где есть GPU/NPU или прочие ускорители инференса. Безусловно, есть всякие FPGA, и прочее, но я не считаю их применимыми для хоббийных проектов. (что такое NPU GPU TPU и другие аббревиатуры - можно прочитать в этой замечательной статье)

Часть 1. Ближе всего к продукту

С одной стороны, весь этот раздел можно было бы свести к простому перечислению:

  • Jetson

  • Intel

  • Coral

  • Android телефоны

  • Прочие Embedded, устройства с хорошим процессором, без NPU/GPU

И в этом списке за последние 2 года появился бы лишь Coral. Но, в реальности, все сильно интереснее. Появились не только и не столько новые архитектуры, как имплементации/доработки старых. О чем мы и поговорим.

В мире Jetsonов новинок нет. Сейчас в продаже:

  • jetson nano

  • jetson xavier nx

  • jetson agx

  • jetson tx2

12ого началась конференция GTC от NVIDIA, но ничего нового на ней не объявили, так что, скорее всего, на следующий год ничего нового не будет.

Встречаются имплементации Jetson'а, под другие экосистемы. Самое известное - AWS Panorama. Jetson находящийся внутри экосистемы Амазона.

PanoramaPanorama

Jetson, безусловно, одна из самых удобных плат для хобби. Есть разводка GPIO, много кода который работает из коробки. Нейронные сети можно никуда не конвертировать, используя в оригинальном фреймворке.
Cтоит понимать, что из всех четырех Jetson'ов для хобби лучше всего подходит Nano. Он стоит лишь 100$, что значительно меньше следующего в серии NX, стоящего 400$. В теории, TX2в середине, но его почти нет в продаже + менее удобная плата. Проектов на Jetson очень много. Например из того что было в медийном пространстве - 1, 2. Вот тут есть неплохая подборка.
Лично я участвовал где-то в 5-7 проектах где Jetson был основной платформой. 2-3 из них переросли в полноценные продукты. Но, вынужден сказать, что для хобби его не использовал ни разу. Почему? Какая-то совокупность факторов всегда. Nano у меня был первой серии, там были баги по питанию. Иногда была не нужна производительность дополнительная. Иногда хотелось опробовать чего-то нового.

В отличие от Jetson, на базе Movidius появляются интересные штуки. В первую очередь это M.2 и mPCIe карты. Какие-то даже уже были, когда я писал прошлый обзор: 1, 2, 3.
Сейчас их очень много от разных производителей.

Удобны ли ли они для каких-нибудь прототипов и хобийных проектов? Мне кажется, что ниша есть, но очень узкая:

  • Когда надо много производительности (есть сборки где есть несколько мовидиусов)

  • Когда USB соединение слишком нестабильно, но M.2/PCIe хватит (переносные устройства)

Во вторую очередь - это ряд устройств от luxonis. Они устраивали большую компанию на кикстартере про OAK и OAK-D. OAK это платы где movidius воткнут не на материнскую плату, а на плату с камерой. Кроме того, у них есть несколько устройств с movidius когда он стоит на плате 1, 2. Я не буду вдаваться подробнее тут, кому интересно - про них я делал более подробный обзор у себя в блоге/на Youtube:

Кому лень читать/смотреть - вот краткая выдержка:

  • + Минус одно USB соединение + к стабильности - для части проектов полезно

  • - От USB все равно не уйти - до прода скорее всего не дойдет

  • + Неплохой дизайн, неплохой корпус

  • - Заменили хороший OpenVino на какой-то мутный DepthAI

  • - Дорого. Дороже чем собрать такое с оригинальным Movidius'ом, дороже чем с Jetson Nano

  • - В камере хорошее разрешение, но провален куда более полезный функционал для машинного зрения (ИК диапазон, нормальное управление выдержкой/частотой, синхронизация с вспышкой, и.т.д.)

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

Кроме luxonis до movidius'а в камере догадался FLIR, достаточно крупный производитель камер. Они выпустили FireFly DL, который явно на порядки более продуктовый чем OAK, а стоит только на 100$ дороже (+объектив).

Чтобы закончить с Movidius окончательно. По простоте использования/наличию документации/комментариям и поддержке - на мой взгляд Movidius - это один из самых разумных ускорителей для своих проектов на нейронных сетях. Его минус - сложный переход с продакшну, и необходимость конвертации сети. То что вышло за последние годы - расширяет возможности использования. Но все же мне не хватает плат сравнимых с RPi3 где мовидиус бы стоял напрямую на плате.

Google Coral. Вот тут много нового. В своем прошлом обзоре я был крайне недоволен им - очень ограниченные платы, очень бажные. Но прогресс. Баги пофикшены, выпущена новая линейка. Есть почти все то же самое что и в movidius, только напрямую от производителя - отдельные платы, стики, M.2, pci-e, чистые чипы, и.т.д..

В качестве основного фреймворка - специальный tflite, где уже сильно меньше потерь на конвертации. Но, как видно, слоев все равно сильно меньше чем в том же ONNX.
Из плюсов, про которые не сказал - на базе Coral уже сторонние производители создают свои решения. Например Asus. Из минусов - считанные разы слышал что его использовали в продакшене. И, обычно, для каких-то простых задач.
Для себя я понимаю почему я избегаю Coral - при прочих равных не хочу трогать TensorFlow. А по текущим характеристикам он нигде не превосходит вариантов выше.

Телефоны. Так же, стоит отметить, многие телефоны получили поддержку из плат сопроцессоров для нейронных сетей. Есть несколько фреймфорков для инференса моделей на них. Например тут и тут описывал. Зачастую телефон стал удобнее чем embedded для пилота и хобби. Основной минус - отсутствие периферии. Второй серьезный минус для меня - внутренняя инфраструктура приложений. Конечно, Unity и Flutter упрощают логику использования. Но все же, лично для меня, телефоны сильно сложнее чем Linux-системы.
С другой стороны, в телефоне уже есть и камера и акселерометр, и интернет.

Прочее. Под "прочим" я в первую очередь подразумеваю системы где заход в нейронные сети идет со стороны процессора. Например в процессорах Intel за счет OpenVino можно сильно оптимизировать сети. На некоторых процессорах, например на RaspberryPI есть оптимизация под инструкции Neon. RPi4 вполне может справляться с какими-то задачами детекции и трекинга в реальном времени. Так что если вам нужно с помощью машинного зрения раз в день проверять рассаду - думаю подойдет.

Часть 2. Работает, но мало информации

Есть такая забавная штука. В ML сейчас 90% знаний открыто. Есть статьи, большая часть публикаций с OpenSource. Подробнейшие фреймворки на Nvidia и Intel. Но рынок аппаратных платформ был исторически не такой. Хотите подключить камеру по csi-mpi к своей платформе? Будьте добры купите дорогущий мануал по протоколу. Хотите разрабатывать на нашей платформе? Для этого вам нужно специальное программное обеспечение которое просто так вы не скачаете. И много фирм по производству железа по-другому и не мыслят. Как результат мы имеем полтора гайда на платформу до её покупки. Невозможность протестировать до покупки. Отсутствие форумов по теме. И проблему с каждой функцией где что-то пошло не так.

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

  • RockChip

  • Gyrfalcon

Обе платформы я видел в проде. Даже немного экспериментировал. Но у обоих платформ крайне неудобный фреймворк переноса сетей/использования.

RochChip. Основная платформа на которой все делается - Rockchip 3399Pro. Самая популярная реализация, наверное - Firefly, RockPiN10 или Toybrick.

Что забавно, у того же ASUS есть версия не только на базе Google Coral, но и на базе RockChip.
Сейчас разрабатывается новая версия - 1, 2.
В целом, плюс RockChip'а - это плата которую любят все разработчики железа. Есть референсный дизайн, комплектующие, и.т.д. Собрать продукт проще и быстрее чем на Jetson.
Но перенос сети весьма непредсказуем. Документация куцая и полукитайская. Как поддерживается - не понятно. Я видел несколько проектов где сети все же перенесли. Но, гарантировать что это всегда можно, нельзя.

Gyrfalcon. Вторым примером закрытой архитектуры, но на базе которой я видел проекты - является Gyrfalcon

Забавно, что платы на его базе в продаже почти отсутствуют. Что-то из того что есть: 1, 2, 3 .

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

Делать ли свои проекты на базе этих платформ? Подходят ли они для хобби? В целом, такое мне кажется возможным. Главное чтобы были простые сетки. Классификация/базовая детекция, и.т.д.
По цене такие платформы достаточно дешевы и сравнимы с OpenVino|Jetson вариантами.
Но надо серьезно понимать зачем так делать. Это может быть:

  • желание сделать продукт из своей разработки

  • желание распаять свою систему

  • нехватка в Jetson|RPi каких-то возможностей

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

Часть 3. Внешне все выглядит неплохо, есть какая-то документация, но примеров нет

Пожалуй, сюда я отнесу только одну плату Khadas VIM3 . Много кто о ней знает, но не видел ни одного человека который бы что-то на ней сделал. Есть в открытой продаже, просто купить. Заявлены неплохие параметры по скорости.

Судя по документации перенос моделей достаточно простой. Но, так как никто не пробовал/не тестировал, - не понятны ограничения. Сама плата собрана на базе процессора Amlogic A311D, который содержит NPU модуль. Amlogic многие позиционируют как конкурент RockChip, сравнивая их. Но сравнений именно NPU модулей - нет.

Все что я говорил в прошлом раздели про проекты - глобально справедливо и тут. Единственное, внешне мне приятнее подход Khadas - документация открыта, поддерживаемые гиты, вроде все на русском английском. Возможно как-нибудь возьму попробовать, но пока лень. По цене выглядит неплохо, на уровне Jetson.

Часть 4. Железки есть, информации нет

Большая часть плат тут имеет очень слабую документацию. Часть плат - это отладочные платы для мобильных платформ. Другая часть - платы специально под ML, но по которым очень мало информации и данных в интернете.

BeagleV. Плата которая пока не вышла, но выглядит неплохо. Разработана на базе процессора U74 от SiFive. Используется RISC-V архитектура.

BeagleBoard - странная плата с комьюнити вокруг. Именно вокруг этого комьюнити частично построена плата BeagleV. Плата сделана на базе NPU модуля от Texas Instruments. Вроде даже какие-то репозитории есть:

  1. Фреймворк от TI для обучения нейронных сетей. Аж 55 звезд на гитхабе.

  2. Репозиторий платы. Аж 88 звезд.

Считать ли это "популярным" решением - не уверен. Но, возможно, какие-то базовые сети запустить будет можно.

Пример настоящего Edge (минимальное использование ЦПУ и энергоэффективности) это - Sipeed Maixduino и Grove AI Hat. Но, разработка на них, судя по отзывам, которые я слышал, ужасна. Сети плохо поддерживаются, мало производительности. Вот тут пример использования. Ну, по сути все проблемы обычного Arduino.
Я видел людей которые делали и адекватные проекты на их базе, и хоббийные. Но я не готов:)

Глобально, Qualcomm - это, конечно, производитель процессоров для мобильных. Но, на их же базе, есть какое-то количество именно embedded платформ. При этом, Qualcomm - имеет свой SDK, и свою платформу для исполнения нейронных сетей. Года 2.5 назад я сталкивался с ней. И тогда там была жесть. Простейший слой сложения не поддерживался. Что там говорить про сплиты или объединения. По сути работал лишь VGG на трехканальный вход.
Сейчас, судя по слухам все лучше. К тому же, должен нормально работать Tensorflow lite.
Но вот с платами под эмбеддед у Qualcomm плохо. Есть вот такое (но стоит почти 500 баксов). Или вот такое (мало информации, но выглядит прикольно, за 300 баксов камера + корпус + ускоритель = неплохо).

Примерно так же себя ведет Huawei. Есть фреймворк. Не пользовался, и не знаю. Есть какое-то количество плат. Должен работать Tensorflow lite.
Но, мне сложно придумать где такая плата будет иметь смысл на использование.

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

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

P.S.

Про девайсы которые попадают мне в руки/про которые я читаю - иногда пишу у себя в блоге (telegramm, vk). Наверное, через год-два проапдейчу тут что накопится.
Прошлый апдейт делал на ютубе.

Подробнее..

Изучаем Bash путем написания интерактивой игры, создаем культуру DevOps, а также шпаргалка по MariaDB и MySQL

14.01.2021 16:09:15 | Автор: admin

Начинаем 2021 год с нового дайджеста полезных материалов. Собрали много инсайтов, записей важных вебинаров, книжек и шпаргалок. Оставайтесь с нами станьте частью DevNation!

Начни новое:

  • 5 тенденций гибридного облака, на которые стоит обратить внимание в 2021 году

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

    Вкратце: главный архитектор Red Hat Эмили Бренд (Emily Brand) и другие эксперты делятся советами с ИТ-руководителям.

  • Удаленная работа: 3 способа взбодрить свою команду в 2021 году

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

    Вкратце: главный технический специалист Red Hat по работе с публичным сектором Дэвил Эгтс (David Egts) рассказывает о виртуальных комнатах отдыха и других подобных вещах.

Почитать на досуге:

Скачать:

  • Шпаргалка по MariaDB и MySQL

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

Еще полезное:

  • Запускаем Kubernetes на Raspberry Pi

    Каждую главу этой электронной книги можно читать как самостоятельную единицу или как часть общего руководства по запуску Kubernetes на Raspberry Pi.

  • Шпаргалка по Kubectl

    9 критически важных команд kubectl для устранения неполадок и управления при администрировании кластера Kubernetes.

  • Шпаргалка по Emacs

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

Подробнее..

Изучаем Bash путем написания интерактивной игры, создаем культуру DevOps, а также шпаргалка по MariaDB и MySQL

14.01.2021 18:11:53 | Автор: admin

Начинаем 2021 год с нового дайджеста полезных материалов. Собрали много инсайтов, записей важных вебинаров, книжек и шпаргалок. Оставайтесь с нами станьте частью DevNation!

Начни новое:

  • 5 тенденций гибридного облака, на которые стоит обратить внимание в 2021 году

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

    Вкратце: главный архитектор Red Hat Эмили Бренд (Emily Brand) и другие эксперты делятся советами с ИТ-руководителям.

  • Удаленная работа: 3 способа взбодрить свою команду в 2021 году

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

    Вкратце: главный технический специалист Red Hat по работе с публичным сектором Дэвил Эгтс (David Egts) рассказывает о виртуальных комнатах отдыха и других подобных вещах.

Почитать на досуге:

Скачать:

  • Шпаргалка по MariaDB и MySQL

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

Еще полезное:

  • Запускаем Kubernetes на Raspberry Pi

    Каждую главу этой электронной книги можно читать как самостоятельную единицу или как часть общего руководства по запуску Kubernetes на Raspberry Pi.

  • Шпаргалка по Kubectl

    9 критически важных команд kubectl для устранения неполадок и управления при администрировании кластера Kubernetes.

  • Шпаргалка по Emacs

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

Подробнее..

Установка docker-контейнеров c Zabbix на Raspberry Pi

06.02.2021 10:17:52 | Автор: admin

Добрый день, коллеги!

Сегодня я хочу поделиться с Вами опытом установки приложений в контейнерах Docker на Raspberry Pi.

Появилась необходимость установить Zabbix для тестирования и экспериментов. Zabbix должен быть всегда включен, поэтому установка на ноутбук или стационарный компьютер не подходит. В моем распоряжении был микрокомпьютер Raspberry Pi. Он хорошо подходит для небольших проектов. Маленький и бесшумный - очень удобно.


В проекте использовались:

  1. Аппаратное обеспечение - микрокомпьютер Raspberry Pi v3 B, архитектура CPU - armv7l

  2. Программное обеспечение - операционная система GNU\Linux Raspbian 10. (Будем считать, что Вы умеете работать в командной строке и подключаться по SSH.)

Для начала установим Portainer - веб-интерфейс для управления docker-контейнерами. Бесплатно, удобно, подойдет новичкам в docker.

Установка Portainer:

1) docker volume create portainer_data2) docker run -d -p 9000:9000 \--name portainer \--restart always \-v /var/run/docker.sock:/var/run/docker.sock \-v portainer_data:/data portainer/portainer

После установки веб-интерфейс Portainer будет открыт на http://ip-адрес-хоста:9000

Теперь скачаем и запустим контейнеры с Zabbix-ом.

Могут возникнуть проблемы с установкой контейнера с MySql-сервером из стандартного реестра.

latest: Pulling from library/mysqlno matching manifest for linux/arm/v7 in the manifest list entries

На сайте https://hub.docker.com можно найти контейнеры My Sql для ARM-архитектур. Я воспользовался вот этим контейнером - https://hub.docker.com/r/biarms/mysql.

Стоит обратить внимание на сетевые подключения контейнеров. Шлюз моста займет адрес Х.Х.Х.1, контейнер с Portainer-ом получит адрес Х.Х.Х.2 и так далее. Это будет иметь значение при подключении приложений в контейнерах. Стандартная сеть для docker-контейнеров на bridge - 172.17.0.0/16.

Установка контейнера с My SQL:

1) docker pull biarms/mysql2) docker run -d -p 3306:3306 --name mysql -t \ -e MYSQL_DATABASE="zabbix" \-e MYSQL_USER="zabbix" \-e MYSQL_PASSWORD="zabbix" \-e MYSQL_ROOT_PASSWORD="root" \-d biarms/mysql:latest3) docker logs mysql - посмотреть логи контейнера

Установка контейнера с Zabbix - Server:

172.17.0.3 - это ip-адрес контейнера с MySql-сервером. Посмотреть информацию о сети bridge можно командой - docker network inspect bridge.

1) docker run --name zabbix-server -t -p 10051:10051 \-e DB_SERVER_HOST="172.17.0.3" \-e MYSQL_DATABASE="zabbix" \-e MYSQL_USER="zabbix" \-e MYSQL_PASSWORD="zabbix" \-e MYSQL_ROOT_PASSWORD="root" \--link mysql:mysql \-d zabbix/zabbix-server-mysql:latest2) docker logs zabbix-server - посмотреть логи контейнера

Проверяем подключение к My Sql со стороны Zabbix Server-а:

1) docker exec -it zabbix-server bash - подключаемся к контейнеру2) mysql -u zabbix -p zabbix -h 172.17.0.3 - в контейнере подключаемся к My Sql-серверу.Пароль - zabbix

Установка контейнера с WEB-интерфейсом Zabbix:

1) docker run --name zabbix-web -t -p 8080:8080 \-e DB_SERVER_HOST="172.17.0.3" \-e MYSQL_USER="zabbix" \-e MYSQL_PASSWORD="zabbix" \-e ZBX_SERVER_HOST="172.17.0.4" \-e ZBX_SERVER_NAME="Zabbix" \-e PHP_TZ="Europe/Moscow" \-d zabbix/zabbix-web-apache-mysql:latest2) docker logs zabbix-web - посмотреть логи контейнера

Выполняем вход в веб-интерфейс сервера Zabbix: http://ip_address:8080. Порт 8080 был задан во время установки контейнера с web-интерфейсом Zabbix-а.

Логин и пароль по умолчанию: admin / zabbix

Счастливого использования!

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru