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

Перевод Как я превратил свой стол с регулировкой высоты в стол с Интернетом вещей

В этой статье я покажу, как я превратил свой стол с ручной регулировкой высоты в автоматизированный стол с Интернетом вещей. Я расскажу, как подобрать размеры и запустить моторы, а также как подключить ваше устройство IoT к Google при помощи Heroku в качестве публичного интерфейса.

Если коротко, у этого проекта две особенности. Первое: стол подключается из Google Smart Home к Heroku с помощью голосовых команд, и второе: Heroku и собственно стол общаются по протоколу Интернета вещей MQTT. MQTT хорошее решение для Интернета вещей, а также для преодоления некоторых других препятствий, с которыми нам придётся столкнуться.

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

Тот самый столик


Аппаратная часть


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

Важность крутящего момента


Заказав нужные привод и ремень, я начал искать на Amazon мотор с высоким крутящим моментом. И о, чудо! я нашёл много подходящих двигателей! Или мне так показалось Купив маленький моторчик, около месяца я ждал его прибытия из Китая. Я был так взволнован, когда моторчик, наконец, приехал! Не мог дождаться выходных, чтобы, наконец, собрать всё воедино и получить мой моторизованный стол.

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

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



Слева на фото мотор и ремень. Вверху справа прикреплённый к столу мотор (позже вы увидите больше о происходящем). Внизу справа мотор в положении на столе.

Подходящий мотор


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

$T = F * r$


Крутящий момент это сила, умноженная на длину плеча рычага.

Что ж, плечо рычага у меня было (это рукоятка стола), нужно было только рассчитать силу, которая легко повернула бы плечо рычага. Я нагрузил стол, привязав к ручке кувшин для молока и постепенно добавлял в кувшин воду, пока рычаг не начал вращаться. Повернув ручку кверху с наполненным кувшином я убедился, что вес легко поворачивает ручку. Я выяснил, что длина плеча рычага составляет 11 см, а требуемая сила 4 фунта. Подставив эти цифры в формулу, я выяснил, что мотор должен выдавать крутящий момент не менее 19,95 кг/см. И начал искать его.

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

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


Два верхних фото полностью установленные на стол моторы. Два нижних фото - интегрированный стержень, с помощью моторов проходящий по длине стола.

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

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

Обороты важны. Окончательная версия


Наконец я понял, что всё сводится к двум вещам: крутящему моменту и оборотам. Нужно было найти мотор с достаточным количеством оборотов при уже известном крутящем моменте.

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

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


Последний мотор сам по себе слева, а установленный справа. Немного аппаратного обеспечения и много программного обеспечения.

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

Bluetooth


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

Итак, теперь я приобрёл плату контроллера мотора, плату для Bluetooth Nordic NRF52, сенсоры для измерения расстояния и начал возиться с прошивкой контроллера.

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

В качестве краткого введения: ESP32 написана на C++ с помощью библиотек Arduino для взаимодействия с приложением BLE Terminal на телефоне. Установка и конфигурирование BLE довольно сложны. Для начала нужно создать все характеристики для значений, которые вы хотели бы контролировать через BLE. Думайте о характеристике, как о переменной в вашем коде. BLE оборачивает переменную во множество обработчиков для получения и установки значения этой переменной.

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

Для регулировки высоты столешница имеет определяющий текущую высоту встроенный в нижнюю часть сенсор TFMini-S LiDAR. Это забавный сенсор: он называется LiDAR, хотя на самом деле это лазер. Он использует оптику и светодиод, чтобы определить время полёта ИК-излучения. Так или иначе, сенсор определяет высоту стола. Затем контрольная плата определяет разницу между текущей высотой и запрашиваемой высотой и запускает мотор, который вращается в нужном направлении. Некоторые основные части кода приведены ниже, но вы можете увидеть весь файл здесь.

