Как сделать правило, работающее по времени

Мне нужно включать реле каждый день с 23 вечера до 7 утра.
Как это сделать и где взять сигнал точного времени?

Можно написать правило которое запускается с периодом раз в 5 сек. а уже в этом правиле проверять текущее время.

Текущее время в коде правил можно получить создав переменную типа Date

d = new Date();

Описание доступных методов объекта типа Date можно посмотреть тут: Дата и время

2 лайка

Собственно ответ уже есть.
Этот же подход применен в Помогите пожалуйста с подбором и настройкой оборудования для теплиц - #347 от пользователя BrainRoot
Ну а использование просто cron тут: Примеры правил — Wiren Board

Что-то не получается.
Я сделал виртуальное устройство.
В нём есть свойство время и правило, срабатывающее раз в минуту, которое должно загружать в топик BoilerTermostat/Time значение текущего часа.
Но топик BoilerTermostat/Time у меня постоянно пустой.

Также пустыми выглядят и топики
BoilerTermostat/Hysteresis хотя в нём в скрипте указано значение 20
BoilerTermostat/RelayState и BoilerTermostat/Temperature хотя они должны принимать значения BoilerTemperature и BoilerRelay.
Допустим температура не менялась за время моего наблюдения, но реле я вручную переключал несколько раз из списка устройств и тишина.

var BoilerTemperature = "wb-mai6_51/IN 1 P Temperature";
var BoilerRelay = "wb-mio-gpio_70:4/K1"; 
var time = new Date(); //Текущее время

defineVirtualDevice("BoilerTermostat", {
    title: "Термостат бойлера",
    cells: {
      Name: {
        title: "Название",
        type: "text",
        value: "Бойлер"
      }, 
      ON_OFF: { // активация термостата 0-выкл 1-включен
        title: "Выключатель",
        type: "switch",
        value: false,
      }, 
      Mode: { // режим 0-ручной 1-по расписанию с 23 вечера до 7 утра
        title: "Работа по расписанию",
        type: "switch",
        value: false,
      },
      Temperature: {
        title: "Температура",
        type: "text",
        value: "",
        units: "deg C",
        precision: 2
      },
      Setpoint: { // уставка
        title: "Уставка",
        type: "range",
        value: 50,
          min: 20,
          max: 70,
        readonly: false
      },
      Hysteresis: {
        title: "Гистерезис",
        type: "number",
        value: 20
      },
      RelayState: { // состояние реле 0-ожидание (ВЫКЛ) 1-нагрев (ВКЛ)
        title: "Состояние реле",
        type: "text",
        value: false,
      },
      Lock: { // блокировка в визуализации 0-снята 1-заблокирована
        title: "Блокировка изменений",
        type: "switch",
        value: false,
      },
      Time: {
        title: "Время",
        type: "text",
        value: ""
      }
  }
});


defineRule("ThermostatTopics", { 
  whenChanged: [BoilerTemperature, BoilerRelay], 
  then: function (newValue, devName, cellName) {
        dev['BoilerTermostat/Temperature'] = dev[BoilerTemperature];
        dev['BoilerTermostat/Relay'] = dev[BoilerRelay];
  }
});


defineRule("cron minute timer", { // задание, которое выполняется каждую минуту
  when: cron("00 * * * * *"),
  then: function () {
    dev['BoilerTermostat/Time'] = time.getHours();
  }
});

Пытаетесь записать number в поле типа text.

//09_15_test_02.js
var time = new Date(); //Текущее время
log.info("time=", time, "time.getHours()=", time.getHours())
log.info("тип time.getHours()=", typeof(time.getHours()))

изменил правило вот так, но всё равно не работает

defineRule("cron minute timer", { // задание, которое выполняется каждую минуту
  when: cron("00 * * * * *"),
  then: function () {
    dev['BoilerTermostat/Time'] = time.getHours();
    log.info(" time =", time, "time.getHours() =", time.getHours())
    log.info(" тип time.getHours() =", typeof(time.getHours()))    
  }
});
  1. Тип данных BoilerTermostat/Time и time.getHours() совпадает, но в топик ничего не записывается, хотя на скриншоте видно, что уже 2 раза сработало правило
  2. Почему время по Гринвичу, а не по Москве?

А как вообще время и tz настроено? Тут контроллер совершенно (кроме RTC) не отличается от компьютера.

TZ изменил через консоль.
А по первому вопросу что? В логе никаких ошибок нет.

Явно укажите для него “readonly: false”

не помогает

Единственное изменение - теперь это поле стало редактируемым в виджете, но пустое.
Значения в него не прилетают, а руками можно вписать что угодно

image

Screenshot_20230915_170508

//09_15_test_02.js
var time = new Date(); //Текущее время

defineVirtualDevice("BoilerTermostat", {
    title: "Термостат бойлера",
    cells: {
      Time: {
        title: "Время",
        type: "value",
        value: "",
        readonly: false
      }
  }
});


defineRule("cron minute timer", { // задание, которое выполняется каждую минуту
  when: cron("00 * * * * *"),
  then: function () {
    dev['BoilerTermostat/Time'] = time.getHours();
    log.info(" time =", time, "time.getHours() =", time.getHours())
  }
});

Screenshot_20230915_170508

type: “value” вместо type: “number” работает.
Я ориентировался на типы javascript поскольку у вас везде ссылки на него и по поводу типов ничего особо не написано.

Разве что тут:

Ссылка на список - из документации

на этой странице есть какой-то огрызок кода с такой строкой и всё

// Control's type
    "type": "value",

Что это, зачем и почему непонятно.

Кроме того тут ещё есть вот это. Тоже непонятно. Вообще никаких пояснений

"precision": 0.1,

Если мне нужно 1 цифру после запятой, то надо написать сюда 0,1? Это так переводится?
Я вообще-то думал один знак после запятой “precision”: 1,, два знака “precision”: 2, и так далее

Даже на базовые вещи нет никакой справки

В общем теперь виртуальный термостат вроде работает. По крайней мере его свойства заполняются значениями, но основная его функция - включать и выключать ТЭН не работает.
Пока что для простоты условия со расписанием убрал из кода.

На скриншоте видно, что термостат включен, текущая температура 58,8, требуемая температура 70, гистерезис 5.
То есть ТЭН должен был включиться, но он выключен.

var time = new Date(); //Текущее время
var name = "BoilerTermostat/Name";
var onoff = "BoilerTermostat/ON_OFF"
var scheduleMode = "BoilerTermostat/ScheduleMode"
var setpoint = "BoilerTermostat/Setpoint"
var hysteresis = "BoilerTermostat/Hysteresis"
var BoilerTemperature = "wb-mai6_51/IN 1 P Temperature";
var BoilerRelay = "wb-mio-gpio_70:4/K1"; 




defineVirtualDevice("BoilerTermostat", {
    title: "Термостат бойлера",
    cells: {
      Name: {
        title: "Название",
        type: "text",
        value: "Бойлер",
      }, 
      ON_OFF: { // активация термостата 0-выкл 1-включен
        title: "Выключатель",
        type: "switch",
        value: false,
      }, 
      ScheduleMode: { // режим 0-ручной 1-по расписанию с 23 вечера до 7 утра
        title: "Работа по расписанию",
        type: "switch",
        value: false,
      },
      Temperature: {
        title: "Температура",
        type: "text",
        value: "",
        units: "deg C",
        precision: 2,
      },
      Setpoint: { // уставка
        title: "Уставка",
        type: "range",
        value: 50,
          min: 20,
          max: 70,
        readonly: false,
      },
      Hysteresis: {
        title: "Гистерезис",
        type: "range",
        value: 10,
          min: 5,
          max: 20,
        readonly: false,     
      },
      RelayState: { // состояние реле 0-ожидание (ВЫКЛ) 1-нагрев (ВКЛ)
        title: "Состояние реле",
        type: "text",
        value: false,
      },
      Lock: { // блокировка в визуализации 0-снята 1-заблокирована
        title: "Блокировка изменений",
        type: "switch",
        value: false,
      },
      Time: {
        title: "Время",
        type: "value",
        value: "",
      }
  }
});



defineRule("BoilerTemperature", { 
  whenChanged: BoilerTemperature, 
  then: function (newValue, devName, cellName) {
    dev['BoilerTermostat/Temperature'] = newValue;
    SendTelegramMsg( 'BoilerTermostat/Temperature = ' + newValue );
  }
});


defineRule("BoilerRelay", { 
  whenChanged: BoilerRelay, 
  then: function (newValue, devName, cellName) {
    if (newValue == true) { dev['BoilerTermostat/RelayState'] = "включено"; }
    if (newValue == false) { dev['BoilerTermostat/RelayState'] = "выключено"; }
    SendTelegramMsg( 'BoilerTermostat/RelayState = ' + newValue );
  }

});



defineRule("cron minute timer", { // задание, которое выполняется каждую минуту
  when: cron("00 * * * * *"),
  then: function () {
    var currentHour = time.getHours();
    dev['BoilerTermostat/Time'] = currentHour;
    SendTelegramMsg( 'currentHour = ' + currentHour );
    }
});




defineRule("BoilerThermostatController", {
  whenChanged: [onoff, scheduleMode, setpoint, BoilerTemperature, hysteresis], 
  then: function (newValue, devName, cellName) {

 
    SendTelegramMsg('Температура ' + dev[BoilerTemperature] + ', Настройка ' + dev[setpoint] + ', Гистерезис ' + dev[hysteresis] + ', Положение реле ' + dev[BoilerRelay] + ', Термостат ' + dev[onoff] + ', Расписание ' + dev[scheduleMode]);
    log.info('Температура ' + dev[BoilerTemperature] + ', Настройка ' + dev[setpoint] + ', Гистерезис ' + dev[hysteresis] + ', Положение реле ' + dev[BoilerRelay] + ', Термостат ' + dev[onoff] + ', Расписание ' + dev[scheduleMode]);
    log.info(" time =", currentHour)

	if (dev[onoff]) {  // если термостат включён

      // тут ТЭН нельзя включать вручную
      // то есть в виджете НЕ  
      // выключатель реле "wb-mio-gpio_70:4/K1" должен быть спрятан 
      // или виден, но заблокирован



      	if ( dev[BoilerTemperature] < dev[setpoint] - dev[hysteresis] ) { // если температура датчика меньше уставки - гистерезис
        	dev[BoilerRelay] = true;
          SendTelegramMsg( dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + '. Начался нагрев.');
      	}

      	if ( dev[BoilerTemperature] = dev[setpoint] ) { //если температура датчика достигла уставки выключить нагрев
        	dev[BoilerRelay] = false;
          SendTelegramMsg( dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + '. Нагрев остановлен.');
      	}

        if ( dev[BoilerTemperature] > dev[setpoint] ) { //если температура датчика больше уставки выключить нагрев
          dev[BoilerRelay] = false;
          SendTelegramMsg( 'ВНИМАНИЕ ПЕРЕГРЕВ. ' + dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + '. Нагрев остановлен. Превышение температуры. Необходимо проверить' + dev[name] + ' .');
        }



  }

  else { dev[BoilerRelay] = false; } // если термостат выключён, то нагрев не работает

  }

});



Не понятно. Что вы ожидаете, что происходит? Точнее - какого поведения от какой части кода ожидаете?
Я - откровенно плохой программист, поэтому для отладки пользуюсь, обычно выводом в лог, отслеживая как зхначения данных, их типы так и ветвления.

Сделал вывод в лог всех изменяемых значений правила BoilerThermostatController и там какие-то красные ошибки.
Что это?
При этом вроде необходимые данные прилетают в лог.

Насколько я понял значение currentHour не видно в правиле BoilerThermostatController.
Но оно мне там будет нужно для логики включения ТЭНа по расписанию.
Как его туда передать?

проблема действительно в этой переменной currentHour, которая не определена внутри правила BoilerThermostatController

При изменении кода вот таким образом всё стало работать.
Но тут получается, что время не вычисляется раз в минуту.
Оно вычисляется только в момент срабатывания правила BoilerThermostatController, то есть
whenChanged: [onoff, scheduleMode, setpoint, BoilerTemperature, hysteresis]

