Экземпляры мигалок на Timer

safonik
Kilpio
Очень ценю вашу помощь!

В окончательном виде код получился такой:

var cycle = 3 * 1000;
heater_pwm ("heater_1", 0, 1, "wb-gpio/A1_OUT");
heater_pwm ("heater_2", 1, 1, "wb-gpio/A2_OUT");
heater_pwm ("heater_3", 2, 1, "wb-gpio/A3_OUT");

startTicker("period", cycle); // основной цикл переключений

function heater_pwm (name, delay_sec, on_sec, relay){
	var count = 0;											// контроль непрерывности работы
	var timer1Name = "timer1_" + name;						// задаем уникальное текстовое значение имени таймера внутри каждого экземпляра функции
	var timer2Name = "timer2_" + name;						// задаем уникальное текстовое значение имени таймера внутри каждого экземпляра функции
	defineRule("pwmCycle_" + name, {						// правило для запуска таймера на окончание "положительной" полуволны
		when: function () { return timers.period.firing; }, // начало отсчета основного цикла
		then: function () { 
			log(count++);
			startTimer(timer1Name, delay_sec * 1000);  		// запустили таймер на отключение "положительной" полуволны	
			timers[timer1Name].name = timer1Name;			// присвоили уникальное имя таймеру, чтбы его окончание отследить
		}
	});
	defineRule("pwmDelay_" + name, {
		when: function () { return timers[timer1Name].firing; }, // отследили срабатывание таймера на задержку начала "положительной" полуволны
		then: function () { 
			dev[relay] = 1;									// включили "положительную" полуволну
			startTimer(timer2Name, on_sec * 1000);  		// запустили таймер на отключение "положительной" полуволны	
			timers[timer2Name].name = timer2Name;			// присвоили уникальное имя таймеру, чтбы его окончание отследить
		}
	});	
		defineRule("pwmOn_" + name, {
		when: function () { return timers[timer2Name].firing; }, // отследили срабатывание таймера на окончание "положительной" полуволны
		then: function () {
			dev[relay] = 0;									// закончили "положительную" полуволну
		}
	});	
}

С такими параметрами можно использовать для “бегущих огней” :slight_smile:
Обнаружил, что если частоту переключения поставить слишком большую (период 0,5 сек), то рано или поздно контроллер зависает.

Может быть посоветуете диагностический инструмент, чтобы отследить какой параметр достигает предельного? Пока подозреваю температуру процессора, так как она в этом режиме переваливает за 62 градуса.

Рад, что мы смогли со всем этим разобраться!

Завешивание контроллера движком правил – неприятная проблема. Первое, что можно подозревать – это утечки памяти. Второе – перегрев. Я попробую воспроизвести проблему с вашим правилом, а вы можете смотреть в консоли за загрузкой процессора и потреблением памяти с помощью top, также интересно, появляется ли какая-то информация в отладочной консоли (USB Debug Console).

htop загрузку памяти и процессора указывает на приемлемые (в пределах 20-30%).

USB Debug Console это то что в WebUI внизу появляется при нажатии Rule debugging?

2018-12-19 12:43:31 19
2018-12-19 12:43:31starting timer: timer1_heater_1
2018-12-19 12:43:31 19
2018-12-19 12:43:31starting timer: timer1_heater_2
2018-12-19 12:43:31 19
2018-12-19 12:43:31starting timer: timer1_heater_3
2018-12-19 12:43:31starting timer: timer2_heater_1
2018-12-19 12:43:32starting timer: timer2_heater_2
2018-12-19 12:43:32starting timer: timer2_heater_3
2018-12-19 12:43:32 20
2018-12-19 12:43:32starting timer: timer1_heater_1
2018-12-19 12:43:32 20
2018-12-19 12:43:32starting timer: timer1_heater_2
2018-12-19 12:43:32 20
2018-12-19 12:43:32starting timer: timer1_heater_3
2018-12-19 12:43:32starting timer: timer2_heater_1
2018-12-19 12:43:32starting timer: timer2_heater_2
2018-12-19 12:43:32starting timer: timer2_heater_3

Я имел в виду то, что вы получите в терминале, подключившись к отладочной консоли USB/UART.
При падении иногда ядро успевает что-то интересное написать туда.

В этой консоли никакой информации нет.

Именно поэтому и хотел спросить про дополнительные инструменты, которые вы используете в работе в консоли, кроме htop.

