1 сообщение было перенесено в новую тему: Запись в EEPROM счетчиков нажатия
2 сообщения были перенесены в новую тему: Ложное срабатывание правила при перезагрузке контроллера
Идея интересная, но дело в том, что при подписке непосредственно на Input N могут случаться пропуски нажатий, если действие не попало в окошко запроса Modbus (это зависит от скорости и загруженности шины).
Как раз из-за этих пропусков и были введены счетчики. Они гарантированно отслеживаются, так как можно сравнить предыдущее и следующее значение.
Используя Input N как триггер на открытие “временного коридора” в 1200мс другие правила на счетчики так же будут получать пропуски нажатий.
Тогда получается единственное решение - ждать от производителя решения данной баги на уровне драйвера. Ведь даже если считать, что все устройства работают от ИБП и не бывает проблем с их физическим отвалом, то как быть при перезагрузке WB, или если завис какой-то из сервисов и произошла перезагрузка отдельного сервиса - везде всё будет моргать или включаться?) Да наверное в идиале перезагрузок быть не должно, а вот как на практике?
А есть ли в ПО какой-то доступный пользователю скрипта индикатор, что модуль отвалился или что сервис перезапустился? (Перезагрузку сервиса самих правил наверное легко отследить с помощью инициализированной переменной, или просто в фрагменте кода за пределами определения функций сделать секцию инициализации.)
И так, послу бурного обсуждения в чате постараюсь написать все заново и более конкретно:
Кратко предыстория, живу в стройке, ПНР системы провожу после работы по вечерам и ночам. В поселке тоже стройка - часто отключают электричество. Я изучил вдоль и поперек всю документацию по wb-rules и кучу веток форума.
На данный момент, в конкретно рассматриваемой ситуации используем Контроллер+MCM8+любое реле.
Изначально мной было взято типовое правило из Wiki по обработке счетчиков нажатий.
В процессе проживания обнаружил, что после отключения электроэнергии и последующим ее включением - ВСЕ правила, в которых код формата -
whenChanged: "wb-mcm8_20/Input 1 Single Press Counter"
реагируют, то есть у меня включается ВЕСЬ свет дома.
Затем обнаружил, что аналогичная ситуация происходит, когда я меняю какие либо параметры любых устройств в драйвере serial (после нажатия кнопки сохранить - происходить перегрузка драйвера с очисткой и последующим наполнением топиков устройств)
Аналогичная ситуация произошла когда я выключал/включал V-out на контроллере.
После недолгих поисков я понял в чем загвоздка: происходит очистка в null топика, а затем его наполнение (Например, в счетчике было значение 10, я перезагрузил контроллер - в топик прилетело значение null - под этим я подразумеваю полностью пустое значение в топике, потом (после загрузки) подгрузилось обратно значение 10, соответсвенно WhenChanged обработал изменение топика)
Я сделал попытку внедрить в код несколько проверок, но результата не получил. На данный момент у меня в работе используется следующий код:
Спойлер
function buttonSinglePress(name, input, output) {
var topic = input + " Single Press Counter";
var counter = dev[topic];
defineRule({
whenChanged: topic,
then: function(newValue, devName, cellName) {
log.debug("button:{} device:{}, cel:{} val={} counter={}", name, devName, cellName, newValue, counter);
if (newValue > 0 && counter !== null && newValue != counter) {
log.debug("Реле переключено {}", output);
dev[output] = !dev[output];
}
counter = newValue;
}
});
}
buttonSinglePress("tualetvent", "wb-mcm8_138/Input 4", "wb-mr6cu_43/K5");
buttonSinglePress("masterwent", "wb-mcm8_203/Input 4", "wb-mr6cu_26/K3");
buttonSinglePress("garderob", "wb-mcm8_211/Input 4", "wb-mr6cu_44/K6");
buttonSinglePress("spalnya", "wb-mcm8_211/Input 5", "wb-mr6cu_44/K3");
buttonSinglePress("zal1", "wb-mcm8_211/Input 7", "wb-mr6cu_58/K4");
buttonSinglePress("zal2", "wb-mcm8_211/Input 8", "wb-mr6cu_58/K5");
buttonSinglePress("divan2", "wb-mcm8_211/Input 2", "wb-mr6cu_58/K5");
buttonSinglePress("vhod1", "wb-mcm8_138/Input 1", "wb-mr6cu_54/K2");
buttonSinglePress("vhod2", "wb-mcm8_138/Input 2", "wb-mr6cu_54/K3");
buttonSinglePress("kuhnya-stena", "wb-mcm8_138/Input 5", "wb-mr6cu_54/K5");
buttonSinglePress("kuhnya2", "wb-mcm8_138/Input 6", "wb-mr6cu_54/K4");
buttonSinglePress("bra1", "wb-mcm8_203/Input 1", "wb-mr6cu_53/K5");
buttonSinglePress("bra2", "wb-mcm8_203/Input 7", "wb-mr6cu_53/K2");
buttonSinglePress("detskay", "wb-mcm8_138/Input 7", "wb-mr6cu_58/K3");
buttonSinglePress("detskay", "wb-mcm8_138/Input 8", "wb-mr6cu_58/K2");
По сути, от правила я ожидаю, что оно отработает только когда значение счетчика увеличилось (даже если принять редкий пропуск сработки при переполнении счетчика) и не будет реагировать на какие-либо служебны ситуации вроде перегрузки контроллера - возвращаясь к примеру где было 10 - потом null - потом опять 10, ведь по факту “полезное” значение счетчика осталось без изменений.
Проблема сохраняется. Прошу о помощи…
Так не хотите попробовать? Чтобы в правила не летел всякий непредсказуемый мусор, пока вся система не загрузится
Данное решение исправляет ситуацию с перезагрузкой - но когда происходит перезапуск serial, или пропадает питания конкретно модуля MCM8 - нет
Изначально же и была озвучена проблема, что у вас при повторном включении электричества включается весь свет.
Перезапуск Serial уже контролируемый процесс ПНР
Я вроде в 26 сообщении указал не только перезагрузку
Это я видел, но мне показалось справедливым отделить ПНР от перезагрузки по независящим причинам - из сообщения №1
Я тоже обращал внимание, что мне в Телегу летят уведомления о протечках с WB-MWAC при перезагрузке Serial.
Но это не сильно парит, так как контролируемый процесс.
По справедливости я бы тоже внес предложение в библиотеке WhenChanged внести исключение в обработку поступления значения null
хотя это очередной костыль, но можно попробовать анализировать регистр
104-105 0x0068 - 0x0069 Input RO u32 Время работы с момента загрузки секунды
игнорируя первые 2-5 секунд.
Добрый день! В понедельник коллеги смогут заняться подробнее, пока пара замечаний.
-
Кажется, вызов правила по whenChanged со значением newValue==null - это баг. Это значение отправляется сервисом wb-mqtt-serial при завершении и должно вызывать удаление устройства, а не вызов правила. Проверим, исправим.
-
Обработку переполнения и всего остального можно сделать, сохраняя предыдущее состояние. Например, так:
defineRule({
whenChanged: "myvdev/counter1",
then: function (newValue, devName, cellName) {
log("срабатывание правила newValue: {}, was: {}".format(newValue, this.prevValue));
// игнорируем сообщение при выгрузке wb-mqtt-serial: 123 => null
if (newValue === null) return;
// загрузка wb-mqtt-serial восстановление предыдущего значения, null => 123. Игнорируем, только если значение не изменилось. Если изменилось - было нажатие перед загрузкой драйвера.
if (newValue == this.prevValue) return;
// ноль мог прийти после перезагрузки modbus-устройства по питанию, а мог из-за переполнения
// ожидаем переполнения, только если счётчик был близок к пределу 16 бит
if (newValue == 0) {
if (this.prevValue < (65536 - 5)) {
return;
}
}
log("тут обработка нажатия!");
this.prevValue = newValue; // эта строчка должна быть в конце
}
});
Важно №1: у меня не получилось воспроизвести неправильную срабатывания правила с null.
Важно №2: пожалуйста, приложите диагностический архив, как мы вас просили.
Добрый день! Прикладываю диагностический архив.
Мне кажется проблема не в newValue==null (которую легко побороть одной проверкой на null) а именно в последующем значении параметра, то есть было null - стало не null.
Сегодня ночью проснулся о. того что во всей квартире опять горел свет -_-
На счет:
Важно №1 : у меня не получилось воспроизвести неправильную срабатывания правила с null.
У вас не отрабатывает мое правило при перегрузке контроллера/изменении параметров serial?
Добрый день.
Мы пока глобально разбираемся в проблеме.
Как временное решение, было предложено исключить все условия ложного срабатывания правила.
Вы пробовали применить этот скрипт у себя?
Если что, поправил под вашу задачу и чуть-чуть доработал:
/* 1. Одиночное нажатие на включение*/
function button(name, input, output) {
defineRule({
whenChanged: input + " Single Press Counter",
then: function (newValue, devName, cellName) {
log("срабатывание правила newValue: {}, output: {}, this.prevValue: {}".format(newValue, output, this.prevValue));
if (newValue === null || newValue == this.prevValue) return;
if (newValue == 0 && this.prevValue < (65536 - 5)) return;
if (newValue == 0 && !this.prevValue) return;
dev[output] = !dev[output];
this.prevValue = newValue;
}
});
}
У меня прошли следующие тесты:
- Перезапуск wb-mqtt-serial
(Поведение: состояние выходов сохраняется) - Перезагрузка контроллера
(Поведение: состояние выходов сохраняется) - Перезапуск wb-rules
(Поведение: состояние выходов сохраняется) - Отключение питания модулей (V_Out On → Off → On)
(Поведение: состояние выходов не сохраняется, но и не переключается, все выходы в выключенном состоянии)
P.S. null я тоже не смог отловить.
Круто! Наличие this.prevValue
позволяет элегантно решить вопрос! Не нашел этого в документации. Это незадокументированная фича? Какое у него значение? Предыдущее значение топика?
prevValue реально звучит как то что искал пару месяцев, спрашивал в чате несколько раз. Очень жаль что про данный параметр не прописано в wiki и на gite, это бы решало много проблем, завтра накачу на контроллере Ваше правило и постараюсь протестировать, дам обратную связь
Это просто определение переменной в контексте. this: контекст выполнения функций — JavaScript — Дока
А, т.е. это то же что предлагалось через
function buttonSinglePress(name, input, output) {
var counter = dev[topic];
....
только не через замыкание, а через this.prevValue.
Тогда проблема остается, в случае с перезагрузкой драйвера, если prevValue ни разу не сохранялся (например, перегрузить контроллер и потом драйвер, либо перезагрузить wb-rules - потом драйвер).
При перезапуске драйвера в whenChanged приходит newValue: 10, this.prevValue: undefined
.
В итоге мы получаем переключение.
Тестовый код
function button(name, input, output) {
log("--- Определение правила button [{}] input: {}, output: {}",name, input, output);
defineRule({
whenChanged: input + " Single Press Counter",
then: function (newValue, devName, cellName) {
log(">>> Cрабатывание правила button [{}] input: {}/{}, newValue: {}, output: {}, this.prevValue: {}",name, devName, cellName, newValue, output, this.prevValue);
if (newValue === null || newValue == this.prevValue) return;
if (newValue == 0 && this.prevValue < (65536 - 5)) return;
if (newValue == 0 && !this.prevValue) return;
log("!!! Переключаем состояние dev['{}']".format(output));
//dev[output] = !dev[output];
this.prevValue = newValue;
}
});
}
button("test button", "wb-mr6c_75/Input 1", "test_output" );
Лог после перезагрузки контроллера, потом драйвера
-- Boot 464238ed115e485b8057d5f7412868b1 --
Apr 10 10:38:03 wirenboard-AC6A3GB6 systemd[1]: Started MQTT Rule engine for Wiren Board.
Apr 10 10:38:03 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: broker URL is default and mosquitto socket detected, trying to connect via it
Apr 10 10:38:03 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: driver is created
Apr 10 10:38:03 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [wbgo_mqtt] rules-wirenboard-AC6A3GB6-4294: MQTT connection established
Apr 10 10:38:04 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: driver loop is started
Apr 10 10:38:04 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: wait for driver to become ready
Apr 10 10:38:08 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: driver is ready
Apr 10 10:38:08 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [rule info] using file /var/lib/wirenboard/wbrules-persistent.db for persistent DB
Apr 10 10:38:08 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [wbgo_mqtt] wb-rules-engine-wirenboard-AC6A3GB6-4294: MQTT connection established
Apr 10 10:38:08 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [engine] Starting main loop
Apr 10 10:38:08 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: the engine is ready
Apr 10 10:38:08 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [engine] Starting sync loop
Apr 10 10:38:10 wirenboard-AC6A3GB6 wb-rules[4294]: WARNING: [device] Unknown metadata for device metrics: 'error'
Apr 10 10:38:11 wirenboard-AC6A3GB6 wb-rules[4294]: WARNING: [rule warning] DAC: no config file
Apr 10 10:38:12 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [rule info] --- Определение правила button [test button] input: wb-mr6c_75/Input 1, output: test_output
Apr 10 10:38:12 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [rule info] _update_git_status started!
Apr 10 10:38:12 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [rule info] add your rules to /etc/wb-rules/
Apr 10 10:38:13 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: all rule files are loaded
Apr 10 10:39:12 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [rule info] _update_git_status started!
Apr 10 10:40:11 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [rule info] _update_git_status started!
Apr 10 10:40:21 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [rule info] >>> Cрабатывание правила button [test button] input: wb-mr6c_75/Input 1 Single Press Counter, newValue: 10, output: test_output, this.prevValue: undefined
Apr 10 10:40:21 wirenboard-AC6A3GB6 wb-rules[4294]: INFO: [rule info] !!! Переключаем состояние dev['test_output']
Лог после перезагрузки правил, потом драйвера
Apr 10 10:45:10 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: driver is created
Apr 10 10:45:10 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [wbgo_mqtt] rules-wirenboard-AC6A3GB6-11664: MQTT connection established
Apr 10 10:45:10 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: driver loop is started
Apr 10 10:45:10 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: wait for driver to become ready
Apr 10 10:45:11 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: driver is ready
Apr 10 10:45:11 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [rule info] using file /var/lib/wirenboard/wbrules-persistent.db for persistent DB
Apr 10 10:45:11 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [wbgo_mqtt] wb-rules-engine-wirenboard-AC6A3GB6-11664: MQTT connection established
Apr 10 10:45:11 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [engine] Starting main loop
Apr 10 10:45:11 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [engine] Starting sync loop
Apr 10 10:45:11 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: the engine is ready
Apr 10 10:45:12 wirenboard-AC6A3GB6 wb-rules[11664]: WARNING: [rule warning] DAC: no config file
Apr 10 10:45:12 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [rule info] --- Определение правила button [test button] input: wb-mr6c_75/Input 1, output: test_output
Apr 10 10:45:12 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [rule info] _update_git_status started!
Apr 10 10:45:12 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [rule info] add your rules to /etc/wb-rules/
Apr 10 10:45:12 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: all rule files are loaded
Apr 10 10:45:38 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [rule info] >>> Cрабатывание правила button [test button] input: wb-mr6c_75/Input 1 Single Press Counter, newValue: 10, output: test_output, this.prevValue: undefined
Apr 10 10:45:38 wirenboard-AC6A3GB6 wb-rules[11664]: INFO: [rule info] !!! Переключаем состояние dev['test_output']
Да. Но зачем переменную определять до фактического выполнения? Неопределенная переменная - это маркер первого срабаттывания что тут и показано.
А как часто такое происходит и из-за чего может быть? То есть какой сценарий возникновения?