Однократное и длительное нажатие кнопки для управления светом

Нужна помощь с настройкой выключателей.
В чем суть: есть модули аналогового вывода (WBIO-AO-10V-8 - подключается напрямую к вайрену, WB-MAO4 - подключается через мод бус и WB-MRGBW-D - тоже через мод бус), которые управляют диммерами светодиодных лент, и два модуля дискретных входов (WBIO-DI-WD-14, один из который напрямую к вайрену, а другой через WB-MGE и WB-MIO, т.е из интернета в мод бус, а из мод буса в I2C), к которым подключаются выключатели без фиксации (звонковые кнопки).
В чем задача: нужно настроить управление диммерами по нажатию на кнопки. Однократное краткое нажатие – включить на 100 процентов, еще одно однократное – выключить, длительное – изменение яркости по кругу (от 0 дошло до 100, потом в обратную сторону).
Как такое можно реализовать?
Если можно, прошу максимально подробный ответ, тк работаю с этим в первый раз)

Добрый день.
Вот то, что для обработки WD-14 нужно:

Нужно только переписать функции под задачу.

WB-MRGBW-D - умеет с помощью своих входов управляться, или обязательно внешнее управление?

Да, т.к WB-MRGBW-D используется нескольких одноцветных лент, а встроенная регулировка только общая

А можно чуть конкретнее? Что именно в данном коде нужно поменять именно под мою задачу?

Например, кнопка у нас подключена к модулю WBIO-DI-WD-14, в вайрене вход GPIO 268 (EXT1_IN13). Диммер подключен к WBIO-AO-10V-8, в вайрене выход 3 (DACchannel 1, MQTT id EXT4_O1, IIO channel number 3. Как правильно написать это все?

Понятно. Поэтому - можно переработать функцию из

function changeSetting(){
  log.info("Enter function");
  stringRGB = dev[dimmNumber +"mrgbw-d/RLine"].toString() +";"+ dev[dimmNumber +"mrgbw-d/GLine"].toString() +";"+ dev[dimmNumber +"mrgbw-d/BLine"].toString();
  //log.info("stringRGB=",stringRGB);
  dev[devDimmer +"/RGB"] = stringRGB;
  dev[devDimmer +"/White"] = dev[dimmNumber +"mrgbw-d/WLine"];
}

так:

//01_29_test_04.js
var devDimmer = "wb-mrgbw-d_189" // For name REAL MRGBW-D device #ChangeMe!#

function changeSettingRGB(num, newSetiing){
  //log.info("Enter function");
  //log.info("dev[devDimmer +/RGB]=",dev[devDimmer +"/RGB"]);
  //Получим строку с текущими значениями цвета.
  //ну и надо ее разобрать
  arrayOfRGB = dev[devDimmer +"/RGB"].split(";");
  //Тут - присваиваем ЭЛЕМНТУ массива НОВОЕ значение
  arrayOfRGB[num] = newSetiing;
  //log.info("arrayOfRGB=",arrayOfRGB[0],arrayOfRGB[1],arrayOfRGB[2]);
  stringRGB = arrayOfRGB[0].toString() +";"+ arrayOfRGB[1].toString() +";"+ arrayOfRGB[2].toString();
  //log.info("stringRGB=",stringRGB);
  dev[devDimmer +"/RGB"] = stringRGB;
}

//использование:
changeSettingRGB(0,25);  //для канала R -25
changeSettingRGB(1,42); //для канала G -42
changeSettingRGB(2,200); //для канала B -200

белый канал обработки не требует.

В коде реализована готовая функция, которая создает правила под обработку разных “нажатий”.
Туда (в функцию), как видно, передается кроме утроройства, за которысм “следим” еще и вызовы (имена) функций, которые вызываются при событиях. События - короткое нажатие, длинное, …
Менять надо именно эти функции. То есть скелет - готов, надо только реализовать алгоритм.
Для включения по короткому нажатию, например:

...
singlePress: {
       func: OnOff,
       prop: ["SomeDimmer", "SomeOutput", 100]
    },
...


и описать саму функцию-хелпер:

function OnOff(dimmerName, outputName, dimmerValue){
  if (dev[dimmerName][outputName]) { //Если не ноль
    dev[dimmerName][outputName] = 0; //Выключаем
  }
  else {
    dev[dimmerName][outputName] = dimmerValue; //Включаем на заданное значение
  }
}

Хинт:
Открываем в веб-интерфейсе “Settings” - “MQTT Channels”


Ну и тот же “EXT1_IN13”
записываем как

dev["wb-gpio"][EXT1_IN13]

используем строки из первого и второго столбца.
Тут же можно следить за значениями, если не хочется подписываться на топики в консоли.

Ура! Вкл, выкл заработало отлично, но не как не могу додуматься как реализовать функцию диммирования на WBIO-AO-10V-8. Можете, пожалуйста помочь и с этой функцией?

Подскажите пожалуйста)