Может и не сильно страшно, потому как если подумать, то пока идёт нагрев постоянно изменяется температура.
Я посмотрел по логам примерно пару раз в минуту повышается на 0,1 градус и соответственно запускается правило.
Потом температура достигает предела и ТЭН отключается. В этот промежуток времени мне вообще не важно какой сейчас час.

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

var time = new Date(); //Текущее время
var name = "BoilerTermostat/Name";
var onoff = "BoilerTermostat/ON_OFF"
var scheduleMode = "BoilerTermostat/ScheduleMode"
var setpoint = "BoilerTermostat/Setpoint"
var hysteresis = "BoilerTermostat/Hysteresis"
var BoilerTemperature = "wb-mai6_51/IN 1 P Temperature";
var BoilerRelay = "wb-mio-gpio_70:4/K1"; 



defineVirtualDevice("BoilerTermostat", {
    title: "Термостат бойлера",
    cells: {
      Name: {
        title: "Название",
        type: "text",
        value: "Бойлер",
      }, 
      ON_OFF: { // активация термостата 0-выкл 1-включен
        title: "Выключатель",
        type: "switch",
        value: false,
      }, 
      ScheduleMode: { // режим 0-ручной 1-по расписанию с 23 вечера до 7 утра
        title: "Работа по расписанию",
        type: "switch",
        value: false,
      },
      Temperature: {
        title: "Температура",
        type: "text",
        value: "",
        units: "deg C",
        precision: 2,
      },
      Setpoint: { // уставка
        title: "Уставка",
        type: "range",
        value: 50,
          min: 20,
          max: 70,
        readonly: false,
      },
      Hysteresis: {
        title: "Гистерезис",
        type: "range",
        value: 10,
          min: 5,
          max: 20,
        readonly: false,     
      },
      RelayState: { // состояние реле 0-ожидание (ВЫКЛ) 1-нагрев (ВКЛ)
        title: "Состояние реле",
        type: "text",
        value: false,
      },
      Lock: { // блокировка в визуализации 0-снята 1-заблокирована
        title: "Блокировка изменений",
        type: "switch",
        value: false,
      },
      Time: {
        title: "Время",
        type: "value",
        value: "",
      }
  }
});



defineRule("BoilerTemperature", { 
  whenChanged: BoilerTemperature, 
  then: function (newValue, devName, cellName) {
    dev['BoilerTermostat/Temperature'] = newValue;
    log.info( 'BoilerTermostat/Temperature = ' + newValue );
  }
});


defineRule("BoilerRelay", { 
  whenChanged: BoilerRelay, 
  then: function (newValue, devName, cellName) {
    if (newValue == true) { dev['BoilerTermostat/RelayState'] = "включено"; }
    if (newValue == false) { dev['BoilerTermostat/RelayState'] = "выключено"; }
    log.info( 'BoilerTermostat/RelayState = ' + newValue );
  }

});




defineRule("cron minute timer", { // задание, которое выполняется каждую минуту
  when: cron("00 * * * * *"),
  then: function () {
    var currentHour = time.getHours();
    dev['BoilerTermostat/Time'] = currentHour;
    log.info('Время ' + currentHour );
    }
});




