Last active
July 15, 2022 13:09
-
-
Save ssalonen/257078e7310c4629e9983c9ff315dc9e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
uid: ssalonen:device-online-monitor | |
label: Monitor device online status | |
description: Monitor device online status using combination of thing status and item state | |
configDescriptions: | |
- name: INPUT_ITEM | |
type: TEXT | |
context: item | |
label: Input item to monitor | |
required: true | |
description: Item to monitor for UNDEF changes | |
- name: INPUT_THING | |
type: TEXT | |
context: thing | |
label: Input thing to monitor | |
required: true | |
description: Thing to monitor for OFFLINE/ONLINE | |
- name: ONLINE_STATUS_ITEM | |
type: TEXT | |
context: item | |
label: Item to output the detected online status | |
required: true | |
description: Item to output the detected online status | |
- name: GRACE_PERIOD_SECS | |
type: INTEGER | |
label: Grace period after startup, in seconds | |
required: false | |
defaultValue: 0 | |
description: Grace period after startp before deeming the device status offline | |
- name: CRON | |
type: TEXT | |
label: Cron expression specifying period for checking inital status | |
required: false | |
defaultValue: 0 0 0/2 * * ? * | |
description: Cron expression specifying period for checking inital status | |
triggers: | |
- id: "1" | |
configuration: | |
startlevel: 100 | |
type: core.SystemStartlevelTrigger | |
- id: "2" | |
configuration: | |
cronExpression: "{{CRON}}" | |
type: timer.GenericCronTrigger | |
- id: "3" | |
configuration: | |
thingUID: "{{INPUT_THING}}" | |
type: core.ThingStatusChangeTrigger | |
- id: "4" | |
configuration: | |
itemName: "{{INPUT_ITEM}}" | |
type: core.ItemStateUpdateTrigger | |
conditions: [] | |
actions: | |
- inputs: {} | |
id: "6" | |
configuration: | |
type: application/javascript;version=ECMAScript-2021 | |
script: >- | |
/* global Java, event, items, actions */ | |
(function () { | |
const THING_ID = '{{INPUT_THING}}' | |
const INPUT_ITEM_NAME = '{{INPUT_ITEM}}' | |
const RAW_ITEM_NAME = '{{ONLINE_STATUS_ITEM}}' | |
const GRACE_PERIOD_SECS = parseInt('{{GRACE_PERIOD_SECS}}', 10) | |
function calculateUptimeSeconds () { | |
const ManagementFactory = Java.type('java.lang.management.ManagementFactory') | |
const runtime = ManagementFactory.getRuntimeMXBean() | |
const startedSecs = runtime.getStartTime() / 1000 | |
return startedSecs | |
} | |
const uptimeSecs = calculateUptimeSeconds() | |
// We know that the trigger must be time interval based (cron) or "system started" when | |
// we do not have any thing status info or item state information in the event | |
const cronOrStarted = typeof event === 'undefined' || (event.statusInfo === undefined && event.itemState === undefined) | |
const thingTurnedOffline = typeof event !== 'undefined' && event.statusInfo !== undefined && event.statusInfo.status.toString() === 'OFFLINE' | |
const thingTurnedOnline = typeof event !== 'undefined' && event.statusInfo !== undefined && event.statusInfo.status.toString() === 'ONLINE' | |
const itemUpdatedUndef = typeof event !== 'undefined' && event.itemState !== undefined && event.itemState.toString() === 'UNDEF' | |
const itemUpdatedNonUndef = typeof event !== 'undefined' && event.itemState !== undefined && event.itemState.toString() !== 'UNDEF' | |
// handle each case separately | |
if (cronOrStarted) { | |
if (((GRACE_PERIOD_SECS === 0) || (uptimeSecs > GRACE_PERIOD_SECS)) && | |
(items.getItem(RAW_ITEM_NAME).state.toString() === 'NULL')) { | |
// Init with NULL on startup unless we can consider the thing/state clearly "offline". | |
// Further updates are based on thing status updates and state updates | |
const inputItemStateStr = items.getItem(INPUT_ITEM_NAME).state.toString() | |
const consideredNonAlive = (actions.Things.getThingStatusInfo(THING_ID).getStatus().toString() === 'OFFLINE' | |
|| inputItemStateStr === 'UNDEF' || inputItemStateStr === 'NULL') | |
const aliveState = consideredNonAlive ? 'OFF' : 'NULL' | |
console.debug(INPUT_ITEM_NAME + ' / ' + THING_ID + ' initialization (' + | |
(consideredNonAlive ? 'considered non-alive' : 'considered as indeterminate state') + | |
') -> alive state = ' + aliveState + ' (' + RAW_ITEM_NAME + ')') | |
items.getItem(RAW_ITEM_NAME).postUpdate(aliveState) | |
} else { | |
console.debug(INPUT_ITEM_NAME + ' / ' + THING_ID + ' initialization: completed. Not updating active status (' | |
+ RAW_ITEM_NAME + ')') | |
} | |
} else if (thingTurnedOffline) { | |
console.debug(THING_ID + ' turned OFFLINE (' + event.statusInfo.description.toString() | |
+ ') -> Considering non-alive (' + RAW_ITEM_NAME + ')') | |
items.getItem(RAW_ITEM_NAME).postUpdate('OFF') | |
} else if (thingTurnedOnline) { | |
const inputItemStateStr = items.getItem(INPUT_ITEM_NAME).state.toString() | |
const inputItemValid = inputItemStateStr !== 'UNDEF' && inputItemStateStr !== 'NULL' | |
console.debug(THING_ID + ' turned ONLINE and input item state (' + inputItemStateStr + ') is ' + | |
(inputItemValid ? 'valid' : 'non-valid') + | |
' -> Considering ' + (inputItemValid ? 'alive' : 'non-alive') + ' (' + RAW_ITEM_NAME + ')') | |
const aliveState = inputItemValid ? 'ON' : 'OFF' | |
items.getItem(RAW_ITEM_NAME).postUpdate(aliveState) | |
} else if (itemUpdatedUndef) { | |
console.debug(INPUT_ITEM_NAME + ' updated with UNDEF -> Considering non-alive' + ' (' + RAW_ITEM_NAME + ')') | |
items.getItem(RAW_ITEM_NAME).postUpdate('OFF') | |
} else if (itemUpdatedNonUndef) { | |
console.debug(INPUT_ITEM_NAME + ' updated with non-UNDEF state -> Considering alive' + ' (' + RAW_ITEM_NAME + ')') | |
items.getItem(RAW_ITEM_NAME).postUpdate('ON') | |
} else { | |
console.error('Unexpected condition') | |
} | |
})() | |
type: script.ScriptAction |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment