// виртуальная кнопка defineVirtualDevice("switches", { title: "Весь свет", cells: { btn1: { type: "switch", value: false } } }); defineVirtualDevice("hall", { title: "Свет в зале", cells: { all_btn: { type: "switch", value: false } } }); var devTimers = {}; // соответствие имен светильников - выходам var groups = { // прихожая lobby_all: [ "wb-gpio/EXT7_K3", ], // гардероб cloak_all: [ "wb-gpio/EXT6_K2", ], // зал - бар bar_all: [ "wb-gpio/EXT6_K9", "wb-gpio/EXT6_K14", "wb-gpio/EXT6_K16", "wb-gpio/EXT6_K6", ], // зал центр - люстра и колонны center_all: [ "wb-gpio/EXT5_K13", "wb-gpio/EXT6_K13", "wb-gpio/EXT6_K4", ], // кухня kitchen_all: [ "wb-gpio/EXT6_K11", "wb-gpio/EXT5_K1", "wb-gpio/EXT5_K7", "wb-gpio/EXT6_K5", "wb-gpio/EXT7_K13", // подсветка стола ], // зал весь hall_all: [ //bar_all "wb-gpio/EXT6_K9", "wb-gpio/EXT6_K14", "wb-gpio/EXT6_K16", //center_all "wb-gpio/EXT5_K13", "wb-gpio/EXT6_K13", //kitchen_all "wb-gpio/EXT6_K11", "wb-gpio/EXT5_K1", "wb-gpio/EXT5_K7", ], // комната 1 - вход room1_enter_all: [ "wb-gpio/EXT6_K10", ], // комната 1 room1_all: [ "wb-gpio/EXT5_K3", "wb-gpio/EXT5_K12", "wb-gpio/EXT6_K15", // подсветка ТВ ], // комната 1 - туалет room1_wc_all: [ "wb-gpio/EXT5_K4", "wb-gpio/EXT5_K11", "wb-gpio/EXT5_K14", ], // комната 2 - вход room2_enter_all: [ "wb-gpio/EXT5_K16", ], // комната 2 room2_all: [ "wb-gpio/EXT5_K6", //"wb-gpio/EXT6_K12", // бра на стене "wb-gpio/EXT5_K2", "wb-gpio/EXT7_K6", // подсветка ТВ ], // комната 2 - туалет room2_wc_all: [ "wb-gpio/EXT5_K5", "wb-gpio/EXT5_K9", "wb-gpio/EXT6_K8", ], // зимний сад park_all: [ "wb-gpio/EXT5_K15", "wb-gpio/EXT7_K1", ], rooms_all: [ "wb-gpio/EXT5_K1", "wb-gpio/EXT5_K2", "wb-gpio/EXT5_K3", "wb-gpio/EXT5_K4", "wb-gpio/EXT5_K5", "wb-gpio/EXT5_K6", "wb-gpio/EXT5_K7", "wb-gpio/EXT5_K8", "wb-gpio/EXT5_K9", "wb-gpio/EXT5_K10", "wb-gpio/EXT5_K11", "wb-gpio/EXT5_K12", "wb-gpio/EXT5_K13", "wb-gpio/EXT5_K14", "wb-gpio/EXT5_K15", "wb-gpio/EXT5_K16", "wb-gpio/EXT6_K1", "wb-gpio/EXT6_K2", "wb-gpio/EXT6_K3", "wb-gpio/EXT6_K4", "wb-gpio/EXT6_K5", "wb-gpio/EXT6_K6", "wb-gpio/EXT6_K7", "wb-gpio/EXT6_K8", "wb-gpio/EXT6_K9", "wb-gpio/EXT6_K10", "wb-gpio/EXT6_K11", "wb-gpio/EXT6_K12", "wb-gpio/EXT6_K13", "wb-gpio/EXT6_K14", "wb-gpio/EXT6_K15", "wb-gpio/EXT6_K16", "wb-gpio/EXT7_K1", "wb-gpio/EXT7_K2", "wb-gpio/EXT7_K3", "wb-gpio/EXT7_K4", "wb-gpio/EXT7_K5", "wb-gpio/EXT7_K6", "wb-gpio/EXT7_K7", "wb-gpio/EXT7_K8", "wb-gpio/EXT7_K9", "wb-gpio/EXT7_K10", "wb-gpio/EXT7_K11", "wb-gpio/EXT7_K12", "wb-gpio/EXT7_K13", "wb-gpio/EXT7_K14", "wb-gpio/EXT7_K15", "wb-gpio/EXT7_K16", "wb-gpio/EXT8_K1", "wb-gpio/EXT8_K2", "wb-gpio/EXT8_K3", "wb-gpio/EXT8_K4", "wb-gpio/EXT8_K5", "wb-gpio/EXT8_K6", "wb-gpio/EXT8_K7", "wb-gpio/EXT8_K8", "wb-gpio/EXT8_K9", "wb-gpio/EXT8_K10", "wb-gpio/EXT8_K11", "wb-gpio/EXT8_K12", "wb-gpio/EXT8_K13", "wb-gpio/EXT8_K14", "wb-gpio/EXT8_K15", "wb-gpio/EXT8_K16", ], }; var rules = [ //{ // name: "весь свет", // when: function (caller) { // return caller.change("switches/btn1") || caller.press("wb-gpio/EXT1_DR1"); // }, // then: function (newValue, devName, cellName) { // //log(newValue); // //doToggle("rooms_all"); // } //}, { name: "вход в гардероб", when: function (caller) { return caller.press("wb-gpio/EXT1_DR2") ; }, then: function (newValue, devName, cellName) { //log(newValue); doToggle("cloak_all"); } }, { name: "прихожая", when: function (caller) { return caller.press("wb-gpio/EXT3_DR14"); }, then: function (newValue, devName, cellName) { //log(newValue); doToggle("lobby_all"); } }, { name: "вход в зал", when: function (caller) { return caller.press("wb-gpio/EXT2_DR12") || caller.press("wb-gpio/EXT1_DR16"); }, then: function (newValue, devName, cellName) { //log(newValue); doToggle("bar_all"); } }, { name: "свет в центре", when: function (caller) { return caller.press("wb-gpio/EXT2_DR11") || caller.press("wb-gpio/EXT2_DR6") || caller.press("wb-mio-gpio_20:2/DR5"); }, then: function (newValue, devName, cellName) { //log(newValue); doToggle("center_all"); } }, { name: "прихожая комнаты 1", when: function (caller) { return caller.press("wb-gpio/EXT3_DR1") || caller.press("wb-gpio/EXT4_DR10"); }, then: function (newValue, devName, cellName) { //log(newValue); doToggle("room1_enter_all"); } }, { name: "комната 1 туалет", when: function (caller) { return caller.press("wb-mio-gpio_20:1/DR16") || caller.press("wb-mio-gpio_20:1/DR15") || caller.press("wb-gpio/EXT2_DR1"); }, then: function (newValue, devName, cellName) { //log(newValue); doToggle("room1_wc_all"); } }, { name: "комната 1", when: function (caller) { return caller.press("wb-mio-gpio_20:1/DR3") || caller.press("wb-mio-gpio_20:1/DR4"); }, then: function (newValue, devName, cellName) { //log(newValue); doToggle("room1_all"); } }, { name: "прихожая комнаты 2", when: function (caller) { return caller.press("wb-gpio/EXT3_DR10"); }, then: function (newValue, devName, cellName) { //log(newValue); doToggle("room2_enter_all"); } }, { name: "комната 2", when: function (caller) { return caller.press("wb-gpio/EXT2_DR16") || caller.press("wb-gpio/EXT4_DR1"); }, then: function (newValue, devName, cellName) { //log(newValue); doToggle("room2_all"); } }, { name: "комната 2 туалет", when: function (caller) { return caller.press("wb-mio-gpio_20:1/DR10") || caller.press("wb-mio-gpio_20:1/DR11"); }, then: function (newValue, devName, cellName) { //log(newValue); doToggle("room2_wc_all"); } }, { name: "кухня", when: function (caller) { return caller.press("wb-gpio/EXT4_DR13") || caller.press("wb-gpio/EXT3_DR7"); }, then: function (newValue, devName, cellName) { //log(newValue); doToggle("kitchen_all"); } }, { name: "зимний сад", when: function (caller) { return caller.press("wb-gpio/EXT1_DR5"); }, then: function (newValue, devName, cellName) { //log(newValue); doToggle("park_all"); } }, { name: "зал свет", when: function (caller) { return caller.change("hall/all_btn"); }, then: function (newValue, devName, cellName) { //log(newValue); doToggle("hall_all"); } }, { name: "лестница свет вверх", when: function (caller) { return caller.press("wb-gpio/EXT1_DR15"); }, then: function (newValue, devName, cellName) { //log(newValue); doToggle("wb-gpio/EXT7_K7"); } }, { name: "лестница свет вниз", when: function (caller) { return caller.press("wb-gpio/EXT4_DR14"); }, then: function (newValue, devName, cellName) { //log(newValue); doToggle("wb-gpio/EXT6_K1"); } }, { name: "вентиляция в туалете 1 (комната 4)", when: function (caller) { return caller.press("wb-gpio/EXT2_DR2"); }, then: function (newValue, devName, cellName) { //log(newValue); doToggle("wb-gpio/EXT7_K2"); } }, { name: "вентиляция в туалете 2 (комната 6)", when: function (caller) { return caller.press("wb-mio-gpio_20:1/DR12"); }, then: function (newValue, devName, cellName) { //log(newValue); doToggle("wb-gpio/EXT6_K3"); } }, // ШТОРЫ и приводы окон // окно прихожей { name: "окно прихожей открытие", when: function (caller) { return caller.press("wb-gpio/EXT3_DR12") && !caller.change("wb-gpio/EXT3_DR11"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-mio-gpio_20:3/K2", "wb-mio-gpio_20:3/K1", 15); } }, { name: "окно прихожей закрытие", when: function (caller) { return caller.press("wb-gpio/EXT3_DR11") && !caller.change("wb-gpio/EXT3_DR12"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-mio-gpio_20:3/K1", "wb-mio-gpio_20:3/K2", 15); } }, // окно у камина { name: "окно у камина открытие", when: function (caller) { return caller.press("wb-gpio/EXT4_DR16") && !caller.change("wb-gpio/EXT4_DR15"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-mio-gpio_20:3/K4", "wb-mio-gpio_20:3/K3", 15); } }, { name: "окно у камина закрытие", when: function (caller) { return caller.press("wb-gpio/EXT4_DR15") && !caller.change("wb-gpio/EXT4_DR16"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-mio-gpio_20:3/K3", "wb-mio-gpio_20:3/K4", 15); } }, // окно у ТВ зоны { name: "окно у ТВ зоны открытие", when: function (caller) { return caller.press("wb-gpio/EXT1_DR7") && !caller.change("wb-gpio/EXT1_DR8"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-gpio/EXT8_K13", "wb-gpio/EXT8_K14", 15); } }, { name: "окно у ТВ зоны закрытие", when: function (caller) { return caller.press("wb-gpio/EXT1_DR8") && !caller.change("wb-gpio/EXT1_DR7"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-gpio/EXT8_K14", "wb-gpio/EXT8_K13", 15); } }, // окно ЗС { name: "окно ЗС открытие", when: function (caller) { return caller.press("wb-gpio/EXT2_DR15") && !caller.change("wb-mio-gpio_20:2/DR6"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-gpio/EXT8_K9", "wb-gpio/EXT8_K10", 15); } }, { name: "окно ЗС закрытие", when: function (caller) { return caller.press("wb-mio-gpio_20:2/DR6") && !caller.change("wb-gpio/EXT2_DR15"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-gpio/EXT8_K10", "wb-gpio/EXT8_K9", 15); } }, // тюль в углу ТВ зоны { name: "тюль в углу ТВ зоны открытие", when: function (caller) { return caller.press("wb-gpio/EXT3_DR3") && !caller.change("wb-gpio/EXT3_DR4"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-mio-gpio_20:3/K5", "wb-mio-gpio_20:3/K6", 15); } }, { name: "тюль в углу ТВ зоны закрытие", when: function (caller) { return caller.press("wb-gpio/EXT3_DR4") && !caller.change("wb-gpio/EXT3_DR3"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-mio-gpio_20:3/K6", "wb-mio-gpio_20:3/K5", 15); } }, // штора ТВ зоны { name: "штора ТВ зоны открытие", when: function (caller) { return caller.press("wb-gpio/EXT1_DR3") && !caller.change("wb-gpio/EXT1_DR4"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-gpio/EXT8_K11", "wb-gpio/EXT8_K12", 15); } }, { name: "штора ТВ зоны закрытие", when: function (caller) { return caller.press("wb-gpio/EXT1_DR4") && !caller.change("wb-gpio/EXT1_DR3"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-gpio/EXT8_K12", "wb-gpio/EXT8_K11", 15); } }, // штора центральной зоны { name: "штора центральной зоны открытие", when: function (caller) { return (caller.press("wb-gpio/EXT3_DR5") || caller.press("wb-gpio/EXT1_DR14")) && !(caller.change("wb-gpio/EXT3_DR6") || caller.change("wb-gpio/EXT1_DR13")); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-mio-gpio_20:3/K7", "wb-mio-gpio_20:3/K8", 15); } }, { name: "штора центральной зоны закрытие", when: function (caller) { return (caller.press("wb-gpio/EXT3_DR6") || caller.press("wb-gpio/EXT1_DR13")) && !(caller.change("wb-gpio/EXT3_DR5") || caller.change("wb-gpio/EXT1_DR14")) }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-mio-gpio_20:3/K8", "wb-mio-gpio_20:3/K7", 15); } }, // штора каминной зоны { name: "штора каминной зоны открытие", when: function (caller) { return caller.press("wb-gpio/EXT4_DR5") && !caller.change("wb-gpio/EXT4_DR6"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-gpio/EXT8_K5", "wb-gpio/EXT8_K6", 15); } }, { name: "штора каминной зоны закрытие", when: function (caller) { return caller.press("wb-gpio/EXT4_DR6") && !caller.change("wb-gpio/EXT4_DR5"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-gpio/EXT8_K6", "wb-gpio/EXT8_K5", 15); } }, // штора каминной зоны малая { name: "штора каминной зоны малая открытие", when: function (caller) { return caller.press("wb-gpio/EXT4_DR8") && !caller.change("wb-gpio/EXT4_DR7"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-gpio/EXT8_K15", "wb-gpio/EXT8_K16", 15); } }, { name: "штора каминной зоны малая закрытие", when: function (caller) { return caller.press("wb-gpio/EXT4_DR7") && !caller.change("wb-gpio/EXT4_DR8"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-gpio/EXT8_K16", "wb-gpio/EXT8_K15", 15); } }, // штора кухни { name: "штора кухни открытие", when: function (caller) { return caller.press("wb-gpio/EXT3_DR15") && !caller.change("wb-gpio/EXT3_DR16"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-gpio/EXT8_K8", "wb-gpio/EXT8_K7", 15); } }, { name: "штора кухни закрытие", when: function (caller) { return caller.press("wb-gpio/EXT3_DR16") && !caller.change("wb-gpio/EXT3_DR15"); }, then: function (newValue, devName, cellName) { //log(newValue); doShutter("wb-gpio/EXT8_K7", "wb-gpio/EXT8_K8", 15); } }, ]; function doShutter(mainState, slaveState, sec) { clearStateTimeout(mainState); clearStateTimeout(slaveState); doState(slaveState, false); // если не работает, то включаем на 15 секунд if (!dev[mainState]) { doStateTimeout(mainState, true, false, sec*1000); } else { // иначе выключаем doState(mainState, false); } } function clearTimer(devname, type) { var timername = devname+'_'+type; if (devTimers[timername]) { clearTimeout(devTimers[timername]); delete devTimers[timername]; } } function clearStateTimeout(devname) { clearTimer(devname, 'dostatetimeout'); } function doStateTimeout(devname, stateOn, stateOff, timeout) { clearStateTimeout(devname); var devices = []; // проверим что имя устройства это группа if (groups[devname] !== undefined) { devices = groups[devname]; } else { devices.push(devname); } log("do state devices: {}".format(devices)); if (devices.length > 0) { devices.forEach(function(item){ log("{} state: {}".format(item, stateOn)); dev[item] = stateOn; }); // по таймеру вернес прежний стейст var timer = setTimeout(function(){ devices.forEach(function(item){ log("{} state: {}".format(item, stateOff)); dev[item] = stateOff; }); }, timeout); devTimers[devname+'_dostatetimeout'] = timer; } } function doState(devname, state) { var devices = []; // проверим что имя устройства это группа if (groups[devname] !== undefined) { devices = groups[devname]; } else { devices.push(devname); } log("do state devices: {}".format(devices)); if (devices.length > 0) { var nextState = state; devices.forEach(function(item){ log("{} state: {}".format(item, nextState)); dev[item] = nextState; }); } } function doToggle(devname) { var devices = []; // проверим что имя устройства это группа if (groups[devname] !== undefined) { devices = groups[devname]; } else { devices.push(devname); } log("Toggle devices: {}".format(devices)); if (devices.length > 0) { // текущее и следующее состояние определим по первому элементу var currentState = dev[devices[0]]; var nextState = (currentState == 1) ? false : true; devices.forEach(function(item){ log("{} current: {}, next: {}".format(item, currentState, nextState)); dev[item] = nextState; }); } } function prepareThen(timers, condition, callback) { function res(newValue, devName, cellName) { var caller = { press: function (name) { var result = false; var devcell = devName+'/'+cellName; log("press name = {} devcell = {}".format(name, devcell)); if (name == devcell) { // если нажата log("short newValue = {}".format(newValue)); if (newValue) { result = true; } } log("press result = {}".format(result)); return result; }, short: function (name) { var result = false; var devcell = devName+'/'+cellName; log("short name = {} devcell = {}".format(name, devcell)); if (name == devcell) { // если нажата - запоминаем время нажатия log("short newValue = {}".format(newValue)); if (newValue) { timers[name+'_short'] = new Date(); } else { // если отжата - сравниваем время. если < 500, значит короткое if ((new Date() - timers[name+'_short']) < 500) { result = true; } } } log("short result = {}".format(result)); return result; }, long: function (name) { var result = false; var devcell = devName+'/'+cellName; if (name == devcell) { // если нажата - запоминаем время нажатия if (newValue) { timers[name+'_long'] = new Date(); } else { // если отжата - сравниваем время. если >= 500, значит длиное if ((new Date() - timers[name+'_long']) >= 500) { result = true; } } } return result; }, change: function (name) { var result = false; var devcell = devName+'/'+cellName; if (name == devcell) { result = true; } return result; }, on: function (name) { var result = false; var devcell = devName+'/'+cellName; if (name == devcell) { result = (dev[name] == 1); } return result; }, off: function (name) { var result = false; var devcell = devName+'/'+cellName; if (name == devcell) { result = (dev[name] !== 1); } return result; }, }; if (condition(caller)) { callback(newValue, devName, cellName); } } return res; } function collectTriggers(condition) { var triggers = []; var caller = { press: function (name) { triggers.push(name); return false; }, short: function (name) { triggers.push(name); return false; }, long: function (name) { triggers.push(name); return false; }, change: function (name) { triggers.push(name); return false; }, on: function (name) { triggers.push(name); return false; }, off: function (name) { triggers.push(name); return false; }, }; condition(caller); return triggers; } function createRule(ruleDef) { var triggers = collectTriggers(ruleDef.when); log("create rule {}".format(triggers)); defineRule(ruleDef.name, { whenChanged: triggers, then: prepareThen(devTimers, ruleDef.when, ruleDef.then) }); } rules.forEach(function (item) { createRule(item); });