Сбросить значения items, если Thing OFFLINE - d51x/openhab-docs-russian GitHub Wiki

Проблема

Когда устройство выпадает из сети (thing становится OFFLINE), то прилинкованые items не изменяют своего предыдущего значения. Скорее всего это зависит от реализации биндинга, но у меня подавляющее число things - это mqtt.

Пример

Имеется энергомонитор на esp8266, который по mqtt отправляет данные - напряжение, сила тока, мощность.

В какой-то момент энергомонитор выходит из строя, а items для напряжения, силы тока и мощности будет показывать последние значения, которые были отправлены устройством.

Это выглядит неправдоподобно

image

Значения отображаются по сей день, хотя устройство не подает признаков жизни уже неделю.

Было бы логичнее вместо старых значений видеть что-то более подходящее, либо знак -, либо Недоступно, либо еще как-то, зависит от твоей фантазии.

Решение

Если thing стал OFFLINE, то прилинкованным items можно проставить значение UNDEF, а на UI в виджетах уже делать подстановку нужного текста вместо UNDEF.

image

Настроить это можно через параметр виджета (в yaml)

after: =items.EnergyMonitorsdm230_Voltage.state=="UNDEF"?"-":items.EnergyMonitorsdm230_Voltage.displayState

Но не делать же правила на каждый item?

Можно создать универсальный скрипт, который на вход примет thingUid (mqtt:topic:b59315f1c3:8f2379fd47), а далее для всех прилинкованных items к каналам thing проставит состояние UNDEF, если thing перешел в OFFLINE.

var thingUid = ctx['thingID'];

if (things.getThing(thingUid).status=== "OFFLINE") {
  processThing(thingUid);
}

function processThing(uid) {
  var resetTag = 'undef';
  var noResetTag = 'noreset';
  var updateType = 'noreset'; // reset, noreset

  var linkRegistry = osgi.getService('org.openhab.core.thing.link.ItemChannelLinkRegistry');
  var thingRegistry2 = osgi.getService('org.openhab.core.thing.ThingRegistry');
  var ThingUID = Java.type('org.openhab.core.thing.ThingUID');
  var thingUid = new ThingUID(uid);
  var rawThing = thingRegistry2.get(thingUid);
  var channelList = utils.javaListToJsArray(rawThing.getChannels());
  channelList.forEach(channel=>{
    var linkedItems = utils.javaSetToJsArray(linkRegistry.getLinkedItems(channel.getUID()));
    linkedItems.forEach(item => {
      var tags = utils.javaSetToJsArray(item.tags);
      if (updateType === 'reset') {
        if (tags.includes(resetTag)) {
          items.getItem(item.name).postUpdate(undefined);
        }
      } else if (updateType === 'noreset') {
        if (!tags.includes(noResetTag)) {
          items.getItem(item.name).postUpdate(undefined);
        }
      }
    })  
  })
}

Но таким скриптом можно испортить нужные данные, например, есть прилинкованный item, который не нужно обнулять, нужно чтобы он имел последнее значение.

Это может быть item, который фиксирует время последнего изменения/обновления значения.

Чтобы этого не произошло, есть 2 варианта:

  1. проставить тэг undef для тех items, которые надо обнулить, и в скрипте прописать значение reset для переменной updateType
  2. проставить тэг noreset для тех items, которые НЕ НАДО обнулять, и в скрипте прописать значение noreset для переменной updateType, тэг undef вообще не требуется проставлять

Далее нужно уже создать правило для отслеживания изменения состояния thing.

image

Выбираем триггер по изменению состояния thing.

Добавляем action - inline script

image

Вставляем скрипт

rules.runRule('reset_linked_items', {'thingID': event.thingUID});

где reset_linked_items - это название первого скрипта

Отслеживаем все Things

Идем дальше, и чтобы для каждого thing не делать правило, будем использовать Rule Template - Thing Status Reporting

В маркtnt таких темплейта 2. Т.к. заметка относится к openHAB 4.x, то нам надо устанавливать темплейт для 4-ой версии.

Версия темплейта для openHAB 3.x - /addons/marketplace:128901 (Thing Status Reporting [3.2.0;3.4.9])

image

Ее не ставим!


Версия темплейта для openHAB 4.x - /addons/marketplace:143180 (Thing Status Reporting [4.0.0.0;4.9.9.9]) https://community.openhab.org/t/thing-status-reporting-4-0-0-0-4-9-9-9/143180

image

Ее ставим!


Создадим правило и выберем темплейт

image

В настройках темплейта выберем скрипт для запуска.

Скрипт для запуска - это самый первый скрипт из данной заметки.

image

Получим правило с триггером. Триггер будет срабатывать, когда у любого thing будет изменяться статус.

**!!! У темплейта есть ограничения, см. на странице темплейта **(https://community.openhab.org/t/thing-status-reporting-4-0-0-0-4-9-9-9/143180)

**!!! Темплейт требует установки бибилиотеки **openhab_rules_tools

Установка производится из папки $OH_CONF/automation/js, npm уже должен быть установлен

npm install openhab_rules_tools

Для данного способо код первоначального скрипта немного другой

var thingUid = ctx['thingID'];
if (ctx['oldStatus'] === "ONLINE" && ctx['newStatus'] === "OFFLINE") {
  processThing(thingUid);
}

function processThing(uid) {
  var resetTag = 'undef';
  var noResetTag = 'noreset';
  var updateType = 'reset'; // reset, noreset

  var linkRegistry = osgi.getService('org.openhab.core.thing.link.ItemChannelLinkRegistry');
  var thingRegistry2 = osgi.getService('org.openhab.core.thing.ThingRegistry');
  var ThingUID = Java.type('org.openhab.core.thing.ThingUID');
  var thingUid = new ThingUID(uid);
  var rawThing = thingRegistry2.get(thingUid);
  var channelList = utils.javaListToJsArray(rawThing.getChannels());
  channelList.forEach(channel=>{
    var linkedItems = utils.javaSetToJsArray(linkRegistry.getLinkedItems(channel.getUID()));
    linkedItems.forEach(item => {
      // console.info("  linked item type:", item.type);
      var tags = utils.javaSetToJsArray(item.tags);
      if (updateType === 'reset') {
        if (tags.includes(resetTag)) {
          items.getItem(item.name).postUpdate(undefined);
          console.info("send UNDEF to", item.name);
        }
      } else if (updateType === 'noreset') {
        if (!tags.includes(noResetTag)) {
          items.getItem(item.name).postUpdate(undefined);
          console.info("send UNDEF to", item.name);
        }
      }
    })  
  })
}