Как управлять wi-fi розеткой от Xiaomi через умные часы (на примере часов Garmin)

от автора

Вводные данные:

а) Имеются довольно старые, но до сих весьма высокотехнологичные умные часы — Garmin Fenix 6 Pro Solar, работающие на проприетарной системе компании Garmin.
б) Умные интернет-розетки от Xiaomi Smart Plug 2 Wi-Fi.

Появилась задача, а скорее просто очередное дико зудящее желание в стиле “кулибинство” — управлять такими розетками (хотя бы удаленно включать и выключать их) прямо с указанных часов.

Желание есть, начинаю изучать задачу. И решать её, как это у меня обычно происходит, нестандартным путем.

Для начала выясняю, как вообще реализовано управление данными интернет-розетками Xiaomi? Умные устройства Xiaomi преимущественно управляются через фирменное приложение Xiaomi Home, которое отлично работает, например, в OS Android. Приложение огромное по размеру, громоздкое, по сути — целый программный “комбайн” для управления огромным множеством умных устройств Xiaomi. Очень быстро становится понятно, что на часы Garmin никакого подобного приложения, или какого-либо компактного форка нет и быть не может. Слишком уж скромные программные возможности у часов Garmin при работе с таким монструозным софтом!

И поэтому я решил пойти другим путём:

  1. В моем случаи все указанные интернет-розетки у меня работают в домашней сети, за NAT роутера. Поэтому для начала на примере одной такой розетки выясняю, какой у неё локальный IP-адрес? Проще всего это сделать из установленного прямо из работающего приложения Xiaomi Home в свойствах розетки. Либо Вы можете просто просканировать свою домашнюю сеть и увидеть среди других устройств IP адрес этой розетки, ориентируясь на разработчика устройства Beijing Xiaomi Mobile Software Co., Ltd. Например, в моем случае IP адрес розетки — 192.168.8.199. И работает розетка на порту 54321 по протоколу UDP.

  2. Так как в моем случае у меня есть полный доступ к моему роутеру, то я подключаюсь к нему по ssh и в консоли настраиваю форвардинг:

iptables -t nat -I POSTROUTING -p udp -d 192.168.8.199 —dport 54321 -j MASQUERADE

где 192.168.8.199 — текущий локальный адрес розетки.

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

Дополнительно в роутере нужно обязательно сделать проброс UDP порта 54321 (снаружи внутрь на локальный IP розетки, в данном случае на 192.168.8.199).

Дальнейшие “ходы” в решении задачи я решил проделать, используя на одном из своих удаленных win-серверов, сначала установив там Node.js. Не спрашивайте, почему win-сервер и Node.js. Использовал, что было под рукой и что имеет “белый” IP, работая по схеме 24/7. Да и под Node.js у меня работают и другие проекты. Разумеется, всё можно проделать и под Linux.

Что дальше:

  1. Cоздадим на диске сервера, например, папку с именем, “c:\Xiaomi”.

  2. Далее, находясь в этой папке, запустим (в моем случае) консоль Windows и скомандуем:

npm install express npm install miio npm install miio-api

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

Тем самым мы добавим программную возможность управлять через среду Node.js, путем веб-редиректов, своими розетками Xiaomi. После установки модулей дополнительно выполним команду:

npm audit fix —force

чтобы убедиться, что очевидных и потенциальных “дыр” в работе Node.js сейчас нет.

3. Затем необходимо создать и скопировать в папку Xiaomi скрипт с именем, например, index.js и с таким содержимым (я оставил комментарии в коде для понимания, что и к чему):

const express = require(‘express’); const miio = require(‘miio-api’); // Используем miio-api const app = express();

const deviceIp = ‘111.111.111.111’; const deviceToken = ‘1855c4f24c7fb6592e348903f78e4c164’;

async function setPlugState(state) { const device = await miio.device({ address: deviceIp, token: deviceToken }); // Команда для Smart Plug 2 (siid 2, piid 1) const res = await device.call(‘set_properties’, [ { did: ‘any’, siid: 2, piid: 1, value: state } ]); return res; }

app.get(‘/on’, async (req, res) => { try { await setPlugState(true); res.send(‘Розетка ВКЛЮЧЕНА’); } catch (err) { res.status(500).send(‘Ошибка: ’ + err.message); } });

app.get(‘/off’, async (req, res) => { try { await setPlugState(false); res.send(‘Розетка ВЫКЛЮЧЕНА’); } catch (err) { res.status(500).send(‘Ошибка: ’ + err.message); } });

app.listen(3000, () => console.log(‘Сервер: http://localhost:3000/on’));

В этом скрипте надо отредактировать всего две строки:

const deviceIp = ‘111.111.111.111’; const deviceToken = ‘1855c4f24c7fb6592e348903f78e4c164’;

в первой строке надо вписать внешний IP своего роутера (в моем случае это домашний роутер), к которому подключена розетка, а во второй — 32-значный токен розетки.

Как получить такой токен? Всё очень просто! Погуглите по словам:

“Xiaomi-cloud-tokens-extractor github”

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

Дальше получаете через этот экстрактор токен своей розетки (-ок). На github-странице экстрактора очень просто и понятно описано, как это сделать буквально в несколько кликов.

4. Отредактировав скрипт с правильными значениями IP и токена, нам теперь надо запустить на win-сервере (в моем случае), на локалхосте на порту 3000 (порт можно поменять в коде скрипта) небольшой веб-сервер для ретрансляции запросов к розетке.

Для этого сначала в консоли, запущенной через Пуск-Выполнить-cmd, командуем:

ssh-keygen -t ed25519

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

Затем в другой запущенной консоли воспользуемся простой возможностью сделать ssh-проброс с одновременным получением бесплатного временного домена через онлайн-сервис, например, через популярный сервис srv.us:

ssh srv.us -R 1:127.0.0.1:3000

Эта команда позволит подключаться встроенному ssh-клиенту вашей OS к специальному онлайн-сервису и получать временный домен для проброса к запущенному на локалхосте Вашего сервера, тому самому веб-серверу для трансляции веб-запросов к розетке Xiaomi, работающей, в свою очередь, в Вашей домашней сети за NAT.

Полученный домен в ссылке будет примерно такого вида:

https://esnivup33tkale57bmnamz6l7m.srv.us/

(у Вас ссылка и домен будут другими!)

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

https://esnivup33tkale57bmnamz6l7m.srv.us/off

(отключить розетку)

https://esnivup33tkale57bmnamz6l7m.srv.us/on

(включить розетку)

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

Но, напомню, что я хотел это делать через часы Garmin!

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

Как Вы уже догадались, останется просто создать в часах такие “кнопки-ссылки” на On и Off для конкретной розетки, а сами часы, конечно же, как в случае со всеми умными часами, должны быть подключены к любому интернету через сопряженный с часами телефон.

В моем случае я просто установил на часы Garmin виджет “MyHomeControl” (легко находится на сайте приложений Garmin), в котором добавил две “кнопки-ссылки” со ссылками, полученными выше. Теперь можно просто запускать на часах этот виджет MyHomeControl и всего парой кнопок-ссылок выключать и включать розетку Xiaomi.

Конечно, я прекрасно понимаю, что выше я сделал всё, мягко говоря, “на коленке”, примитивно и, возможно не совсем классно с точки зрения безопасности. Но своей статьёй я хотел описать лишь метод, а промежуточные шаги Вы может проделать совершенно другие, на Ваш вкус.

Спасибо за внимание, надеюсь, что моя статья окажется для Вас полезной.

ссылка на оригинал статьи https://habr.com/ru/articles/1043286/