Управление подсветкой Xiaomi Gateway (часть вторая)
И снова возвращаясь к этой теме и к своим хотелкам, с учетом созданного транслятора сообщений в MQTT, обновил flow Node-Red и добавил проброс в HomeKit
Конечно это не столь изящное решение, как с остальным светом, да еще и требующее отдельной esp, но пока оно мне нравится и работает, на удивление, именно так, как ожидалось.
Как обычно, по нодам по порядку:
Get Heartbeat Message (MQTT In)
Задача этой ноды – быть подписанной на топик MQTT и получать информацию об обновлении состояния и текущем сессионном токене
Write Flow Data (function)
В этой ноде происходит обработка пришедшего сообщения и в зависимости от его типа – выставление параметров и запись во flow переменные
Код этой функции в читаемом виде:
var data = "";
var CurrentLightMode = "";
if(msg.payload.cmd === "heartbeat" && msg.payload.hasOwnProperty('token')) {
flow.set('XiaomiCurrentToken', msg.payload.token);
}
else if (msg.payload.cmd === "report") {
data = JSON.parse(msg.payload.data);
if(data.hasOwnProperty('rgb')) {
if(data.rgb > 0) {
flow.set('CurrentLightMode', 'ON');
} else {
flow.set('CurrentLightMode', 'OFF');
}
}
return;
}
else if (msg.payload.cmd === "read_ack") {
data = JSON.parse(msg.payload.data);
if(data.hasOwnProperty('rgb')) {
if(data.rgb > 0) {
flow.set('CurrentLightMode', 'ON');
CurrentLightMode = "ON"
} else {
flow.set('CurrentLightMode', 'OFF');
CurrentLightMode = "OFF";
}
var TargetLightMode = flow.get('TargetLightMode') || null;
if(TargetLightMode && (TargetLightMode != CurrentLightMode)) {
msg.payload = TargetLightMode;
node.send(msg);
} else {
flow.set('TargetLightMode', CurrentLightMode);
}
}
}
Encrypt Token and Create Message (function)
Шифруем токен своим ключом и формирую сообщение для отправки на шлюз. Цвет и яркость тут заданы жестко, управлять ими откуда-либо я не планирую, исходя из основного предназначения подсветки.
Тут логика такая: если я знаю текущее состояние света и пришло сообщение на смену его на противоположное – то так и делать, если же не знаю – то просто наудачу послать команду в шлюз и записать желаемое состояние в переменную.
Читаемый код функции:
var crypto = global.get('cryptoModule');
var iv = Buffer.from([0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28, 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58, 0x56, 0x2e]);
var newmsg = {};
var lastToken = flow.get('XiaomiCurrentToken') || null;
if(lastToken) {
var password = 'КЛЮЧ ШЛЮЗА';
var cipher = crypto.createCipheriv('aes-128-cbc', password, iv);
var key = cipher.update(lastToken, "ascii", "hex");
cipher.final('hex');
var mode = flow.get('CurrentLightMode') || "UNKNOWN";
if(mode === "OFF" && msg.payload === "ON") {
newmsg.payload = '{"cmd":"write","model":"gateway","sid":"4cf8cf2ee25","data":"{\\"key\\":\\"' + key + '\\",\\"rgb\\":838795264}"}';
flow.set('TargetLightMode', 'ON');
return newmsg;
} else if (mode === "ON" && msg.payload === "OFF") {
newmsg.payload = '{"cmd":"write","model":"gateway","sid":"4cf8cf2ee25","data":"{\\"key\\":\\"' + key + '\\",\\"rgb\\":0}"}';
flow.set('TargetLightMode', 'OFF');
return newmsg;
} else if (msg.payload === "ON") {
newmsg.payload = '{"cmd":"write","model":"gateway","sid":"4cf8cf2ee25","data":"{\\"key\\":\\"' + key + '\\",\\"rgb\\":838795264}"}';
flow.set('TargetLightMode', 'ON');
return(newmsg);
} else {
newmsg.payload = '{"cmd":"write","model":"gateway","sid":"4cf8cf2ee25","data":"{\\"key\\":\\"' + key + '\\",\\"rgb\\":0}"}';
flow.set('TargetLightMode', 'OFF');
return(newmsg);
}
}
UDP Out
Просто отправка сообщения на шлюз. На этот раз с произвольного порта, его ответ меня не интересует, к тому же он все равно отметит изменение состояния по мультикасту и esp его поймает.
To HomeKit (function)
Стандартное превращение сообщений в понятный для HomeKit формат. Ориентируюсь на желаемое состояние света, а не на текущее. Потому что в случае если все нормально – они синхронизируются.
Bathroom Night Light (HomeKit)
Стандартная нода лампочки, без каких либо свойств, поскольку ни цвет, ни яркость менять не планируется.
From HomeKit (function)
Ну и обратная трансформация сообщений из ноды HomeKit в нужные для работы всего этого дела
Что бы все это дело нормально обменивалось сообщениями и при этом их связи не выглядели как кошмар любителя спагетти, используются ноды Link In и Link Out.
К ноде To HomeKit приходят сообщения от Get HeartBeat Message, поскольку с приходящим сообщением я не работаю никак, зато в этом случае гарантированно раз в десять секунд обновляется состояние света в HomeKit.
От ноды From HomeKit сообщения уходят в ноду Encrypt Token… и соответственно далее отправляются на шлюз.
Если кто-то захочет повторить такую схему у себя (в чем я очень сильно сомневаюсь), то цвет и яркость задаются в функции Encrypt Token and Create Message – вот это число в моем случае: 838795264 – красный на 50 процентах яркости. Сразу скажу честно, что как его посчитать я не знаю и просто сграбил tcpdump-ом сообщение от приложения к шлюзу.
Если не придумаю, как эту задачу в моих условиях можно реализовать другим способом – данный способ буду считать окончательным и рабочим.
Один ответ к «Управление подсветкой Xiaomi Gateway (часть вторая)»