Ну, достаточно, думаю, описать функцию-хелпер для изменения уровня диммирования так:

function dimmerChange(dimmerName, outputName, shiftValue, maxValue){
 var currentValue = dev[dimmerName][outputName]  //получим текущее значение
var newValue = currentValue+shiftValue; //Определяем предполоджительно новое значение
  if (newValue>maxValue) {newValue=0}
  if (newValue<0) {newValue=maxValue}
  dev[dimmerName][outputName] = newValue; //ставим на заданное значение

}

Вызывать, передавая имяДиммера, ИмяКанала, ИзменениеЗначения(положительное или отрицательное), максимальноеЗначение

Есть новая версия функции, в которой добавлена обработка долгого нажатия и периодического (пока не отпустил) вызова функции:

1 симпатия

К сожалению не работает. Краткое нажатие отрабатывает исправно, а вот длительное не работает(
Выдает вот это:

А какое значение передется диммеру?

В каком смысле какие?
Вот, если нужно код целиком:

(function () {
'use strict';
var ActionButtons = {};
ActionButtons.onButtonPress = function (trigger, action, timeToNextPress, timeOfLongPress) {
    log.info("LongPress ActionButtons.onButtonPress")//Это лог. Он попадает в /var/log/messages
    var buttonPressedCounter = 0;
    var timerWaitNextShortPress = null;
    var timerLongPress = null;
    var isLongPress = false;
    var ruleName = "on_button_press_" + trigger.replace("/", "_");
    defineRule(ruleName, {
        whenChanged: trigger,
        then: function (newValue, devName, cellName) {
          log.info("LongPress defineRule")//Это лог. Он попадает в /var/log/messages
            // If button is pressed, wait for a long press
            if (newValue) {
                if (timerWaitNextShortPress) {
                    clearTimeout(timerWaitNextShortPress);
                }
                timerLongPress = setTimeout(function () {
                    if (typeof action.longPress === "object") {
                        if (typeof action.longPress.func === "function") {
                            action.longPress.func.apply(this, action.longPress.prop);
                        }
                    }
                    // log(">>>>>>> long press <<<<<<");
                    isLongPress = true;  // Long press identified, we will skip short press
                    buttonPressedCounter = 0;
                }, timeOfLongPress);
            }
            // If button is released, then it is not a "long press", start to count clicks
            else {
                if (!isLongPress) {
                    clearTimeout(timerLongPress);
                    buttonPressedCounter += 1;
                    timerWaitNextShortPress = setTimeout(function () {
                        switch (buttonPressedCounter) {
                        // Counter equals 1 - it's a single short press
                        case 1:
                            if (typeof action.singlePress === "object") {
                                if (typeof action.singlePress.func === "function") {
                                    action.singlePress.func.apply(this, action.singlePress.prop);
                                }
                            }
                            // log(">>>>>> short press - single <<<<<<");
                            break;
                        // Counter equals 2 - it's a double short press
                        case 2:
                            if (typeof action.doublePress === "object") {
                                if (typeof action.doublePress.func === "function") {
                                    action.doublePress.func.apply(this, action.doublePress.prop);
                                }
                            }
                            // log(">>>>>> short press - double <<<<<<");
                            break;
                        }
                        // Reset the counter
                        buttonPressedCounter = 0;
                    }, timeToNextPress);
                }
                // Catch button released after long press
                else {
                    if (typeof action.longRelease === "object") {
                        if (typeof action.longRelease.func === "function") {
                            if (typeof action.longRelease.prop === "array") {
                                action.longRelease.func.apply(this, action.longRelease.prop);
                            } else {
                                action.longRelease.func.apply(this, []);
                            }
                        }
                    }
                    isLongPress = false;
                }
            }
        }
    });
};
// export as Node module / AMD module / browser variable
if (typeof exports === 'object' && typeof module !== 'undefined') {
    module.exports = ActionButtons;
} else if (typeof define === 'function' && define.amd) {
    define(ActionButtons);
} else {
    global.ActionButtons = ActionButtons;
}
}());
ActionButtons.onButtonPress(
"wb-gpio/EXT2_IN2",          //Вход, за которым следим.
{
    singlePress: {
       func: OnOff,
       prop: ["wb-dac", "EXT1_O1", 10000]
    },
    longPress: {
       func: dimmerChange, 
       prop: ["wb-dac", "EXT1_O1"]
    }
},
300, 1000
);
/**
* Helper Functions
*/
function OnOff(dimmerName, outputName, dimmerValue){
  if (dev[dimmerName][outputName]) { //Если не ноль
    dev[dimmerName][outputName] = 0; //Выключаем
  }
  else {
    dev[dimmerName][outputName] = dimmerValue; //Включаем на заданное значение
  }
}

function dimmerChange(dimmerName, outputName, shiftValue, maxValue){
 var currentValue = dev[dimmerName][outputName]  //получим текущее значение
var newValue = currentValue+shiftValue; //Определяем предполоджительно новое значение
  if (newValue>maxValue) {newValue=0}
  if (newValue<0) {newValue=maxValue}
  dev[dimmerName][outputName] = newValue; //ставим на заданное значение

}

А значения-то почему в функцию не передаете? Ни shiftValue ни maxValue
Надо как-то так:

 prop: ["wb-dac", "EXT1_O1", 10, 1000]

Не выходит, при длительном нажатии однократно прибавляет яркость на 10 пунктов и все.

А как должно быть? Что бы периодически значение увеличивалось пока нажата кнопка, до указанного диапазона?

Попробуйте данное правило, не забудьте только указать свои устройства.
Я не много переделал логику. На одно быстрое нажатие выключаем свет, по двойному включаем свет. А если кнопка зажата уставка на диммере будет постепенно увеличивать или уменьшатся.

	(function () {
	'use strict';
	var ActionButtons = {};
	ActionButtons.onButtonPress = function (trigger, action, timeToNextPress, timeOfLongPress) {
		log.info("LongPress ActionButtons.onButtonPress")//Это лог. Он попадает в /var/log/messages
		var buttonPressedCounter = 0;
		var timerWaitNextShortPress = null;
		var timerLongPress = null;
		var isLongPress = false;
		var ruleName = "on_button_press_" + trigger.replace("/", "_");
		defineRule(ruleName, {
			whenChanged: trigger,
			then: function (newValue, devName, cellName) {
			  log.info("LongPress defineRule")//Это лог. Он попадает в /var/log/messages
				// If button is pressed, wait for a long press
				if (newValue) {
					if (timerWaitNextShortPress) {
						clearTimeout(timerWaitNextShortPress);
					}
					timerLongPress = setTimeout(function () {
						if (typeof action.longPress === "object") {
							if (typeof action.longPress.func === "function") {
								action.longPress.func.apply(this, action.longPress.prop);
							}
						}
						// log(">>>>>>> long press <<<<<<");
						isLongPress = true;  // Long press identified, we will skip short press
						buttonPressedCounter = 0;
					}, timeOfLongPress);
				}
				// If button is released, then it is not a "long press", start to count clicks
				else {
					if (!isLongPress) {
						clearTimeout(timerLongPress);
						buttonPressedCounter += 1;
						timerWaitNextShortPress = setTimeout(function () {
							switch (buttonPressedCounter) {
							// Counter equals 1 - it's a single short press
							case 1:
								if (typeof action.singlePress === "object") {
									if (typeof action.singlePress.func === "function") {
										action.singlePress.func.apply(this, action.singlePress.prop);
									}
								}
								// log(">>>>>> short press - single <<<<<<");
								break;
							// Counter equals 2 - it's a double short press
							case 2:
								if (typeof action.doublePress === "object") {
									if (typeof action.doublePress.func === "function") {
										action.doublePress.func.apply(this, action.doublePress.prop);
									}
								}
								// log(">>>>>> short press - double <<<<<<");
								break;
							}
							// Reset the counter
							buttonPressedCounter = 0;
						}, timeToNextPress);
					}
					// Catch button released after long press
					else {
						if (typeof action.longRelease === "object") {
							if (typeof action.longRelease.func === "function") {
								if (typeof action.longRelease.prop === "array") {
									action.longRelease.func.apply(this, action.longRelease.prop);
								} else {
									action.longRelease.func.apply(this, []);
								}
							}
						}
						isLongPress = false;
					}
				}
			}
		});
	};

	// export as Node module / AMD module / browser variable
	if (typeof exports === 'object' && typeof module !== 'undefined') {
		module.exports = ActionButtons;
	} else if (typeof define === 'function' && define.amd) {
		define(ActionButtons);
	} else {
		global.ActionButtons = ActionButtons;
	}
	}());

	ActionButtons.onButtonPress(
			"wb-gpio/EXT1_IN2",          //Вход, за которым следим.
			{
				singlePress: {	 // Когда нажали быстро выключаем свет
				func: OnOff,
				prop: ["wb-dac_test", "EXT1_O1_test",0] 
				},
				doublePress: { // Когда нажали быстро 2 раза включаем свет
				func: On, 
				prop: ["wb-dac_test", "EXT1_O1_test",10000]
				},
				longPress: { // Когда зажали добовляем или уменьшаем яркость, в зависимости в каком был включен или выключен свет.
				func: dimmerChange, 
				prop: ["wb-dac_test", "EXT1_O1_test",10,10000]
				}
			},
		300, 1000
	);
	/**
	* Helper Functions
	*/

	var Destinations; // Флаг направления изменения яркости, для опредееняи увиличивать или уменьшать

	function OnOff(dimmerName, outputName, dimmerValue){
		  dev[dimmerName][outputName] = 0; //Выключаем
		  Destinations = true; // Выстовялем флаг на увиличение
	}

	function On(dimmerName, outputName, maxValue){
		 dev[dimmerName][outputName] = maxValue; //ставим на максимальное значение
		 Destinations= false; // Выстовялем флаг на уменьшения
	}

	function dimmerChange(dimmerName, outputName, shiftValue, maxValue){ 
	 while (dev["wb-gpio"]["EXT1_IN2"]) {
	   var currentValue = dev[dimmerName][outputName]  //получим текущее значение
	   if (Destinations)
		   {      
				var newValue = currentValue+shiftValue; //Определяем предполоджительно новое значение 
				 if (newValue>maxValue) {
					newValue=maxValue; 
					dev[dimmerName][outputName] = newValue; //ставим на заданное значение
					Destinations = false;
					return;
				 };     
				 dev[dimmerName][outputName] = newValue; //ставим на заданное значение
			 
		   }
	   else
		   {      
				var newValue = currentValue-shiftValue; //Определяем предположительно новое значение    
				if (newValue<0){
				  newValue=0; 
				  dev[dimmerName][outputName] = newValue; //ставим на заданное значение             
				  Destinations=true;
				  return;
				};
				dev[dimmerName][outputName] = newValue; //ставим на заданное значение        

		   }
		
	}
	}
1 симпатия

Да, именно так. Чтобы была та же логика работы, что и у WB-MDM3 в однокнопочном режиме:

  • короткое нажатие переключает состояние канала (выключает или включает с установленной яркостью).

  • долгое нажатие меняет яркость, вверх до 100 % или вниз до 1 %. Направление меняется при каждом долгом нажатии.

К сожалению, присланный вами код вообще не заработал(