Округлить - можно и скриптом, ну и отдать внешнему сервису значения из виртуального устройства.
Но и в самом шаблоне тоже предусмотрен механизм, отлично описано тут:
Округлить - можно и скриптом, ну и отдать внешнему сервису значения из виртуального устройства.
Но и в самом шаблоне тоже предусмотрен механизм, отлично описано тут:
Спасибо, в таком виде отрабатывает хорошо, за исключением выключение
"name" : "Channel 00",
"reg_type" : "holding",
"address" : 3004,
"type": "value",
"max": 100,
"min": 0,
"round_to": 1,
"scale" : 0.583,
"offset" : -48,
"readonly" : true,
"format": "u16"
Не подскажете, как лучше реализовать передачу нуля в устройство?
Попробуйте использовать:
"off_value": 0,
Попробовал, при 0 свет все равно горит (хоть и на минимальной яркости).
Еще обнаружил проблему в виде “прилета” значений из соседних регистров:
Данные в регистрах 3004 и 3009 (Запрос текущего уровня яркости индивидуального устройства) - “пляшут”. Мне кажется, они подтягиваются из “соседнего” регистра, т.е. если у меня нулевой светильник (адрес 3004) установлен на 23, а первый (адрес 3009) на 5, То в нулевой иногда прилетает 5, а держится 23. То же самое и с первым, только у него установлено 5, но иногда прилетает 23. Не сталкивались с таким поведением?
modbus_client --debug -mrtu -b19200 -pnone -s1 /dev/ttyRS485-2 -a21 -t0x03 -r3004
то в ответ всегда приходит 0x00a0 (160 в десятичном), что верно. Тогда мне не понятно, почему wb-mqtt-serial получает другие, соседние значения??
Интересное наблюдение, как только убрал
"max": 100,
"min": 0,
"round_to": 1,
"scale" : 0.583,
"offset" : -48,
проблема с считыванием соседних значений пропала. Может подскажите, как с помощью правила можно создать виртуальное устройство, которое будет равно 0-100, и при изменении своего значения - будет отправлять в реальный адрес шлюза данные с учетом того что:
0=0
1-86=1%
254=100%
Спасибо за помощь (нет), добился управления в фэб интерфейсе WB. Но теперь другая проблема. Не происходит сработка правила, если значение вирт устройства меняется через MQTT. Пробовал и с /on и напрямую в топик. В интерфейсе значение меняется, а правило не срабатывает. Подскажите, как решить проблему??
var hkmin = 0;
var hkmax = 100;
var dalimin = 86;
var dalimax = 254;
var p;
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;
}
}
});
кусок кода, который “слушает” значение в устройстве /devices/dimmer2/controls/value
Тут нет виртуального устройства. Я создал и попробовал воспроизвести
Не воспроизводится. Правило отрабатывает. Дайте скрипт полный, воспроизводящий проблему.
пока вышел из положения вот таким вот костылём:
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;
}
});
Весь скрипт выглядит так:
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 - работает не стабильно. Завтра продолжу эксперименты, Если подскажите способ оптимизировать правило, или всю задачу - буду признателен.
Взял ваше правило и виртуальное устройство. Для поля value
добавил атрибут readonly: false
для возможности его изменения:
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, // значение по умолчанию
readonly: false // добавил для возможности редактирования поля
},
saved: {
type: "value", // тип (.../meta/type)
value: 100 // значение по умолчанию
},
}
});
var hkmin = 0;
var hkmax = 100;
var dalimin = 86;
var dalimax = 254;
var p;
defineRule("simple_folow", {
whenChanged: "dimmer2/value",
then: function (newValue, devName, cellName) {
log.info("Вход в функцию, value = " + newValue);
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;
log("p = " + p);
}
}
});
Публикую в топик /devices/dimmer2/controls/value/on
новое значение - получаю срабатывание правила.
Мы поддержали шлюз ECOdim DALI GW2, подробнее читайте в документации.