Сбросить значения items, если Thing OFFLINE - d51x/openhab-docs-russian GitHub Wiki
Проблема
Когда устройство выпадает из сети (thing становится OFFLINE
), то прилинкованые items не изменяют своего предыдущего значения.
Скорее всего это зависит от реализации биндинга, но у меня подавляющее число things - это mqtt.
Пример
Имеется энергомонитор на esp8266, который по mqtt отправляет данные - напряжение, сила тока, мощность.
В какой-то момент энергомонитор выходит из строя, а items для напряжения, силы тока и мощности будет показывать последние значения, которые были отправлены устройством.
Это выглядит неправдоподобно
Значения отображаются по сей день, хотя устройство не подает признаков жизни уже неделю.
Было бы логичнее вместо старых значений видеть что-то более подходящее, либо знак -
, либо Недоступно
, либо еще как-то, зависит от твоей фантазии.
Решение
Если thing стал OFFLINE
, то прилинкованным items можно проставить значение UNDEF
, а на UI в виджетах уже делать подстановку нужного текста вместо UNDEF
.
Настроить это можно через параметр виджета (в 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 варианта:
- проставить тэг
undef
для тех items, которые надо обнулить, и в скрипте прописать значениеreset
для переменнойupdateType
- проставить тэг
noreset
для тех items, которые НЕ НАДО обнулять, и в скрипте прописать значениеnoreset
для переменнойupdateType
, тэгundef
вообще не требуется проставлять
Далее нужно уже создать правило для отслеживания изменения состояния thing.
Выбираем триггер по изменению состояния thing.
Добавляем action - inline script
Вставляем скрипт
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])
Ее не ставим!
Версия темплейта для 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
Ее ставим!
Создадим правило и выберем темплейт
В настройках темплейта выберем скрипт для запуска.
Скрипт для запуска - это самый первый скрипт из данной заметки.
Получим правило с триггером. Триггер будет срабатывать, когда у любого 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);
}
}
})
})
}