defineRule("BoilerThermostatController", {
  whenChanged: [onoff, scheduleMode, setpoint, BoilerTemperature, hysteresis], 
  then: function (newValue, devName, cellName) {

  	if (dev[onoff]) { // если термостат включён

      if (dev[scheduleMode]) { // если термостат работает по расписанию
          // тут ТЭН нельзя включать вручную
          // то есть в виджете выключатель реле "wb-mio-gpio_70:4/K1"
          // должен быть спрятан или виден, но заблокирован для нажатия

        if (time.getHours() < 7 || time.getHours() >= 23) { // с 23 ночи до 7 утра

          heatingRules();
          SendTelegramMsg('Температура ' + dev[BoilerTemperature] + ', Настройка ' + dev[setpoint] + ', Гистерезис ' + dev[hysteresis] + ', Положение реле ' + dev[BoilerRelay] + ', Термостат ' + dev[onoff] + ', Расписание ' + dev[scheduleMode] + ', Время ' + time.getHours());
          log.info('Температура ' + dev[BoilerTemperature] + ', Настройка ' + dev[setpoint] + ', Гистерезис ' + dev[hysteresis] + ', Положение реле ' + dev[BoilerRelay] + ', Термостат ' + dev[onoff] + ', Расписание ' + dev[scheduleMode] + ', Время ' + time.getHours());

        }

        else  { // с 7 утра до 23 ночи
          dev[BoilerRelay] = false;
          SendTelegramMsg( dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + '. Нагрев остановлен по времени.');
        }
      }

      else { // scheduleMode == false, то есть термостат работает вручную по кнопке
          // тут ТЭН надо включать вручную
          // то есть в виджете выключатель реле "wb-mio-gpio_70:4/K1"
          // должен быть виден и активен для нажатия

      }
    }

    else { // если термостат выключён, то нагрев не работает
      dev[BoilerRelay] = false; 
      SendTelegramMsg( dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + '. Нагрев остановлен. Термостат выключён.');
      log.info( dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + '. Нагрев остановлен. Термостат выключён.');     
    } 

  }

});



function heatingRules() { 

  if ( dev[BoilerTemperature] <= dev[setpoint] - dev[hysteresis] ) { // если температура датчика меньше уставки - гистерезис
    dev[BoilerRelay] = true;
    SendTelegramMsg( dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + '. Начался нагрев.');
    log.info( dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + '. Начался нагрев.');
  }
  
  else if ( dev[BoilerTemperature] = dev[setpoint] ) { //если температура датчика достигла уставки выключить нагрев
    dev[BoilerRelay] = false;
    SendTelegramMsg( dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + '. Нагрев остановлен по настройке термостата.');
    log.info( dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + '. Нагрев остановлен по настройке термостата.');
  }
  
  else if ( dev[BoilerTemperature] > dev[setpoint] ) { //если температура датчика больше уставки выключить нагрев
    dev[BoilerRelay] = false;
    SendTelegramMsg( 'ВНИМАНИЕ ПЕРЕГРЕВ. ' + dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + '. Нагрев остановлен. Превышение температуры. Необходимо проверить' + dev[name] + ' .');
    log.info( 'ВНИМАНИЕ ПЕРЕГРЕВ. ' + dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + '. Нагрев остановлен. Превышение температуры. Необходимо проверить' + dev[name] + ' .');
  }
  
  else {  // тут ничего не делаем (либо идёт нагрев либо остывание)
  
  }
  
};

В итоге термостат работает не так как я ожидал. Вот основные правила управления ТЭНом.

dev[BoilerTemperature] <= dev[setpoint] - dev[hysteresis]
Включаем ТЭН, если температура датчика меньше настройки термостата минус гистерезис.
В моём примере нагрев начался при температуре датчика 58 < 70-11

dev[BoilerTemperature] = dev[setpoint]
Выключаем ТЭН, когда температура достигла настройки термостата.
А в моих логах видно, что ТЭН отключился, когда температура достигла (настройки термостата минус гистерезис), хотя у меня такого в коде нет.

Почему так случилось?

dev[BoilerTemperature] > dev[setpoint]

Ну и значение температуры виртуального термостата почему-то отличается от температуры датчика почти на целый градус, хотя изменения прилетают каждый 0,1 градус.

А переменная time где определяется?
Я вижу присвоение ей значения только при старте, все.

Тут ведь проверяется слева наприаво, получается что условие можно записать как (false - value) или (true - value). В общем вычисление следует выполнять до сравнения, закоючив в скобки.

Подправил.
И ещё придумал как завернуть весь код в cron, чтобы раз в минуту проверялась температура.
Теперь появилась новая проблема - скрипт отправляет мне в телеграм 15 сообщений в минуту.
Совсем отключать уведомления я не хочу, но хочется чтобы они были не такими тупыми.
Что-то типа если минуту назад это сообщение уже было, то не надо слать его повторно.

