Управление подсветкой 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-ом сообщение от приложения к шлюзу.

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *