Протокол DALI

Весь скрипт выглядит так:

defineVirtualDevice("dimmer2", { //Создаём виртуальнное устройство Диммер3
    title: "dimmer control2",
    cells: {  //с параметрами 
        change: {
            type: "switch", //  тип, публикуемый в MQTT-топике /devices/.../controls/.../meta/type для данного параметра.
            value: false    // значение по умолчанию
        },
		click: {
            type: "switch", //  одиночный клик
            value: false    // значение по умолчанию
        },
		doubleClick: {
            type: "switch", //  двойной клик
            value: false    // значение по умолчанию
        },
        value: {
            type: "value",  // тип (.../meta/type)
            value: 0        // значение по умолчанию
        },
        saved: {
            type: "value",  // тип (.../meta/type)
            value: 100      // значение по умолчанию
        },
    }
});

var dirct3 = false;
var lastdirct3 = false;
var timerLast3;
var timerTime3;
var countClick3 = 0;		// кол-во сделанных кликов (счетчик, начальное значение всегда = 0)

// для тонкой настройки
var timeClick3 = 900;   // время одного клика/длинного клика
var timeout23 = 1500; 	// максимальное время ожидания двойного клика
var timeout3 = 400; 		// интервал изменения яркости димера в мс
var delta3 = 6;     		// шаг приращения яркости диммера
var startBright3 = 1; 	// начальная яркость при розжиге

var hkmin = 0;
var hkmax = 100;
var dalimin = 86;
var dalimax = 254;

var p;

trackMqtt("/devices/dimmer2/controls/value", function(message){
  log.info("name: {}, value: {}".format(message.topic, message.value));
  log.info(p);
  if(message.value > hkmin && message.value <= hkmax){
    p = parseInt(((message.value-hkmin) / (hkmax-hkmin)) * (dalimax-dalimin) + dalimin, 10);
        dev["dali_gw2_21"]["Channel 0"] = p;
    } else {
      dev["dali_gw2_21"]["Channel 0"] = 0;
    }
});


defineRule("simple_folow", {
  whenChanged: "dimmer2/value",
  then: function (newValue, devName, cellName) {
	  log.info("Вход в функцию"); 
    log.info(p); 
    if(newValue > hkmin && newValue <= hkmax){
        p = parseInt(((newValue-hkmin) / (hkmax-hkmin)) * (dalimax-dalimin) + dalimin, 10);
        dev["dali_gw2_21"]["Channel 0"] = p;
    }
  }
});

defineRule("oneClick3", {
    asSoonAs: function() {
		// было одно нажатие, восстанавливаем запомненое значение или полностью выключаем
        return dev["dimmer2/click"];
    },
    then: function() { 						// выполняется при срабатывании правила
        if (dev["dimmer2/value"] > 0) {   	// если свет включен, сохраняем текущее значение и выключаем
			dev["dimmer2/saved"] = dev["dimmer2/value"];
			dev["dimmer2/value"] = 0;
			dev["dali_gw2_21"]["Channel 0"] = 0;
			log.info("Выключить свет");
		} else { 							// если свет выключен, выставляем значение взяв из сохраненного
			dev["dimmer2/value"] = dev["dimmer2/saved"];
			log.info("Включить свет");
		}
		dev["dimmer2/click"] = false; 		// сброс состояния
		log.info("oneClick");
    }
});

defineRule("wtoClick3", {
    asSoonAs: function() {
		// было двойное нажатие, свет на максимум
        return dev["dimmer2/doubleClick"];
    },
    then: function() { 						// выполняется при срабатывании правила
        dev["dimmer2/value"] = 100; 		// максимальная яркость
		dev["dimmer2/doubleClick"] = false; // сброс состояния
		log.info("doubleClick");
    }
});

// правило с именем startClicking
defineRule("startClicking3", {
    asSoonAs: function() {
		// edge-triggered-правило - выполняется, только когда значение
		// данной функции меняется и при этом становится истинным
		// т.е. когда dimmer2/change стало = true, а до этого было fasle
		// запускаем работу диммера по нажатию клавиши
        return dev["dimmer2/change"];
    },
    then: function() { 						// выполняется при срабатывании правила
      //log.info("1 - dirct3:", dirct3, "lastdirct3:", lastdirct3);
        if (dev["dimmer2/value"] == 100) {
            dirct3 = false;
        } else if (dev["dimmer2/value"] == 0) {
            dirct3 = true;
        } else {
            dirct3 = !lastdirct3;
        }
        //log.info("2 - dirct3:", dirct3, "lastdirct3:", lastdirct3);
        startTicker("clickTimer3", timeout3); // запустить таймер clickTimer со срабатыванием каждые N мс
		log.info("startClicking3");
    }
});

