Подключаем Xiaomi Mi Smart LED к Умному Дому

Автор: | 05.12.2017

Подключаем лампу Xiaomi Mi Smart LED к Умному Дому

 

 

 

 

 

 

 

Два скрипта и лампа под контролем 🙂

var dgram = require('dgram');
var s = dgram.createSocket('udp4');
var debug = true;

const MULTICAST_IP = '239.255.255.250';
const s_dataset = 'javascript.0.Yeelight.Bulb';
const s_id = '.id';
const s_address = '.Location';
const s_bright = '.bright';
const s_hue = '.hue';
const s_colorMode = '.color_mode';
const s_rgb = '.rgb';
const s_sat = '.sat';
const s_power = '.power';
const s_ct = '.ct';
const s_name = '.name';
const s_group = '.group';


s.bind(1982, function() {
   s.addMembership(MULTICAST_IP);
   if (debug) console.log("listening on all addresses");
});

s.on("message", function (msg, rinfo) {
   if (debug) console.log('Broadcast empfangen: ' + msg);
   if (msg.indexOf('yeelight') < 0) {
       if (debug) console.log("Kein Yeelight Broadcast");
       return;
   }
   var bulbID = extractValue('id: ', msg);
   var i = 1;
   var unknownBulb = true;

   //wenn Lampe vorhanden, dann Werte aktualisieren
   while (getObject(s_dataset + i + s_id)) {
      if (getState(s_dataset + i + s_id).val == bulbID) {
         setState(s_dataset + i + s_address, extractValue('Location: ', msg), false);
         setState(s_dataset + i + s_bright, parseInt(extractValue('bright: ', msg)), true);
         setState(s_dataset + i + s_hue, parseInt(extractValue('hue: ', msg)), true);
         setState(s_dataset + i + s_colorMode, parseInt(extractValue('color_mode: ', msg)), true);
         setState(s_dataset + i + s_rgb, '#' + parseInt(extractValue('rgb: ', msg)).toString(16), true); //Wert umgewandelt von Dec zu Hex damit Colorpicker Widget einfacher zu nutzen ist
         setState(s_dataset + i + s_sat, parseInt(extractValue('sat: ', msg)), true);
         setState(s_dataset + i + s_ct, parseInt(extractValue('ct: ', msg)), true);
         setState(s_dataset + i + s_power, extractValue('power: ', msg), true);
         unknownBulb = false;
         if (debug) console.log('Werte für Lampe ' + i + ' aktualisiert');
         break;
      }
      i++;
      //Notaus
      if (i >= 100) {
         if (debug) console.log('zu viele Schleifendurchläufe');
         break;
      }
   }
   //wenn Lampe nicht gefunden, dann neue Lampe erstellen
   if (unknownBulb) {
      if (debug) console.log('neue Lampe wird erstellt');
      createNewBulb(i, msg);  
   }
});

function createNewBulb(i, msg) {
   createState(s_dataset + i + s_id, extractValue('id: ', msg), {read: true, write: true, desc: "unique ID der Yeelight Lampe", type: "string", def: ""});
   createState(s_dataset + i + s_address, extractValue('Location: ', msg), {read: true, write: true, desc: "URL der Yeelight Lampe", type: "string", def: ""});
    createState(s_dataset + i + s_bright, parseInt(extractValue('bright: ', msg)), {read: true, write: true, desc: "Helligkeit", type: "number", min: 1, max: 100, def: 1, unit: "%"});
   createState(s_dataset + i + s_hue, parseInt(extractValue('hue: ', msg)), {read: true, write: true, desc: "HSV Farbwert", type: "number", min: 0, max: 359, def: 1, unit: ""});
   createState(s_dataset + i + s_colorMode, parseInt(extractValue('color_mode: ', msg)), {read: true, write: true, desc: "Farbwert", type: "number", min: 1, max: 3, def: 1, unit: ""});
   createState(s_dataset + i + s_rgb, '#' + parseInt(extractValue('rgb: ', msg)).toString(16), {read: true, write: true, desc: "RGB Farbwert in HEX", type: "string", def: ""});
   createState(s_dataset + i + s_sat, parseInt(extractValue('sat: ', msg)), {read: true, write: true, desc: "HSV Sättigung", type: "number", min: 1, max: 100, def: 1, unit: ""});
   createState(s_dataset + i + s_ct, parseInt(extractValue('ct: ', msg)), {read: true, write: true, desc: "Farbtemperatur weiß", type: "number", min: 1700, max: 6500, def: 5000, unit: ""});
   createState(s_dataset + i + s_power, extractValue('power: ', msg), {read: true, write: true, desc: "Zustand on/off", type: "string", def: ""});
    createState(s_dataset + i + s_name, '', {read: true, write: true, desc: "selbst vergebener Name", type: "string", def: "Yeelight"});
   createState(s_dataset + i + s_group, i, {read: true, write: true, desc: "Gruppe", type: "number", min: 1, max: 100, def: 1, unit: ""});
   if (debug) console.log('neue Lampe erstellt mit ID: ' + i);
}

