From c5ed9c9c44ebecc652a6a00a17fbc4abd0baabf7 Mon Sep 17 00:00:00 2001 From: Christian Weimann Date: Sat, 18 Jan 2025 04:25:42 +0100 Subject: [PATCH] refactor(utils): rename and update SceneController to SceneMgr --- SceneController.js => utils/SceneMgr.js | 116 +++++++++++------------- 1 file changed, 54 insertions(+), 62 deletions(-) rename SceneController.js => utils/SceneMgr.js (69%) diff --git a/SceneController.js b/utils/SceneMgr.js similarity index 69% rename from SceneController.js rename to utils/SceneMgr.js index 3f336fd..0642a72 100644 --- a/SceneController.js +++ b/utils/SceneMgr.js @@ -1,10 +1,10 @@ // Settings const ITEMPREFIX = "System_StatefulScene"; const DEBOUNCETIME = 3000; -const LOGGER = "org.openhab.js.SceneController"; // Logging -const log = Java.type('org.slf4j.LoggerFactory').getLogger(LOGGER); +const log = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.js.utils.SceneMgr'); +console.loggerName = 'org.openhab.js.utils.SceneMgr'; // Load dependencies const { TimerMgr } = require('../utils'); @@ -13,14 +13,18 @@ const tm = new TimerMgr(); const { ruleRegistry } = require('@runtime/RuleSupport'); // Functions -class SceneController { +class SceneMgr { - constructor() { - // Log the initialization message for SceneController. - log.info('Initialization of SceneController'); + constructor(itemPrefix, debounceTime) { + // Load class properties + this.itemPrefix = itemPrefix; + this.debounceTime = debounceTime; + + // Log the initialization message for SceneMgr + console.log('Initialization of SceneMgr'); // Initialize the scenes map by reducing the array of scenes into an object with unique IDs as keys. - this.scenes = this.getScenes().reduce((scenes, scene) => { + this.scenes = this.#getStatefulScenes().reduce((scenes, scene) => { const sceneUID = scene.getUID(); scenes[sceneUID] = new Scene(scene); return scenes; @@ -48,17 +52,19 @@ class SceneController { } } - getScenes() { + #getStatefulScenes() { + // Fetch all rules from ruleRegistry const allRules = utils.javaSetToJsArray(ruleRegistry.getAll()); + // Filter rules relating to stateful scenes depending on the respective tags return allRules.filter(rule => { const ruleTags = utils.javaSetToJsArray(rule.getTags()); const hasSceneTag = ruleTags.includes("Scene"); const hasStatefulTag = ruleTags.includes("Stateful"); const isEnabled = rules.isEnabled(rule.getUID()); - return hasSceneTag && hasStatefulTag && isEnabled; + return hasSceneTag && hasStatefulTag && isEnabled; // Todo: refactoring enabled }); } @@ -66,25 +72,30 @@ class SceneController { class Scene { - constructor(scene) { + #isActive = false; + constructor(scene) { + // Load class properties this.scene = scene; this.sceneUID = this.scene.getUID(); this.sceneName = this.scene.getName(); this.sceneSwitchItemName = ITEMPREFIX + "_" + this.sceneUID; this.evaluationRuleUID = "SceneItems" + this.sceneUID; - log.info(`Initialize scene ${this.sceneName}`); + // Log the initialization of the scene + console.log(`Initialize scene ${this.sceneName}`); + // Create switchItem for scene if it does not exits if (!items[this.sceneSwitchItemName]) { this.createSceneSwitchItem(); } + // Create required scene rules for the scene this.createSceneRules(); } createSceneSwitchItem() { - log.info(`Creating scene switch for ${this.sceneSwitchItemName}`); + console.log(`${this.sceneName}: Create scene switch with item name ${this.sceneSwitchItemName}`); items.addItem({ name: this.sceneSwitchItemName, type: 'Switch', @@ -116,35 +127,21 @@ class Scene { id: this.evaluationRuleUID, overwrite: true }); - this.disableEvaluationRule(); } - - disableEvaluationRule() { - // Log the action using template literals for cleaner string interpolation - log.debug(`Disable evaluation rule for scene ${this.sceneName}`); - - // Disable the evaluation rule by setting its enabled state to false - rules.setEnabled(this.evaluationRuleUID, false); - } - - enableEvaluationRule() { - // Log the action using template literals for better readability - log.info(`Enable evaluation rule for scene ${this.sceneName}`); - - // Enable the evaluation rule by setting its enabled state to true - rules.setEnabled(this.evaluationRuleUID, true); - } - + evaluateScene() { const sceneUID = this.scene.getUID(); - const sceneName = this.scene.getName(); const timerUID = "EvaluateScene_" + sceneUID; - const sceneSwitchItemName = ITEMPREFIX + "_" + sceneUID; + + if (!this.#isActive) { + console.debug(`Scene ${this.sceneName}: Skip evaluation because scene is not active`); + return; + } const evaluate = () => { - log.info(`Evaluate scene ${sceneName}`); + log.info(`Evaluate scene ${this.sceneName}`); const scenceConfig = this.getSceneConfig(); let conditionsFailed = false; @@ -166,24 +163,19 @@ class Scene { } if (conditionsFailed) { - log.info(`Switch off sceneSwitch for scene ${sceneName} because conditions failed`); - items[sceneSwitchItemName].postUpdate("OFF"); - this.disableEvaluationRule(); + log.info(`Switch off sceneSwitch for scene ${this.sceneName} because conditions failed`); + items[this.sceneSwitchItemName].postUpdate("OFF"); + this.#isActive = false; } }; - if (items[sceneSwitchItemName].state === "OFF") { - log.info(`Skip evaluation of scene ${sceneName} because scene is off`); - return; - } - const timeout = time.ZonedDateTime.now().plusNanos(DEBOUNCETIME * 1000000); if (tm.hasTimer(timerUID) && tm.isActive(timerUID)) { - log.info(`Skip evaluation of scene ${sceneName} as evaluation function is already running. Reschedule timer`); + log.info(`Skip evaluation of scene ${this.sceneName} as evaluation function is already running. Reschedule timer`); tm.reschedule(timerUID, timeout); } else { - log.info(`Create timer to evaluate scene ${sceneName}`); + log.info(`Create timer to evaluate scene ${this.sceneName}`); if (tm.hasTimer(timerUID)) { tm.cancel(timerUID); } @@ -233,39 +225,39 @@ class Scene { } rules.runRule(this.sceneUID); - java.lang.Thread.sleep(2500); - this.enableEvaluationRule(); + this.#isActive = true; break; case "OFF": - log.info("Deactivate scene " + this.sceneName); + console.debug(`Scene ${this.sceneName}: Deactivate scene`); if (this.hasRestoreEnabled()) { - log.info("Restore is enabled"); + log.debug(`Scene ${this.sceneName}: Restore previous values before scene was activated`); let timestamp = this.switchedOn.minusNanos(DEBOUNCETIME * 1000000) - for (const sceneItem of this.getSceneItems()) { - let historicSceneItem = items[sceneItem].persistence.persistedState(timestamp); - let historicSceneItemState = historicSceneItem.state - items[sceneItem].sendCommandIfDifferent(historicSceneItemState); + for (const sceneItemName of this.getSceneItems()) { + let historicSceneItem = items[sceneItemName].persistence.persistedState(timestamp); + + if (historicSceneItem !== null) { + items[sceneItemName].sendCommandIfDifferent(historicSceneItem.state); + } else { + console.warn(`Scene ${this.sceneName}: No previous value found for ${sceneItemName}`); + } + } } - this.disableEvaluationRule(); + this.#isActive = false; break; } } } -// Load script -const sm = new SceneController(); +function getSceneMgr() { + return new SceneMgr(); +} -// Unload script -require('@runtime').lifecycleTracker.addDisposeHook(() => { - log.info('Deinitialization of SceneController'); - - sm.purgeUnusedSceneSwitchItems(); - - tm.cancelAll(); -}); \ No newline at end of file +module.exports = { + getSceneMgr +}; \ No newline at end of file