var name = "BoilerTermostat/Name";
var onoff = "BoilerTermostat/ON_OFF";
var scheduleMode = "BoilerTermostat/ScheduleMode";
var setpoint = "BoilerTermostat/Setpoint";
var hysteresis = "BoilerTermostat/Hysteresis";
var BoilerTemperature = "wb-mai6_51/IN 1 P Temperature";
var WBBoilerRelay = "wb-mio-gpio_70:4/K1"; 
var CirculationTimeout = 10000; // 10 секунд
var CirculationTopics = ["wb-mr6c_120/Input 4 Double Press Counter",    "wb-mr6c_126/Input 5 Double Press Counter"];
var CirculationNames =  ["на первом этаже", "на втором этаже"];



defineVirtualDevice("BoilerTermostat", {
    title: "Термостат бойлера",
    cells: {
      Name: {
        title: "Название",
        type: "text",
        value: "Бойлер",
      }, 
      ON_OFF: { // активация термостата 0-выкл 1-включен
        title: "Выключатель",
        type: "switch",
        value: false,
      }, 
      ScheduleMode: { // режим 0-ручной 1-по расписанию с 23 вечера до 7 утра
        title: "Работа по расписанию",
        type: "switch",
        value: false,
      },
      Temperature: {
        title: "Температура",
        type: "value",
        value: "",
        units: "deg C",
        precision: 2,
      },
      Setpoint: { // уставка
        title: "Уставка",
        type: "range",
        value: 50,
          min: 20,
          max: 70,
        readonly: false,
      },
      Hysteresis: {
        title: "Гистерезис",
        type: "range",
        value: 10,
          min: 5,
          max: 20,
        readonly: false,     
      },
      WBRelayState: { // состояние реле 0-ожидание (ВЫКЛ) 1-нагрев (ВКЛ)
        title: "Состояние реле WB",
        type: "text",
        value: false,
      },
      ABBRelayState: { // состояние реле 0-ожидание (ВЫКЛ) 1-нагрев (ВКЛ)
        title: "Состояние реле ABB",
        type: "text",
        value: false,
      },
      Lock: { // блокировка в визуализации 0-снята 1-заблокирована
        title: "Блокировка изменений",
        type: "switch",
        value: false,
      },
  }
});



defineRule("BoilerTemperature", { 
  whenChanged: BoilerTemperature, 
  then: function (newValue, devName, cellName) {
    dev['BoilerTermostat/Temperature'] = newValue;
    log.info( 'BoilerTermostat/Temperature = ' + newValue );
  }
});


defineRule("WBBoilerRelay", { 
  whenChanged: WBBoilerRelay, 
  then: function (newValue, devName, cellName) {
    if (newValue == true) { dev['BoilerTermostat/WBRelayState'] = "включено"; }
    if (newValue == false) { dev['BoilerTermostat/WBRelayState'] = "выключено"; }
    log.info( 'BoilerTermostat/WBRelayState = ' + newValue );
  }

});




defineRule("cron minute timer", { // задание, которое выполняется каждую минуту
  when: cron("00 * * * * *"),
  then: function () {

    BoilerController();

    }
});




function BoilerController() {

  defineRule( {
    whenChanged: [onoff, scheduleMode, setpoint, BoilerTemperature, hysteresis], 
    then: function (newValue, devName, cellName) {

      time = new Date(); //Текущее время

    	if (dev[onoff]) { // если термостат включён
            SendTelegramMsg( 'Термостат включён');
            log.info( 'Термостат включён');

        if (dev[scheduleMode]) { // если термостат работает по расписанию
            // тут ТЭН нельзя включать вручную
            // то есть в виджете выключатель реле "wb-mio-gpio_70:4/K1"
            // должен быть спрятан или виден, но заблокирован для нажатия
            SendTelegramMsg('scheduleMode ON - нагрев по расписанию ночью');
            log.info('scheduleMode ON - нагрев по расписанию ночью');

          if (time.getHours() < 7 || time.getHours() >= 23) { // с 23 ночи до 7 утра
            SendTelegramMsg('Началось ночное время нагрева по расписанию');
            log.info('Началось ночное время нагрева по расписанию');
            heatingRules();
          }

          else  { // с 7 утра до 23 ночи
            dev[WBBoilerRelay] = false;
            SendTelegramMsg( 'Время ' + time.getHours() + '. heatingRules stopped в Южном. Ночь закончилась.');
            log.info( 'Время ' + time.getHours() + '. heatingRules stopped в Южном. Ночь закончилась.');
          }
        }

        else { // scheduleMode == false, то есть термостат работает вручную по кнопке
            // тут ТЭН надо включать вручную
            // то есть в виджете выключатель реле "wb-mio-gpio_70:4/K1"
            // должен быть виден и активен для нажатия
            SendTelegramMsg( 'scheduleMode OFF - ручной режим');
            log.info( 'scheduleMode OFF - ручной режим');
            heatingRules();
        }
      }

      else { // если термостат выключён, то нагрев не работает
        dev[WBBoilerRelay] = false; 
        SendTelegramMsg( dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + '. Нагрев остановлен. Термостат выключён.');
        log.info( dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + '. Нагрев остановлен. Термостат выключён.');     
      } 

    }

  });

}


