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

  • Имеются довольно старые, но до сих весьма высокотехнологичные умные часы — 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. И работает розетка на порту 54 321 по протоколу 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:\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.

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

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

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

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

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

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

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

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

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