void setup(){   Serial.begin(115200);   Serial2.begin(TFMINIS_BAUDRATE);   EEPROM.begin(3); // used for saving the height presets between reboots   tfminis.begin(&Serial2);   tfminis.setFrameRate(0);   ledcSetup(UP_PWM_CHANNEL, PWM_FREQUENCY, PWM_RESOLUTION);   ledcAttachPin(UP_PWM_PIN, UP_PWM_CHANNEL);   ledcSetup(DOWN_PWM_CHANNEL, PWM_FREQUENCY, PWM_RESOLUTION);   ledcAttachPin(DOWN_PWM_PIN, DOWN_PWM_CHANNEL);   state_machine = new StateMachine();   state_machine->begin(*t_desk_height, UP_PWM_CHANNEL, DOWN_PWM_CHANNEL);   BLEDevice::init("ESP32_Desk");  ...   BLEServer *p_server = BLEDevice::createServer();   BLEService *p_service = p_server->createService(BLEUUID(SERVICE_UUID), 20);   /* ------------------- SET HEIGHT TO PRESET CHARACTERISTIC -------------------------------------- */   BLECharacteristic *p_set_height_to_preset_characteristic = p_service->createCharacteristic(...);   p_set_height_to_preset_characteristic->setCallbacks(new SetHeightToPresetCallbacks());   /* ------------------- MOVE DESK UP CHARACTERISTIC ---------------------------------------------- */   BLECharacteristic *p_move_desk_up_characteristic = p_service->createCharacteristic(...);   p_move_desk_up_characteristic->setCallbacks(new MoveDeskUpCallbacks());   /* ------------------- MOVE DESK UP CHARACTERISTIC ---------------------------------------------- */   BLECharacteristic *p_move_desk_down_characteristic = p_service->createCharacteristic(...);   p_move_desk_down_characteristic->setCallbacks(new MoveDeskDownCallbacks());   /* ------------------- GET/SET HEIGHT 1 CHARACTERISTIC ------------------------------------------ */   BLECharacteristic *p_get_height_1_characteristic = p_service->createCharacteristic(...);   p_get_height_1_characteristic->setValue(state_machine->getHeightPreset1(), 1);   BLECharacteristic *p_save_current_height_as_height_1_characteristic = p_service->createCharacteristic(...);   p_save_current_height_as_height_1_characteristic->setCallbacks(new SaveCurrentHeightAsHeight1Callbacks());   /* ------------------- GET/SET HEIGHT 2 CHARACTERISTIC ------------------------------------------ */  ...   /* ------------------- GET/SET HEIGHT 3 CHARACTERISTIC ------------------------------------------ */  ...   /* ------------------- END CHARACTERISTIC DEFINITIONS ------------------------------------------ */   p_service->start();   BLEAdvertising *p_advertising = p_server->getAdvertising();   p_advertising->start();   xTaskCreate(       updateDeskHeight,     // Function that should be called       "Update Desk Height", // Name of the task (for debugging)       1024,                 // Stack size       NULL,                 // Parameter to pass       5,                    // Task priority       NULL                  // Task handle   );}

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

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

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


Голый интерфейс bluetooth Всё, что оставалось на данный момент, научиться писать приложения под iOS

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

Кроме крутости и добавления нового устройства к списку Google Assistant отпала необходимость писать приложение под iOS, чтобы управлять столом. И больше не нужно было доставать телефон, чтобы отрегулировать высоту. Ещё одна маленькая победа!

Добавление Интернета вещей


Теперь поговорим об апгрейде стола до управления голосом через Google Smart Home и как подружить его с Wi-Fi.

Добавить Wi-Fi было достаточно просто. Я заменил микроконтроллер Nordic NRF52 на ESP32 со встроенным WiFi. Большая часть софта была переносимой, потому что была написана на C++, а оба устройства могли программироваться с помощью Platform.IO и библиотек Arduino, включая tfmini-s, написанную мной для измерения текущей высоты стола.

Ниже показана архитектура системы взаимодействия стола с Google Smart Home. Давайте поговорим о взаимодействии между мной и Гуглом.



Итак, Bluetooth был включён. Пришло время выяснить, как взаимодействовать с Google Smart Home. Эта технология контролировала дом с помощью Smart Home Actions. В её действиях интересно то, что сервис действует как сервер OAuth2, а не как клиент. Большая часть проделанной с сервером работы была связана с реализацией приложения OAuth2 Node.js Express, которое добирается до Heroku и взаимодействует как прокси между Google и моим столом.

Мне повезло: была достойная реализация сервера с помощью двух библиотек. Первая библиотека node-oauth2-server, была найдена здесь. Вторая библиотека express-oauth-server для подключения Express была найдена здесь.

const { Pool } = require("pg");const crypto = require("crypto");const pool = new Pool({   connectionString: process.env.DATABASE_URL});module.exports.pool = pool;module.exports.getAccessToken = (bearerToken) => {...};module.exports.getClient = (clientId, clientSecret) => {...};module.exports.getRefreshToken = (bearerToken) => {...};module.exports.getUser = (email, password) => {...};module.exports.getUserFromAccessToken = (token) => {...};module.exports.getDevicesFromUserId = (userId) => {...};module.exports.getDevicesByUserIdAndIds = (userId, deviceIds) => {...};module.exports.setDeviceHeight = (userId, deviceId, newCurrentHeight) => {...};module.exports.createUser = (email, password) => {...};module.exports.saveToken = (token, client, user) => {...};module.exports.saveAuthorizationCode = (code, client, user) => {...};module.exports.getAuthorizationCode = (code) => {...};module.exports.revokeAuthorizationCode = (code) => {...};module.exports.revokeToken = (code) => {...};

Далее идет настройка самого приложения Express. Ниже приведены конечные точки, необходимые для сервера OAuth, но вы можете прочитать полный файл здесь.

const express = require("express");const OAuth2Server = require("express-oauth-server");const bodyParser = require("body-parser");const cookieParser = require("cookie-parser");const flash = require("express-flash-2");const session = require("express-session");const pgSession = require("connect-pg-simple")(session);const morgan = require("morgan");const { google_actions_app } = require("./google_actions");const model = require("./model");const { getVariablesForAuthorization, getQueryStringForLogin } = require("./util");const port = process.env.PORT || 3000;// Create an Express application.const app = express();app.set("view engine", "pug");app.use(morgan("dev"));// Add OAuth server.app.oauth = new OAuth2Server({   model,   debug: true,});// Add body parser.app.use(bodyParser.urlencoded({ extended: false }));app.use(bodyParser.json());app.use(express.static("public"));// initialize cookie-parser to allow us access the cookies stored in the browser.app.use(cookieParser(process.env.APP_KEY));// initialize express-session to allow us track the logged-in user across sessions.app.use(session({...}));app.use(flash());// This middleware will check if user's cookie is still saved in browser and user is not set, then automatically log the user out.// This usually happens when you stop your express server after login, your cookie still remains saved in the browser.app.use((req, res, next) => {...});// Post token.app.post("/oauth/token", app.oauth.token());// Get authorization.app.get("/oauth/authorize", (req, res, next) => {...}, app.oauth.authorize({...}));// Post authorization.app.post("/oauth/authorize", function (req, res) {...});app.get("/log-in", (req, res) => {...});app.post("/log-in", async (req, res) => {...});app.get("/log-out", (req, res) => {...});app.get("/sign-up", async (req, res) => {...});app.post("/sign-up", async (req, res) => {...});app.post("/gaction/fulfillment", app.oauth.authenticate(), google_actions_app);app.get('/healthz', ((req, res) => {...}));app.listen(port, () => {   console.log(`Example app listening at port ${port}`);});

Кода довольно много, но я объясню основные моменты. Два используемых для сервера маршрута OAuth2, это /oauth/token и /oauth/authorize. Они применяются для получения нового токена или обновления истекших токенов. Далее нужно заставить сервер реагировать на действие Google. Вы заметите, что конечная точка /gaction/fulfillment указывает на объект google_actions_app.

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

Конечная точка /gaction/fulfillment использует промежуточное ПО под названием app.oauth.authenticate(), тяжёлая работа по обеспечению работы сервера OAuth2 была направлена на то, чтобы работало это промежуточное ПО. Оно проверяет, что токен-носитель, предоставленный нам Google, ссылается на существующего пользователя и не истёк. Далее маршрут отправляет запрос и ответ объекту google_actions_app.

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

const { smarthome } = require('actions-on-google');const mqtt = require('mqtt');const mqtt_client = mqtt.connect(process.env.CLOUDMQTT_URL);const model = require('./model');const { getTokenFromHeader } = require('./util');mqtt_client.on('connect', () => {   console.log('Connected to mqtt');});const updateHeight = {   "preset one": (deviceId) => {       mqtt_client.publish(`/esp32_iot_desk/${deviceId}/command`, "1");   },   "preset two": (deviceId) => {       mqtt_client.publish(`/esp32_iot_desk/${deviceId}/command`, "2");   },   "preset three": (deviceId) => {       mqtt_client.publish(`/esp32_iot_desk/${deviceId}/command`, "3");   },};const google_actions_app = smarthome({...});google_actions_app.onSync(async (body, headers) => {...});google_actions_app.onQuery(async (body, headers) => {...});google_actions_app.onExecute(async (body, headers) => {...});module.exports = { google_actions_app };

Когда вы добавите интеллектуальное действие в свой аккаунт Google, Google выполнит запрос на синхронизацию. Этот запрос позволяет узнать, какие устройства доступны из аккаунта. Далее происходит опрашивающий запрос: Google запрашивает ваши устройства, чтобы определить их текущее состояние.

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

Особенности (trait) устройства Google Smart Home


Google использует особенности устройства для предоставления элементов пользовательского интерфейса управления вашими устройствами в Google, а также для создания коммуникационных шаблонов голосового управления. Некоторые из особенностей включают в себя следующие настройки: ColorSetting, Modes, OnOff, and StartStop. Мне потребовалось некоторое время, чтобы решить, какая особенность будет лучше всего работать в моём приложения, но позже я выбрал режимы.

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

Проект в деле


Наконец, Google Smart Home и мой компьютер начали общаться. До этого для локального запуска сервера Express я использовал ngrok. Теперь, когда мой сервер наконец заработал достаточно хорошо, пришло время сделать его доступным для Google в любое время. Значит, нужно было разместить приложение на Heroku это поставщик PaaS, упрощающий развёртывание и управление приложениями.

Одно из главных преимуществ Heroku режим дополнений. С дополнениями очень просто добавить CloudMQTT и сервер Postgres для приложения. Ещё одно преимущество использования Heroku простота сборки и развёртывания. Heroku автоматически определяет, какой код вы используете, и создаёт/развёртывает его для вас. Вы можете найти более подробную информацию об этом, прочитав о Heroku Buildpacks. В моём случае всякий раз, когда я отправляю код в git remote Heroku, он устанавливает все мои пакеты, удаляет все зависимости разработки и развёртывает приложение, и это всё простой командой git push heroku main.

Всего в несколько кликов CloudMQTT и Postgres стали доступны моему приложению, и мне нужно было использовать только несколько переменных среды, чтобы интегрировать эти сервисы с моим приложением. Heroku не потребовал денег. Однако CloudMQTT сторонним дополнение за $5 в месяц.

Я считаю, что необходимость в Postgres не нуждается в комментариях, но CloudMQTT заслуживает больше внимания.

Из Интернета в частную сеть. Сложный способ


Есть несколько способов предоставить доступ к приложению или, в моём случае, устройству Интернета вещей. Первый открыть порт в моей домашней сети, чтобы вывести устройство в Интернет. В этом случае моё приложение Heroku Express отправит запрос на моё устройство, используя публичный IP-адрес. Это потребовало бы от меня иметь публичный статический IP-адрес, а также статический IP-адрес для ESP32. ESP32 также должен был бы действовать как HTTP-сервер и всё время слушать инструкции от Heroku. Это большие накладные расходы для устройства, получающего инструкции несколько раз в день.

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

Внутри дырокола происходит многое, и я не до конца понимаю происходящее. Однако, если вам интересно, есть несколько интересных статей, объясняющих больше. Вот две статьи, которые я прочитал, чтобы лучше понять дырокол: Википедия и статья из MIT, написанная Брайаном Фордом и другими.

Из Интернета в частную сеть через IoT


Я не был очень доволен этими решениями. Я подключил много смарт-устройств в дом, и мне никогда не приходилось открывать порт на маршрутизаторе, так что переадресации портов не было. Кроме того, пробивка дыр кажется гораздо более сложной, чем то, что я ищу, и лучше подходит для сетей P2P. В результате дальнейших исследований я обнаружил MQTT и узнал, что это протокол для IoT. Он обладает некоторыми преимуществами, такими как низкое энергопотребление, настраиваемая отказоустойчивость, и не требует переадресации портов. MQTT протокол типа издатель/подписчик, это означает, что стол подписчик определённого топика, а приложение Heroku издатель этого топика.

Таким образом, Google связывается с Heroku, этот запрос анализируется, чтобы определить запрошенное устройство и его новое состояние или режим. Затем приложение Heroku публикует сообщение на сервере CloudMQTT, развёрнутом как надстройка на Heroku, с указанием столу перейти к новой предустановке. Наконец, стол подписывается на топик и получает сообщение, опубликованное приложением Heroku, наконец, стол настраивает свою высоту в соответствии с запросом! В файле googleactionsapp вы заметите, что есть функция updateHeight, которая публикует один номер в топике MQTT для определённого идентификатора устройства. Вот так приложение Heroku публикует в MQTT запрос на перемещение стола.

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

void setup(){ Serial.begin(115200);... tfminis.begin(&Serial2); tfminis.setFrameRate(0);... state_machine = new StateMachine(); state_machine->begin(*t_desk_height, UP_PWM_CHANNEL, DOWN_PWM_CHANNEL); setup_wifi(); client.setServer(MQTT_SERVER_DOMAIN, MQTT_SERVER_PORT); client.setCallback(callback);...}

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

void callback(char *topic, byte *message, unsigned int length){ ... String messageTemp; for (int i = 0; i < length; i++) {   messageTemp += (char)message[i]; } if (messageTemp == "1") {   state_machine->requestStateChange(ADJUST_TO_PRESET_1_HEIGHT_STATE); } if (messageTemp == "2") {   state_machine->requestStateChange(ADJUST_TO_PRESET_2_HEIGHT_STATE); } if (messageTemp == "3") {   state_machine->requestStateChange(ADJUST_TO_PRESET_3_HEIGHT_STATE); }...}

Конечный автомат регистрирует изменение состояния, полученное в теме MQTT. Затем он в основном цикле обрабатывает новое состояние.

void loop(){ if (!client.connected()) {   reconnect(); } client.loop(); state_machine->processCurrentState();}

Основной цикл выполняет несколько задач: во-первых, он повторно подключается к серверу MQTT, если еще не подключён. Затем обрабатывает все данные, полученные через топик MQTT. Наконец, код отрабатывает, перемещая столешницу в нужное место, запрошенное в топике MQTT.

Вот и всё! Стол полностью управляется голосом и обменивается данными с Google для получения команд!

Последние заметки


Последняя конечная точка, о которой я не упоминал, конечная точка / healthz. Это связано с тем, что Google ожидает, довольно быстрого ответа, и загрузка приложения Heroku при каждом запросе в моём случае не работает. Я установил службу ping для проверки связи с конечной точкой /healthz каждую минуту, чтобы служба оставалась работоспособной и была готова ответить. Если вы планируете сделать что-то подобное, помните, что на это будут израсходованы все бесплатные часы на стенде. Сейчас всё нормально: это единственное используемое на Heroku приложение. Кроме того, за 7 долларов в месяц вы можете перейти на тарифный план Herokus Hobby с поддержкой постоянной работы приложения.

Создание устройства IoT связано с большими накладными расходами в начале. Я сконструировал оборудование, построил схему управления, настроил сервер MQTT, написал сервер Express OAuth2 и научился взаимодействовать с Google Smart Home через действия. Первоначальные накладные расходы были огромными, но я чувствую, что многого добился! Не говоря уже о том, что сервер MQTT, сервер приложений Express OAuth2 и Google Smart Home Actions можно использовать для другого проекта. Умные дома мне интересны, и я могу попытаться расширить свой репертуар IoT-устройств, включив в него датчики, отслеживающие происходящее вокруг моего дома и сообщающее об этом через MQTT. Датчики для мониторинга почвы, температуры и датчики света будет очень интересно мониторить и анализировать.

Что дальше?


Высота столешницы сейчас измеряется в лучшем случае ненадёжно. Я использую в целом работающим инфракрасным датчиком расстояния TFMini-S. Замечено, что высота стола немного меняется в течение дня, когда меняется окружающее освещение в комнате. Я заказал датчик угла поворота, чтобы подсчитать обороты стержня, проходящего через стол. Это должно дать мне движения точнее в любое время дня. У меня также есть доступ к серверу, который я размещаю в подвале. На нём я могу исследовать собственный сервер Mosquitto MQTT, Node-RED и Express-приложения OAuth2, если захочу хостить что-то сам. Наконец, сейчас вся электроника лежит прямо на моём столе. Я планирую организовать устройства так, чтобы все было красиво и аккуратно!


image



Источник: habr.com
К списку статей
Опубликовано: 12.12.2020 16:04:40
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Блог компании skillfactory

C++

Интернет вещей

Diy или сделай сам

Лайфхаки для гиков

Skillfactory

Diy

Самоделка

Крафт

Категории

Последние комментарии

  • Имя: Макс
    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