function heatingRules() { 

  SendTelegramMsg('Время ' + time.getHours() + '. heatingRules started в Южном');
  log.info('Время ' + time.getHours() + '. heatingRules started в Южном');


  if ( dev[BoilerTemperature] <= (dev[setpoint] - dev[hysteresis]) ) { // если температура датчика меньше уставки - гистерезис
    dev[WBBoilerRelay] = true;
    SendTelegramMsg(dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + ' <= ' + dev[setpoint] + '-' + dev[hysteresis] + 
      '. Положение реле WB ' + dev[WBBoilerRelay] + '. Начался нагрев.');
    log.info(dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + ' <= ' + dev[setpoint] + '-' + dev[hysteresis] + 
      '. Положение реле WB ' + dev[WBBoilerRelay] + '. Начался нагрев.');
  }

  else if ( dev[BoilerTemperature] > (dev[setpoint] - dev[hysteresis]) || dev[BoilerTemperature] < dev[setpoint] ) { 
  // тут ничего не делаем (либо идёт нагрев либо остывание) - просто пишем об этом сообщение
    SendTelegramMsg('Тут ничего не делаем. Температура достигла ' + dev[BoilerTemperature] + ' . else if ' + dev[BoilerTemperature] + ' > ' + (dev[setpoint] + '-' + dev[hysteresis]) );
    log.info('Тут ничего не делаем. Температура достигла ' + dev[BoilerTemperature] + ' . else if ' + dev[BoilerTemperature] + ' > ' + (dev[setpoint] + '-' + dev[hysteresis]) );

  }
  
  else if ( dev[BoilerTemperature] = dev[setpoint] ) { // если температура датчика достигла уставки выключить нагрев
    dev[WBBoilerRelay] = false;
    SendTelegramMsg(dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + ' = ' + dev[setpoint] + ' (настройка термостата). Нагрев остановлен.');
    log.info(dev[name] + ' в Южном. Температура ' + dev[BoilerTemperature] + ' = ' + dev[setpoint] + ' (настройка термостата). Нагрев остановлен.');
  }
  
  else if ( dev[BoilerTemperature] > dev[setpoint] ) { // если температура датчика больше уставки выключить нагрев
    dev[WBBoilerRelay] = false;
    SendTelegramMsg('ВНИМАНИЕ ПЕРЕГРЕВ. ' + dev[name] + 'а в Южном. Температура ' + dev[BoilerTemperature] + ' > ' + dev[setpoint] + ' (настройка термостата). Нагрев остановлен.');
    log.info('ВНИМАНИЕ ПЕРЕГРЕВ. ' + dev[name] + 'а в Южном. Температура ' + dev[BoilerTemperature] + ' > ' + dev[setpoint] + ' (настройка термостата). Нагрев остановлен.');
  }
    
  else {  // на всякий случай во всех других ситуациях вырубаем ТЭН
    dev[WBBoilerRelay] = true;
    SendTelegramMsg('Тут ничего не делаем. Температура ' + dev[BoilerTemperature] + ' . Последний else.');
    log.info('Тут ничего не делаем. Температура ' + dev[BoilerTemperature] + ' . Последний else.');
  }
  
}