defineRule("stopClicking3", {
    asSoonAs: function() {
		// т.е. когда dimmer2/change стало = false, а до этого было true
		// по простому кнопку димера отпустили, прекращаем димировать (тормозим тикающий таймер)
        return !dev["dimmer2/change"];
    },
    then: function() {
        timers.clickTimer3.stop(); // остановить таймер clickTimer
        lastdirct3 = dirct3;
		log.info("stopClicking3");
    }
});

defineRule("doClick3", {
    when: function() {
	// т.е. пока таймер clickTimer3 работает, вызываем функцию при каждом срабатывании таймера 
	// тут работает диммер
        return timers.clickTimer3.firing;
    },
    then: function() {
		log.info("doClick3");
        if (dirct3) { // розжиг
			log.info("розжиг");
            if (dev["dimmer2/value"] >= 93) {
                dev["dimmer2/value"] = 100;
            } else {
				// при начале розжига проверяем на минимальный порог
				// если меньше, то сразу устанавливаем значение яркости = startBright3
				// иначе наращиваем с заданным шагом
				log.info("Start. value =", dev["dimmer2/value"], "startBright3 = ", startBright3)
				if (dev["dimmer2/value"] >= startBright3){
					dev["dimmer2/value"] = ((dev["dimmer2/value"] * 1) + delta3); //.toFixed(0);
				} else {
					dev["dimmer2/value"] = startBright3; //.toFixed(0);
				}
				log.info("Finish. value =", dev["dimmer2/value"])
            }
        } 
		if (!dirct3) { // затухание
			log.info("затухание");
            if (dev["dimmer2/value"] <= 6) {
                dev["dimmer2/value"] = 0;
            } else {
                dev["dimmer2/value"] = ((dev["dimmer2/value"] * 1) - delta3);//.toFixed(0);
            }
        }
    }

});

defineRule("timeout23", {
    when: function() {
		//вызываем функцию при срабатывании таймера 
        return timers.doubleClickTimeout3.firing;
    },
    then: function() {
		log.info("Прошло много времени, сбрасываем счетчик");
		countClick3 = 0;
	}
});

defineRule("long_press3", {
	// Срабатывание при изменении значения параметра.
    whenChanged: "wb-gpio/A2_IN",  //при изменении состояния A2_IN у устройства wb-gpio
    then: function(newValue, devName, cellName) { //выполняй следующие действия
		log.info("newValue = ", newValue);
        if (newValue) {
            timerLast3 = Date.now();
			log.info("timerLast3 = ", timerLast3);
			startTimer("doubleClickTimeout3", timeout23); // старт таймера ожидания двух кликов
            dev["dimmer2/change"] = true;
        } else {
            dev["dimmer2/change"] = false;
            timerTime3 = Date.now();
			log.info("timerTime3 = " + timerTime3);
            if ((timerTime3 - timerLast3) <= timeClick3) {
				log.info("countClick3 = ", countClick3);
				if (countClick3 >= 1){
					log.info("Было второе короткое нажатие");
					dev["dimmer2/doubleClick"] = true;
					countClick3 = 0; //сброс счетчика
				}
				else if (countClick3 <= 0){
					log.info("Было короткое нажатие");
					dev["dimmer2/click"] = true;
					countClick3 = countClick3 + 1;
				}
            } else if ((timerTime3 - timerLast3) >= timeClick3) {
				countClick3 = 0; //сброс счетчика
				lastdirct3 = dirct3;
				timers.doubleClickTimeout3.stop(); // остановить таймер, т.к. было длинное нажатие
                log.info("было длинное нажатие");
            }
        }
    }
});

Если управлять через WEB работает нормально, но если управлять через A2_IN - работает не стабильно. Завтра продолжу эксперименты, Если подскажите способ оптимизировать правило, или всю задачу - буду признателен.

2 лайка