var cycle = 3 * 1000;
var count = 0;                                                            // контроль непрерывности работы
// основной цикл переключений
setInterval(function () {
log(count++);
heater_pwm("heater_1", 0, 1, "wb-gpio/A1_OUT");
heater_pwm("heater_2", 1, 1, "wb-gpio/A2_OUT");
heater_pwm("heater_3", 2, 1, "wb-gpio/A3_OUT");
}, cycle);
function heater_pwm(name, delay_sec, on_sec, relay) {
setTimeout(function () {
    log("Включение положительной полуволны для " + name);
    dev[relay] = 1;                                                   // включили "положительную" полуволну
    setTimeout(function () {
        log("Отключение положительной полуволны для " + name);
        dev[relay] = 0;                                               // закончили "положительную" полуволну
    }, on_sec * 1000);                                        // запустили таймер на отключение "положительной" полуволны
}, delay_sec * 1000);                                         // запустили таймер на включение "положительной" полуволны                                        
}

Попробуйте так, без использования таймеров - будет тормозить меньше?

Такой вариант значительно изящнее.
Я его также использовал, только не догадался вызов функций осуществлять в периодическом цикле, а все-таки ловил его запуск.
Но все-равно правило “крутится” только определенное количество циклов от 50 до 100, а затем зависает.
К тому же, если во время работы программы поменять параметры, то одни таймеры накладываются на другие (оставшиеся от предыдущих параметров) и начинается хаос.
То есть не чистятся старые таймеры.

Это странно. С какими значениями параметров зависает?

Да. Как при изменении параметров останавливать запланированные setInterval и setTimeout идей нет. Тут похоже поможет только рестарт движка правил при изменении значений в скриптах, или делать на таймерах.
Лучше не менять значения в коде скриптов, а вынести это в виртуальные устройства и менять у них параметры через UI/MQTT, и в правилах при изменении этих значений останавливать старые таймеры и запускать новые с новыми значениями.

Да, не зная номер таймаута или интервала я не смог грохнуть прошлый экземпляр. Только ребут помогал. Решение “влоб”, к ни странно, помогло:
for (var i = 0;i<20;i++)
{
log("сбиваю интервал " + i);
clearInterval(i);
clearInterval(interval_id);
}

Присоединяюсь к вопросу. Есть ли возможность видеть наполнение памяти, например, или еще что-то, что позволит хотя бы таймеры отследить - появляются новые или нет? А то переполнят и завесят через месяц wb…

Таких инструментов, насколько мне известно, нет. Но помогает перезагрузка движка правил по крону )

перегружаются только правила или целиком ребутится? Пожалуйста, если есть такое, скиньте пример, наверняка в документации есть, но я не помню такого…

service wb-rules restart

дистанционно, по внешней команде
может в скрипте можно “выполнить” из комм строки что-то?

runShellCommand()

Ясно, буду изучать. Видите, мне не очень знакомы эти технологии, только собираю знания. Если у меня не получится самому, обращусь за уточнениями. Спасибо!

Какое свойство таймера можно проверить, чтобы понять запущен он уже или нет?
Чтобы избежать повторного его перезапуска при наступлении события еще раз.

Flagman, добрый день!
К сожалению, у таймера только одно свойство, firing:

startTimer("test", 10000);
str = JSON.stringify(timers.test);
log(str);

->

2019-08-14 15:50:48 starting timer: test
2019-08-14 15:50:48 {"firing":false}

Я бы делал через таймерные функции с коллбеками, и состояние отслеживал бы флагами.

Тоже обратил на это внимание и не смог найти ответа на форуме.
Пример аналогично взял тут: https://wirenboard.com/wiki/index.php?title=Rule_Examples)

Как должна работать эта конструкция?:

if (motion_timer_1_id) {
      clearTimeout(motion_timer_1_id);
   }

точнее так: для чего она, если сюда мы никогда не попадаем (внутри конструкции ставил вывод в лог - увидел, что никогда не проходим через это место) ?

Попробовал принудительно в if в этой строке заменить “motion_timer_1_idt” на “true” и получил ошибку:

2020-05-25 20:38:43ECMAScript error: Error: error error (rc -100)
anon native strict preventsyield
clearTimeout /usr/share/wb-rules-system/scripts/lib.js:225
anon /etc/wb-rules/rules.js:178 preventsyield
call native strict preventsyield
anon /usr/share/wb-rules-system/scripts/lib.js:173 preventsyield

Потому что clearTimeout попытался очистить таймер, которого не было.

Задумка понятная: если сейчас таймер, после которого свет выключится, запущен, а датчик показывает движение, то этот таймер нужно отключить, и потом пересоздать заново.
Но в самом правиле в примере действительно была допущена ошибка: запускать таймер нужно не в момент включения датчика движения, а в момент отключения. А вот удалять - действительно в момент включения.
Ещё одной проблемой было, что устройствам типа switch начиная со второй версии движка правил нельзя присваивать 0 или 1, а можно только true или false.
Сейчас исправил код в примере на верный: Примеры правил — Wiren Board