function extractValue(key, message) {
    var text = message.toString('utf-8');
    var startPos = (text.indexOf(key) + key.length);
    var endPos = text.substring(startPos).indexOf('\r\n');
    return text.substr(startPos, endPos);
}

// close connection if script stopped
onStop(function (callback) {
    if (s) {
        // close connection
        s.close();
        if (debug) console.log('UDP Client gestoppt');
    }
    callback();
}, 2000 /*ms*/); 
var net = require('net');
var clients = [];
var debug = true;

const switchEffect = 'smooth'; //smooth or sudden
const switchEffectTime = 1000; // min value 30

const s_dataset = 'javascript.0.Yeelight.Bulb';
const s_bright = '.bright';
const s_hue = '.hue';
const s_colorMode = '.color_mode';
const s_rgb = '.rgb';
const s_sat = '.sat';
const s_power = '.power';
const s_ct = '.ct';
const s_name = '.name';
const s_group = '.group';
const s_location = '.Location';


function createClient(bulbID, location) {
    var port = (new RegExp(':([0-9]{1,5})')).exec(location)[1];
    var ipAddress = (new RegExp('(?:[0-9]{1,3}\.){3}[0-9]{1,3}')).exec(location)[0];
   clients[bulbID - 1] = net.createConnection(port, ipAddress);
   if (debug) console.log('Клиент создан для лампы ' + bulbID);
   
   clients[bulbID - 1].on('data', function(data) {
      if (debug) console.log('Принято: ' + data);
      notificationReceived(bulbID, data)
   });

   clients[bulbID - 1].on('close', function() {
       if (debug) console.log('Соединение закрыто');
   }); 
   
   clients[bulbID - 1].on('error', function() {
      if (debug) console.log('Неисправность соединения');
   }); 
}

function killClient(bulbID) {
   if (clients[bulbID - 1]) {
      clients[bulbID - 1].destroy();
      if (debug) console.log('Клиент завершен для лампы ' + bulbID);
   }
}

function sendBulbCommand(bulbID, changedValue, param1, effect, effectTime) {
   var command;
    switch (changedValue) {
        case 'ct':
            command = '{"id":' + bulbID + ',"method":"set_ct_abx","params":[' + param1 + ', "' + effect + '", ' + effectTime + ']}\r\n';
            break;
        case 'rgb':
            command = '{"id":' + bulbID + ',"method":"set_rgb","params":[' + parseInt(param1.substring(1), 16) + ', "' + effect + '", ' + effectTime + ']}\r\n';
            break;
        case 'hue':
         var sat = getState(s_dataset+ bulbID + '.sat').val;
            command = '{"id":' + bulbID + ',"method":"set_hsv","params":[' + param1 + ', ' + sat + ', "' + effect + '", ' + effectTime + ']}\r\n';
            break;
      case 'sat':
         var hue = getState(s_dataset + bulbID + '.hue').val;
            command = '{"id":' + bulbID + ',"method":"set_hsv","params":[' + hue + ', ' + param1 + ', "' + effect + '", ' + effectTime + ']}\r\n';
            break;   
        case 'bright':
            command = '{"id":' + bulbID + ',"method":"set_bright","params":[' + param1 + ', "' + effect + '", ' + effectTime + ']}\r\n';
            break;
        case 'power':
            command = '{"id":' + bulbID + ',"method":"set_power","params":["' + param1 + '", "' + effect + '", ' + effectTime + ']}\r\n';
            break;
        case 'toggle':
            command = '{"id":' + bulbID + ',"method":"toggle","params":[]}\r\n';
            break;
      case 'name':
         command = '{"id":' + bulbID + ',"method":"set_name","params":["' + param1 + '"]}\r\n';
         break;   
        default:
            if (debug) console.log('Неизвестная команда!');
            return;
    }
    if (debug) console.log(command);

    var commandClient = new net.Socket();
    //if (debug) console.log(clients[bulbID - 1].remoteAddress);
    //if (debug) console.log(clients[bulbID - 1].remotePort);
    
    var location = getState(s_dataset + bulbID + s_location).val;
    var port = (new RegExp(':([0-9]{1,5})')).exec(location)[1];
    var ipAddress = (new RegExp('(?:[0-9]{1,3}\.){3}[0-9]{1,3}')).exec(location)[0];
    
    try {
        commandClient.connect(port, ipAddress, function() {
            commandClient.write(command); 
            if (debug) console.log("CommandClient Command gesendet");
        });
        commandClient.on('data', function(data) {
            if (debug) console.log('CommandClient empfangen: ' + data);
           commandClient.destroy(); // kill client after server's response
           if (debug) console.log('CommandClient beendet');
        });
        commandClient.on('error', function(ex) {
            if (debug) console.log('CommandClient Fehler beim Verbinden');
        });
    } catch (err) {
        if (debug) console.log('CommandClient Fehler allgemein');
    }
}

