Беспроводной термостат Raspberry Pi — в ржавчине!
26 октября 2022 г.Недавно я отошел от крысиных бегов с полной занятостью и обнаружил, что у меня есть свободное время. Будучи пожизненным технологом, я, естественно, начал интересоваться новыми вещами, на которые у меня не было времени, когда я был занят работой на полную ставку.
Rust появился в коротком списке интересных новых технологий. Я начал программировать на C/C++ в DOS/Windows/Mac/Unix много лет назад, поэтому новый компилируемый язык со статической типизацией, провозглашенный «новым C/C++», был естественным выбором. Просматривая Rust Book, я довольно быстро усвоил концепции, но оказался на стадии "что дальше". Это всегда самый сложный этап изучения новых технологий — вы понимаете основы, но не знаете, с чего начать, чтобы создать что-то «настоящее».
В поисках решения этой проблемы я наткнулся на прекрасную книгу Луки Палмиери: Zero to Production in Rust. В книге рассказывается о создании нетривиального веб-приложения производственного качества на Rust. Разработано и проиллюстрировано множество полезных концепций, в том числе:
* Создание веб-серверного приложения производственного качества на Rust. * Телеметрия — централизованное распределение трассировки/журналов и управление обработкой ошибок в нескольких различных стеках API. * Внедрение аутентификации конечных пользователей — аутентификация пользователей производственного уровня, включая шифрование и защиту от распространенных методов взлома. * Взаимодействие с SQL — в данном случае Postgres, включая миграции. * Использование внешнего API — вызов внешних сервисов на основе REST. * HTML-шаблоны — создание веб-страниц для взаимодействия с конечным пользователем с сервера. * Управление сеансом — в данном случае Redis, но стратегия отслеживания состояния конечного пользователя.
Проработав книгу, я почувствовал, что хорошо разобрался в том, как все это работает. В качестве бонуса я не занимался разработкой веб-серверов на других языках для промышленного уровня, и мне было интересно наблюдать за решением обычных задач в этой среде. Но я никогда не заявлял, что владею инструментом, пока не использовал его для создания чего-либо. Примерно в это же время появилось внешнее вдохновение — мне нужен был способ удаленного управления термостатом в отдельно стоящей мастерской. Нагреватель для моей мастерской — это простое двухпроводное управление — не такое сложное, как домашняя печь. Google Nest — это излишество, я программировал для Arduino. и устройств Raspberry Pi в прошлом, поэтому родился этот проект.
Разрабатывая архитектуру своего нового проекта, я определился со следующим первоначальным объемом:
- Меня беспокоит только нагрев, так что единый элемент управления и упрощенная логика для включения или выключения нагрева.
- В качестве основной платформы управления легко выбрать Raspberry Pi. Он работает под управлением ОС Unix, поддерживает сеть Wi-Fi и имеет легкий доступ к физическим устройствам, необходимым для измерения температуры, и реле для работы в качестве термостата.
- Я бы использовал Rust в качестве языка разработки и воспользовался следующими возможностями Rust:
- Кросс-компиляция в собственный исполняемый файл (процессор ARM).
- Используйте инфраструктуру Actix-Web для предоставления интерфейсов REST для удаленной настройки термостата и получения текущей температуры.
- Используйте среду выполнения Tokio для многопоточного приложения, которое может считывать температуру, принимать решения о включении или выключении термостата, получать команды для настройки термостата и отправлять данные извне.
- Получить программный доступ к физическим устройствам на Raspberry Pi для считывания температуры и управления реле для включения или выключения нагревателя.
- Я хотел, чтобы снаружи было видно, как работает термостат. Я решил отправлять данные в облако, а не хранить их на устройстве, чтобы внешний «наблюдатель» мог отправить сигнал тревоги, если что-то работает неправильно. Я бы не хотел, чтобы термостат не включался, когда он должен (замораживание — это плохо), или оставался включенным слишком долго (100 градусов — это тоже плохо и потенциальная опасность возгорания).
- Я выбрал REST-интерфейс для управления термостатом, чтобы потом было легко что-то к нему подключить. Я мог бы сделать приложение Flutter для своего телефона (еще много нового!) или веб-интерфейс.
- Я решил обеспечить безопасность с помощью физического доступа к сети и брандмауэров, а не реализовывать уровень безопасности в API. Я сохраняю реализацию безопасности для версии 2.0, что делает первоначальную разработку чище и проще.
- Я бы следовал основным принципам от нуля до производства при организации проекта и использовал многие из тех же внешних пакетов Rust. Мне понравился стиль кодирования и выбор, сделанный в книге, и я считаю ее справочником по передовому опыту.
Я хотел, чтобы это был хобби-проект, а не готовая к коммерческому использованию реализация. Когда я установлю это для фактического использования, у меня будет система резервного копирования, чтобы ничего плохого не случилось. В текущем состоянии проекта все работает, но я не утверждаю, что система усилена. Нужно больше тестов, прежде чем я доверю этому что-то важное.
На следующей диаграмме показана системная архитектура решения:
Подсистемы приложения следующие:
* Общие данные. В них хранится текущее состояние приложения, и доступ к ним из других подсистем осуществляется по мере необходимости. Каждая подсистема работает в независимых потоках, поэтому мы упаковываем общие данные, чтобы защитить их, когда несколько потоков пытаются прочитать/установить свои данные независимо друг от друга. * Веб-интерфейс (HTTP) — мы запускаем сервер actix-web, что позволяет использовать несколько HTTP-клиентов. Этот интерфейс обеспечивает внешний доступ к термостату, обеспечивая желаемую «беспроводную» функциональность. Эти интерфейсы позволяют установить значение термостата (желаемую минимальную температуру) и получить текущую температуру и настройку термостата. * Чтение текущей температуры — независимый поток периодически опрашивает датчик температуры. Каждый раз, когда он считывает значение температуры, он изменяет внутреннее состояние, а затем отправляет эти значения во внешнее облачное хранилище. * Установка термостата — другой независимый поток опрашивает общие данные, чтобы определить, должен ли термостат быть включен или выключен. Когда температура ниже значения термостата, включается внешнее управляющее реле, в противном случае оно отключается. Порог минимального времени включения/выключения позволяет избежать пробуксовки, поэтому мы сохраняем время смены управляющего реле в общих данных, что становится частью логики определения состояния реле. * Телеметрия — все сообщения об ошибках и трассировках проходят через уровень телеметрии и передаются на внешний сборщик для обеспечения видимости. * Облачное хранилище данных. Мы используем AWS в качестве поставщика облачных услуг и используем функцию Lambda (написанную на Rust!) для получения HTTP-сообщений от приложения и сохранения их в таблице DynamoDB для внешней обработки. Облачная база данных — это хранилище исторической информации о том, как со временем менялись настройки температуры и термостата. В конце концов, монитор этих данных предупредит нас, если что-то пойдет не так. * Пользовательский интерфейс. Нам нужен способ управления термостатом и просмотра его текущего состояния. Этот пользовательский интерфейс взаимодействует с приложением через HTTP для получения/установки данных. Он также может извлекать исторические данные из облака для отображения.
Ссылка GitHub на исходный код находится здесь. Я все еще возюсь с вещами и работаю над клиентом с графическим интерфейсом. Я планирую подробно рассказать о приложении в серии последующих сообщений — следите за обновлениями!
Оригинал