diff --git a/equipmentMgr.js b/equipmentMgr.js index e2dcf84..1ef66a1 100644 --- a/equipmentMgr.js +++ b/equipmentMgr.js @@ -32,21 +32,12 @@ class Equipment { // Initialization of properties this.name = this.equipmentItem.name; - this.watch = new Object(); this.timers = new timer.Timer(); - // Check if equipment has state item - if (this.hasProperty('State')) { - this.stateItem = items[this.getPropertyItemName('State')]; - this.watch['State'] = new watch.Watch(this.stateItem); - } else { - console.info(`Item ${this.equipmentItem.name} has no state item`) - } - // Check if equipment has LowBat item if (this.hasProperty('LowBat')) { - this.watch['LowBat'] = new watch.Watch(this.getPropertyItemName('LowBat')); - this.watch['LowBat'].add({ + watches.add({ + item: this.getPropertyItemName('LowBat'), targetState: 'ON', alertFunc: () => { this.#notifyLowBat(); }, alertRepeat: 'PT23H' @@ -55,8 +46,8 @@ class Equipment { // Check if equipment has Unreach item if (this.hasProperty('Unreach')) { - this.watch['Unreach'] = new watch.Watch(this.getPropertyItemName('Unreach')); - this.watch['Unreach'].add({ + watches.add({ + item: this.getPropertyItemName('Unreach'), targetState: 'ON', alertFunc: () => { this.#notifyUnreach(); }, alertDelay: 'PT15M', @@ -110,12 +101,7 @@ class Equipment { } gc() { - console.log('Denitialization of eqipment ' + this.name); - - // Delete all watchObjects - for (let watchItem of Object.keys(this.watch)) { - this.watch[watchItem].deleteAll(); - } + console.log('Denitialization of equipment ' + this.name); // Cancel all timers this.timers.cancelAll(); @@ -139,12 +125,13 @@ class CCTV extends Equipment { super(equipmentItem); // Watch - this.watch['AP_ResidentsAreHome'] = new watch.Watch('AP_ResidentsAreHome'); - this.watch['AP_ResidentsAreHome'].add({ + watches.add({ + item: 'AP_ResidentsAreHome', targetState: 'ON', alertFunc: () => { this.setHomeMode('ON'); } }); - this.watch['AP_ResidentsAreHome'].add({ + watches.add({ + item: 'AP_ResidentsAreHome', targetState: 'OFF', alertFunc: () => { this.setHomeMode('OFF'); }, alertDelay: 'PT1M' @@ -229,6 +216,7 @@ class Doorbell extends Equipment { super(equipmentItem); this.watch['State'].add({ + item: this.getPropertyItemName('State'), targetState: 'ON', alertFunc: () => { items.getItem("OF_Alexa_Desk_TTS").sendCommand('Es hat geklingelt'); items.getItem("LR_Alexa_TV_TTS").sendCommand('Es hat geklingelt'); } }); @@ -243,7 +231,8 @@ class Irrigation extends Equipment { this.valves = new Object(); // Add on/off watch rule - this.watch['State'].add({ + watches.add({ + item: this.getPropertyItemName('State'), targetState: 'ON', alertFunc: () => { this.#irrigationOn(); }, endAlertFunc: () => { this.#irrigationOff(); }, @@ -346,7 +335,8 @@ class IrrigationValve extends Equipment { constructor(equipmentItem) { super(equipmentItem); - this.watch['State'].add({ + watches.add({ + item: this.getPropertyItemName('State'), targetState: 'ON', alertFunc: () => { this.stateItem.sendCommand('OFF'); }, alertDelay: 'PT30M' @@ -376,7 +366,8 @@ class TowelRadiator extends Equipment { constructor(equipmentItem) { super(equipmentItem); - this.watch['State'].add({ + watches.add({ + item: this.getPropertyItemName('State'), targetState: 'ON', alertFunc: () => { this.stateItem.sendCommand('OFF'); }, alertDelay: 'PT59M' @@ -403,7 +394,7 @@ class Window extends Equipment { } - +const watches = new watch.Watch(); const eMgr = new Object(); for (let equipmentItem of items.getItems().filter(element => { return (element.semantics.isEquipment == true) && (element.semantics.equipment == null) })) { @@ -430,7 +421,9 @@ cache.shared.put('eMgr', eMgr); require('@runtime').lifecycleTracker.addDisposeHook(() => { console.log('Deinitialization of equipmentMgr'); + watches.deleteAll(); + for (let equipmentItemName of Object.keys(eMgr)) { eMgr[equipmentItemName].gc(); } -}); \ No newline at end of file +}); \ No newline at end of file diff --git a/utils/watch.js b/utils/watch.js index 832dfe0..1adfd05 100644 --- a/utils/watch.js +++ b/utils/watch.js @@ -5,27 +5,12 @@ class Watch { #watchItem #watchObjects = new Object(); + #watchItems = new Object(); #timers = new timer.Timer(); - constructor(watchItem) { - - // Fetch item if provided itemName is a string - if (typeof watchItem === 'string' || watchItem instanceof String) { - this.#watchItem = items[watchItem]; - } else { - this.#watchItem = watchItem; - } - - // Throw error if item is not existing - if (this.#watchItem === null) { - throw(`Item ${watchItem} not existing`); - } - - console.log(`Create new Watch instance for ${this.#watchItem.name}`); - - // Create watch rule - this.#createWatchRule(); + constructor() { + console.log('Initialization of watch helper class'); } add(params) { @@ -34,16 +19,24 @@ class Watch { // Validate config for watchObject if (!this.validateWatchConfig(params)) { - console.warn(`Failed to add watch object for ${this.#watchItem.name} because no valid config was provided`); + console.warn(`Failed to add watch object because no valid config was provided`); return; } + if (!this.#watchItems.hasOwnProperty(params['item'])) { + this.#createWatchRule(params['item']); + } else { + console.debug(`Watch rule for item ${params['item']} already existing`) + } + + // Set default values if no config provided let operator = (params['operator'] !== undefined) ? params['operator'] : '=='; // Create watch object and return UUID - console.log(`Add watch object for item ${this.#watchItem.name} with state ${params['targetState']} and operator ${operator} with UUID ${watchUUID}`); + console.log(`Add watch object for item ${params['item']} with state ${params['targetState']} and operator ${operator} with UUID ${watchUUID}`); this.#watchObjects[watchUUID] = { + item: params['item'], targetState: params['targetState'], operator: operator, alertFunc: params['alertFunc'], @@ -63,7 +56,10 @@ class Watch { } delete(watchUUID) { - console.log(`Delete watch object for item ${this.#watchItem.name} with watchUUID ${watchUUID}`); + // Get itemName + let watchItemName = this.#watchObjects[watchUUID].item; + + console.log(`Delete watch object for item ${watchItemName} with watchUUID ${watchUUID}`); // End repeatAlertTimer if existing this.#timers.cancel('repeatAlarm ' + watchUUID); @@ -73,10 +69,10 @@ class Watch { delete this.#watchObjects[watchUUID]; - // Delete watchRule if no more watchObjects are present + // Delete watch rule if no more watchObjects for respective item are present if (Object.keys(this.#watchObjects).length == 0) { - console.debug(`Remove openHAB watch rule for item ${this.#watchItem.name}`); - rules.removeRule(this.watchRuleID); + console.debug(`Remove openHAB watch rule for item ${watchItemName}`); + rules.removeRule(this.#watchItems[watchItemName]); } } @@ -88,6 +84,10 @@ class Watch { validateWatchConfig(params) { + if (params['item'] === undefined) { + console.error('No item set'); + return false; + } if (params['targetState'] === undefined) { console.error('No targetState set'); return false; @@ -114,10 +114,13 @@ class Watch { } #checkAlertState(watchUUID) { - console.debug(`Check if item is in alert state for watchObject ${watchUUID}`) + // Get itemName + let watchItemName = this.#watchObjects[watchUUID].item; + + console.debug(`Check if item ${watchItemName} is in alert state for watchObject ${watchUUID}`) // Convert currentState for comparison - let currentState = lib.convertValue(this.#watchItem.state); + let currentState = lib.convertValue(items[watchItemName].state); // Do comparison if (lib.compare(currentState, this.#watchObjects[watchUUID].targetState, this.#watchObjects[watchUUID].operator)) { // Comparison successful @@ -139,16 +142,17 @@ class Watch { } } - #createWatchRule() { + #createWatchRule(item) { // Create openHAB rule - console.log(`Create openHAB watch rule for item ${this.#watchItem.name}`); - this.watchRuleID = String(utils.randomUUID()); + console.log(`Create openHAB watch rule for item ${item}`); + let watchRuleID = String(utils.randomUUID()); rules.JSRule({ - id: this.watchRuleID, - name: 'Watch rule for ' + this.#watchItem.name, - triggers: [triggers.ItemStateChangeTrigger(this.#watchItem.name)], + id: watchRuleID, + name: 'Watch rule for ' + item, + triggers: [triggers.ItemStateChangeTrigger(item)], execute: (event) => { this.#processItemEvent(event) }, }); + this.#watchItems[item] = watchRuleID; } #endAlert(watchUUID) { @@ -170,16 +174,17 @@ class Watch { #processItemEvent(event) { // Skip if function is triggered without openHAB event - if (event === undefined || event.eventType === undefined) { + if (event.eventType == 'manual') { console.warn(`ProcessItemEvent triggered without openHAB event`); return; } console.log(`Processing state ${event.newState} for ${event.itemName}`); - // Iterate through watchObjetcs // todo: rework to only fetch UUID - for (let [watchUUID, watchObject] of Object.entries(this.#watchObjects)) { - this.#checkAlertState(watchUUID); + for (const [id, watchObject] of Object.entries(this.#watchObjects)) { + if (watchObject.item == event.itemName) { + this.#checkAlertState(id); + } } } @@ -239,4 +244,4 @@ class Watch { module.exports = { Watch, -}; +}; \ No newline at end of file