Я примерно это и понял, у меня последний вариант работает без ошибок.
Т.е. кнопкой контролируем активность правила, а по изменениям данный с датчика контролируем выход за рамки по температуре. Вы его проверяли?
не успел еще, обязательно проверю, отпишусь
Отрабатывает все четко, спасибо огромное!!
а вот тут
if (dev.control_heating.enabled) { // если вируальн. устр-во в положении enabled
log.info(“newValue ={}”,newValue);
if (newValue < temp_on) { //если температура датчика меньше xx градусов
if (!(relay_on_timer_id||relay_off_timer_id)){on_timer();}
log.info(“Stop timer and off relay, temp > {}”,temp_on);
в лог не Start timer and on relay, temp < {}",temp_on ?
Да, тут нужно выводить в лог информацию о запуске реле, если текущая температура меньше минимальной уставки.
Привет, мне в одной ветке сказали что лучше следить не за событием нажатия, а за событием изменения счетчика нажатий. В результате, чуть модифицировал пример под работу сразу с двумя кейсами. Можете посмотреть и дать комментарии, так как я не очень силен в JS.
(function () {
'use strict';
var ActionButtons = {};
/**
* Version: 0.3.1
*
* Function that identifies what kind of press was performed: single, double or long press;
* and assigns an action for each type of press.
*
* @param {string} trigger - Name of device and control in the following format: " <device>/<control>".
* @param {object} action - Defines actions to be taken for each type of button press.
* Key: "singlePress" or "doublePress" or "triplePress" or "longPress" or "longRelease".
* Value: Object of the following structure {func: <function name>, prop: <array of parameters to be passed>}
* Example:
* {
* singlePress: {func: myFunc1, prop: ["wb-mr6c_1", "K1"]},
* doublePress: {func: myFunc2, prop: ["wb-mrgbw-d_2", "RGB", "255;177;85"]},
* triplePress: {func: myFunc3, prop: []},
* longPress: {func: myFunc4, prop: []},
* longRelease: {func: myFunc5, prop: []}
* }
* @param {number} timeToNextPress - Time (ms) after button up to wait for the next press before reseting the counter. Default is 300 ms.
* @param {number} timeOfLongPress - Time (ms) after button down to be considered as as a long press. Default is 1000 ms (1 sec).
* @param {number} intervalOfRepeat - Time (ms) before repeating action specified in LongPress action. Default is 50 ms.
*
* Note: In case longRelease function defined, longPress function will repeate till button is released.
* In case longRelease function not defined, only one action will be executed for longPress.
*/
ActionButtons.onButtonPress = function (trigger, action, timeToNextPress, timeOfLongPress, intervalOfRepeat) {
// Set default values if not passed into function
timeToNextPress = timeToNextPress || 300;
timeOfLongPress = timeOfLongPress || 1000;
intervalOfRepeat = intervalOfRepeat || 100;
var buttonPressedCounter = 0;
var actionRepeatCounter = 0;
var timerWaitNextShortPress = null;
var timerLongPress = null;
var timerWaitLongRelease = null;
var isLongPressed = false;
var isLongReleased = false;
var ruleName = "on_button_press_" + trigger.replace("/", "_").replace(/ /g, "_"); //Добавил условие для удаления пробелов
log("LOG::Define WB Rule: ", ruleName);
defineRule(ruleName, {
whenChanged: trigger,
then: function (newValue, devName, cellName) {
// Вставка для работы со счетчиками нажатий
var isButtonPressed = newValue;
if (typeof newValue === "number"){
isButtonPressed = newValue % 2 !== 0;
}
// If button is pressed, wait for a long press
if (isButtonPressed) {
if (timerWaitNextShortPress) {
clearTimeout(timerWaitNextShortPress);
}
timerLongPress = setTimeout(function () {
isLongPressed = true; // Long press identified, we will skip short press
isLongReleased = false;
buttonPressedCounter = 0;
actionRepeatCounter = 1;
if (typeof action.longPress === "object") {
if (typeof action.longPress.func === "function") {
action.longPress.func.apply(this, action.longPress.prop);
// If Long Release action define, we will repeat Long Press action till not released. Otherwise only 1 Long Press action is executed
if (typeof action.longRelease === "object") {
if (typeof action.longRelease.func === "function") {
timerWaitLongRelease = setInterval(function () {
if(!isLongReleased) {
if (typeof action.longPress === "object") {
if (typeof action.longPress.func === "function") {
action.longPress.func.apply(this, action.longPress.prop);
}
}
// log(">>>>>> long press - press (" + actionRepeatCounter++ + ") <<<<<<");
}
if(isLongReleased) {
clearInterval(timerWaitLongRelease);
}
}, intervalOfRepeat);
}
}
}
}
// log(">>>>>> long press - press (" + actionRepeatCounter++ + ") <<<<<<");
}, timeOfLongPress);
}
// If button is released, then it is not a "long press", start to count clicks
else {
if (!isLongPressed) {
if (timerLongPress) {
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;
// Counter equals 3 - it's a triple short press
case 3:
if (typeof action.triplePress === "object") {
if (typeof action.triplePress.func === "function") {
action.triplePress.func.apply(this, action.triplePress.prop);
}
}
// log(">>>>>> short press - triple <<<<<<");
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, []);
// }
}
}
// log(">>>>>> long press - release <<<<<<");
isLongPressed = false;
isLongReleased = true;
}
}
}
});
};
// 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;
}
}());
const flatIOs = [
{ name: 'DI0', io: ['Counter 1', 'Counter 2', 'Counter 3', 'Counter 4', 'Counter 5', 'Counter 6', 'Counter 7', 'Counter 8', 'Counter 9', 'Counter 10', 'Counter 11', 'Counter 12', 'Counter 13', 'Counter 14'] },
{ name: 'R1', io: ['K1', 'K2', 'K3', 'K4', 'K5', 'K6'] },
{ name: 'R2', io: ['K1', 'K2', 'K3', 'K4', 'K5', 'K6'] }
];
ActionButtons.onButtonPress(
flatIOs[0].name +"/"+ flatIOs[0].io[0], //Вход, за которым следим.
{
singlePress: {
func: switchRelay,
prop: [flatIOs[1].name, flatIOs[1].io[0]]
},
doublePress: {
func: switchRelay, prop: [flatIOs[1].name, flatIOs[1].io[1]]
//func: switchDimmerRGB,
//prop: ["wb-mr6c_10", "K2", "wb-mrgbw-d_24"]
},
longPress: {
func: switchRelay, prop: [flatIOs[1].name, flatIOs[1].io[2]]
//func: setRandomRGB,
//prop: ["wb-mr6c_10", "K2", "wb-mrgbw-d_24"]
}
},
300, 1000
);
/**
* Helper Functions
*/
function switchRelay(device, control) { //Принимает в параметрах устройство и выход. Переключает состояние выхода на противоположное.
log.info("LongPress switchRelay", device, control)//Это лог. Он попадает в /var/log/messages
dev[device][control] = !dev[device + "/" + control];
}
function switchDimmerRGB(relayDevice, relayControl, dimmerDevice) {
dev[relayDevice][relayControl] = true;
if (dev[dimmerDevice + "/RGB"] !== "0;0;0") {
dev[dimmerDevice]["RGB"] = "0;0;0";
}
else {
dev[dimmerDevice]["RGB"] = dev[relayDevice + "/RGB"];
}
}
function setRandomRGB(relayDevice, relayControl, dimmerDevice) {
dev[relayDevice][relayControl] = true;
dev[relayDevice + "/RGB"] = "" + Math.floor(Math.random() * 255) + ";" + Math.floor(Math.random() * 255) + ";" + Math.floor(Math.random() * 255);
dev[dimmerDevice]["RGB"] = dev[relayDevice + "/RGB"];
}
Добрый день!
Использовал ваш кусок кода для обработки 1-, 2-, Долгого- нажатий, все работает, но есть одна проблема, после запуска контроллера, автоматически включаются все выходы, где был использован этот код. Получается после подачи питания на щиток и загрузки контроллера, включается свет на тех реле где используется этот кусок кода (Version: 0.3.1), модули WB-MRPS6/S и WB-MDM3.
В лог выводится сообщение: LOG::Define WB Rule: on_button_press_wb-gpio_EXT5_IN10
Если закомментировать этот кусок кода: singlePress: { func: Switcher, prop: [“rele3”, “K5”] }, то после запуска контроллера свет автоматически не включается.
Значение регистра 6: 0: не восстанавливать состояние реле.
Код функции Switcher:
function Switcher(pDevace, pChanel){
dev[pDevace][pChanel] = !dev[pDevace][pChanel];
}
В чем проблема? Правила, свойствах, версии, настройки модуля?
Тут, думаю, дело в том что при апуске первым в mqtt топик приходит “null”, вызывая срабатывание. Можно либо сделать костыль, принудительно выключая все каналы реле либо исключить в скрипте обработку “null”.
Здравствуйте! Набросал код управления рулонными шторами.
defineRule(“roller cabinet down”, {
when: function(newValue, devName, cellName) {
return dev[“wb-gpio”][“EXT5_IN4”] = true;
},
then: function (newValue, devName, cellName) {
dev[“wb-gpio”][“EXT3_ON2”] = true;
dev[“wb-gpio”][“EXT3_DIR2”] = false;
}
});
Необходимо снимать напряжение с привода через Nнное время, добавил таймаут, но не работает. Снимает напряжение сразу, то есть привод не опускается.
defineRule(“roller cabinet down”, {
when: function(newValue, devName, cellName) {
return dev[“wb-gpio”][“EXT5_IN4”] = true;
},
then: function (newValue, devName, cellName) {
dev[“wb-gpio”][“EXT3_ON2”] = true;
dev[“wb-gpio”][“EXT3_DIR2”] = false;
setTimeout(function () {}, 30000);
dev[“wb-gpio”][“EXT3_ON2”] = false;
}
});
Подскажете, в чем может быть проблема?
И еще хотелось бы сделать так, чтобы при одном нажатии на кнопку штора опускалась до конца, а при повторном она останавливалась.
Не разобрался с виртуальными кнопками. Как сделать так, чтобы шторой можно было управлять через софт? Получается, мне сейчас нужно для опускания шторы вручную переключать два выключателя, а хотелось бы управлять так же, как и с реальной кнопки.
Заранее спасибо за помощь!
Здравствуйте!
Для создания кнопок в веб-интерфейсе нужно создать виртуальное устройство с помощью правил:
defineVirtualDevice("drapery_control", {
title: "Drapery Control",
cells: {
open: {
type: "switch",
value: false,
order: 1,
},
close: {
type: "switch",
value: false,
order: 2,
},
},
});
Результатом будет такое окно на странице Devices:
Сделал несколько исправлений, должно заработать:
defineRule("roller cabinet down", {
whenChanged: ["drapery_control/close", "wb-gpio/EXT5_IN4"], //правило срабатывает при активировании входа или включении кнопки в веб-интерфейсе
then: function (newValue, devName, cellName) {
if (newValue) {
dev["wb-gpio"]["EXT3_ON2"] = true;
dev["wb-gpio"]["EXT3_DIR2"] = false;
setTimeout(function () {
dev["wb-gpio"]["EXT3_ON2"] = false; //прописываем действия по истечению времени
dev["drapery_control"]["close"] = false;
}, 3000);
}
},
});
Спасибо за ответ! Буду пробовать!
Подскажите, как еще сделать так, чтобы при повторном нажатии на кнопку (хотя бы реальную) штора останавливалась в текущем положении? То есть нужно переключить “wb-gpio”][“EXT3_ON2”] в false
Доработал правило отображения ресурсов контроллера: отображается загрузка процессора, сведения об оперативной памяти, сведения о разделе rootfs и сведения об /mnt/data. В правиле используются фрагменты кода из тем на портале техподдержки, которыми поделились пользователи. Возможно, кому-нибудь будет полезным.
.
Правило во вложении.
controller_utilization.zip (1.0 KB)
Здравствуйте! Виртуальные кнопки создаются, но скрипт на них не реагирует…
defineVirtualDevice(“Roller blinds”, {
title: “Шторы”,
cells: {
Спальня_О: {
type: “switch”,
value: false,
order: 1,
},
Спальня_З: {
type: “switch”,
value: false,
order: 2,
},
},
})
;
defineRule(“roller sleeping room down”, {
whenChanged: [“Шторы/Спальня_З”, “wb-gpio/EXT5_IN8”],
then: function (newValue, devName, cellName) {
if (newValue) {
dev[“wb-gpio”][“EXT4_ON3”] = true;
dev[“wb-gpio”][“EXT4_DIR3”] = false;
setTimeout(function () {
dev["wb-gpio"]["EXT4_ON3"] = false;
dev["Шторы"]["Спальня_З"] = false;
}, 30000);
}
},
});
defineRule(“roller sleeping room up”, {
whenChanged: [“Шторы/Спальня_О”, “wb-gpio/EXT5_IN9”],
then: function (newValue, devName, cellName) {
if (newValue) {
dev[“wb-gpio”][“EXT4_ON3”] = true;
dev[“wb-gpio”][“EXT4_DIR3”] = true;
setTimeout(function () {
dev["wb-gpio"]["EXT4_ON3"] = false;
dev["Шторы"]["Спальня_О"] = false;
}, 30000);
}
},
});
Кнопки сейчас в отдельном правиле, помещал и в одно со скриптами - все равно ничего. Пробовал писать отдельное правило на виртуальные кнопки, тоже нет изменений
В условии нужно использовать имя виртуального устройcтва, а не его заголовок окна. Попробуйте так:
whenChanged: ["Roller blinds/Спальня_З", "wb-gpio/EXT5_IN8"],
Скрипт у меня такой:
defineRule(“roller sleeping room down”, {
whenChanged: [“Roller blinds/Спальня_З”, “wb-gpio/EXT5_IN8”],
then: function (newValue, devName, cellName) {
if (newValue) {
dev[“wb-gpio”][“EXT4_ON3”] = true;
dev[“wb-gpio”][“EXT4_DIR3”] = false;
setTimeout(function () {
dev[“wb-gpio”][“EXT4_ON3”] = false;
dev[“Roller blinds”][“Спальня_З”] = false;
}, 30000);
}
},
});
Получается нужно сделать так?
defineRule(“roller sleeping room down”, {
whenChanged: [“Roller blinds/Спальня_З”, “wb-gpio/EXT5_IN8”],
then: function (newValue, devName, cellName) {
if (newValue) {
dev[“wb-gpio”][“EXT4_ON3”] = false;
dev[“wb-gpio”][“EXT4_DIR3”] = false;
dev[“wb-gpio”][“EXT4_ON3”] = true;
setTimeout(function () {
dev[“wb-gpio”][“EXT4_ON3”] = false;
dev[“Roller blinds”][“Спальня_З”] = false;
}, 30000);
}
},
});
пт, 14 янв. 2022 г. в 08:40, Explorerol через Wiren Board Support <info@wirenboard.ru>:
Не совсем так. Если вы отключаете реле и сразу его снова включаете, то контакты реле ON3 не успеют до конца разомкнуться, как придет команда снова на включение. Для отключения реле обычно 10-50 миллисекунд. Поэтому лучше отключить реле ON3, затем сделать паузу для ожидания отключения реле, например 100 мс, затем уже переключить реле DIR3, опять сделать паузу, а затем снова включить ON3.
То есть было так:
dev[“wb-gpio”][“EXT4_ON3”] = false;
dev[“wb-gpio”][“EXT4_DIR3”] = false;
dev[“wb-gpio”][“EXT4_ON3”] = true;
А станет, например, так:
var delay_ms = 100
dev["wb-gpio"]["EXT4_ON3"] = false;
setTimeout(function () {
dev["wb-gpio"]["EXT4_DIR3"] = false;
}, delay_ms);
setTimeout(function () {
dev["wb-gpio"]["EXT4_ON3"] = true;
}, delay_ms * 2);
Подскажите еще: хочу сделать, чтобы при нажатии на кнопку один раз, штора доезжала до конца, при нажатии, второй раз - останавливалась. Идея такая: ввести переменную n, которая будет считать количество нажатий, то есть нажал один раз n=1, нажал второй раз n=2 и обнулилась после этого. При n=1 будет одна функция, при n=2 будет другая. Но как задать n? Если я задаю n после define rule, то выдает ошибку, если после whenchanged - тоже, если после then function, то норм, но тогда n всегда будет обнуляться при наступлении события нажатия на кнопку. У меня сейчас вот такой код:
defineRule(“roller cabinet room down”, {
whenChanged: [“Roller blinds/Кабинет_З”, “wb-gpio/EXT5_IN4”],
then: function (newValue, devName, cellName) {
if (newValue) {
dev[“Roller blinds”][“Кабинет_О”] = false;
dev[“wb-gpio”][“EXT3_ON2”] = false;
setTimeout(function () {
dev[“wb-gpio”][“EXT3_DIR2”] = false;
}, 100);
setTimeout(function () {
dev[“wb-gpio”][“EXT3_ON2”] = true;
}, 100);
setTimeout(function () {
if (“wb-gpio/EXT3_DIR2”==true) {
dev[“wb-gpio”][“EXT3_ON2”] = false;
dev[“Roller blinds”][“Кабинет_З”] = false; }
}, 30000);
}
},
});
пт, 14 янв. 2022 г. в 15:56, Explorerol через Wiren Board Support <info@wirenboard.ru>:
И еще понял, что не работает последний if. В коде не правильно написал, нужно написать if (“wb-gpio/EXT3_DIR2”==false). Это для того, чтобы, если я когда штора едет вниз, нажав на кнопку вверх, она бы не отключались по таймеру в 30 секунд с правила движения вниз. Как это правильнее реализовать?
Предлагаю вот это все прописать нормально и выложить куда-нибудь на вики. Большому количеству пользователей, типа меня, нужен стандартный набор функций устройств и чтобы они нормально работали. А то мало того, что приходятся разбираться в семантике языка, так еще и дофига тонкостей логики, которые по факту элементарные, но без опыта о них даже не думаешь.
вс, 16 янв. 2022 г. в 22:10, Андрей К <andrey.kopylov.mail@gmail.com>:
Конструкция
if (dev[“wb-gpio/EXT3_DIR2]”==true)
записывается как
if (dev[“wb-gpio/EXT3_DIR2”])
А такая:
if (dev[“wb-gpio/EXT3_DIR2”]==false)
как
if (!dev[“wb-gpio/EXT3_DIR2”])
Примененная запись вида if (“wb-gpio/EXT3_DIR2”==false) не выполнится корректно, потому что “wb-gpio/EXT3_DIR2” - это не значение топика а просто контатнта строковая. Верно: dev[“wb-gpio/EXT3_DIR2”]
И, кстати, для вставки кода советую пользоваться
``` (три символа на русской букве Ё)
Я вот смотрю и не пойму, либо вы ошиблись, либо у меня со зрением что-то не то. Вы же написали две одинаковых строки кода?
пн, 17 янв. 2022 г. в 10:07, Андрей Радионов через Wiren Board Support <info@wirenboard.ru>:
Здесь будет лежать последняя версия модуля для программной обработки разных нажатий (короткое, двойное, тройное, долгое нажатие, удержание):
/wb-rules-modules/module_ActionButtons.js
А здесь пример использования вместе со вспомогательными функциями:
/wb-rules/rules_Buttons.js
Предполагается, что вы обновили движок правил до версии 2.0