function notificationReceived(bulbID, data) {
   var notification = JSON.parse(data);
   if (notification.params.power) {
      setState(s_dataset + bulbID + s_power, notification.params.power, true);
   }
   if (notification.params.bright) {
      setState(s_dataset + bulbID + s_bright, parseInt(notification.params.bright), true);
   }
   if (notification.params.ct) {
      setState(s_dataset + bulbID + s_ct, parseInt(notification.params.ct), true);
   }
   if (notification.params.rgb) {
      setState(s_dataset + bulbID + s_rgb, '#' + parseInt(notification.params.rgb).toString(16), true);
   }
   if (notification.params.hue) {
      setState(s_dataset + bulbID + s_hue, parseInt(notification.params.hue), true);
   }
   if (notification.params.sat) {
      setState(s_dataset + bulbID + s_sat, parseInt(notification.params.sat), true);
   }
   if (notification.params.color_mode) {
      setState(s_dataset + bulbID + s_colorMode, parseInt(notification.params.color_mode), true);
   }
   
   
}

//Subscribe für Änderung der Datenpunkte // Подписаться на изменение данных
subscribe({id: /^javascript\.0\.Yeelight.Bulb.*/, change: 'any', ack: false}, function (obj) {
   var bulbID = (new RegExp('^javascript\.0\.Yeelight.Bulb([0-9]?[0-9])\.')).exec(obj.id)[1];
   var changedValue = (new RegExp('^javascript\.0\.Yeelight.Bulb[0-9]?[0-9]\.(.*)')).exec(obj.id)[1];
   if (debug) console.log('Kommando für Lampe ' + bulbID + ' mit ' + changedValue);
   if (changedValue == 'Location') {
      killClient(bulbID);
      createClient(bulbID, obj.state.val);
   } else {
      sendBulbCommand(bulbID, changedValue, obj.state.val, switchEffect, switchEffectTime);
      //Änderung an Gruppe weitergeben
      var group = parseInt(getState(s_dataset + bulbID + s_group).val);
      if (group > 0 && changedValue != 'group' && changedValue != 'name') {
          if (debug) console.log('Kommando wird an Gruppe weitergegeben');
          var i = 1;
         while (getObject(s_dataset + i + s_group)) {
            if (debug) console.log('Schleifendurchlauf ' + i);
            if (i == bulbID) { //sich selbst muss man nicht updaten
               if (debug) console.log('Gruppenmitglied bin ich selbst'); 
            } else if (getState(s_dataset + i + s_group).val == group) { //jemand anderes ist in der gleichen Gruppe
               sendBulbCommand(i, changedValue, obj.state.val, switchEffect, switchEffectTime);
               if (debug) console.log('Lampe ' + i + ' in Gruppe ' + group + ' wurde angepasst');
            } else {
               if (debug) console.log('Lampe ' + i + ' nicht Mitglied in Gruppe ' + group);   
            }
            i++;
         } 
      }
      
   }
});

Оригинальный пост

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