From 3f93b71549c9bd14ca29abd486fdb367336debf0 Mon Sep 17 00:00:00 2001 From: Scott Rushworth Date: Mon, 20 May 2019 07:29:20 -0400 Subject: [PATCH] Backwards compatibility for package name changes (#109) Signed-off-by: Scott Rushworth --- .../community/esper/components/000_Esper.py | 5 +- .../openweathermap/owm_daily_forecast.py | 18 ++- .../lib/python/community/idealarm/__init__.py | 1 + .../jsr223/core/000_startup_delay.py | 1 - .../core/components/100_DirectoryTrigger.py | 30 ++-- .../core/components/100_OsgiEventTrigger.py | 23 +-- .../core/components/100_ShutdownTrigger.py | 55 ------- .../core/components/100_StartupTrigger.py | 49 +++--- .../200_JythonBindingInfoProvider.py | 61 +++++--- .../components/200_JythonExtensionProvider.py | 139 ++++++++++-------- .../200_JythonItemChannelLinkProvider.py | 80 ++++++---- .../core/components/200_JythonItemProvider.py | 84 +++++++---- .../components/200_JythonThingProvider.py | 85 ++++++----- .../components/200_JythonThingTypeProvider.py | 63 +++++--- .../core/components/200_JythonTransform.py | 37 +++-- .../lib/python/configuration.py.example | 2 +- Core/automation/lib/python/core/__init__.py | 3 +- Core/automation/lib/python/core/date.py | 8 +- Core/automation/lib/python/core/items.py | 55 ++++--- Core/automation/lib/python/core/links.py | 63 ++++---- Core/automation/lib/python/core/log.py | 4 +- .../automation/lib/python/core/osgi/events.py | 12 +- Core/automation/lib/python/core/rules.py | 17 ++- Core/automation/lib/python/core/triggers.py | 60 +++++--- Core/automation/lib/python/core/utils.py | 6 +- Docs/Defining-Rules.md | 27 ++-- Script Examples/Alexa/speak_and_respond.py | 2 +- Script Examples/components/300_EchoThing.py | 31 +++- Script Examples/components/300_LogAction.py | 4 +- Script Examples/dirwatcher_example.py | 5 +- ...py => example_extension_provider_usage.py} | 0 31 files changed, 579 insertions(+), 451 deletions(-) delete mode 100644 Core/automation/jsr223/core/components/100_ShutdownTrigger.py rename Script Examples/{components/300_ExampleExtensionProvider.py => example_extension_provider_usage.py} (100%) diff --git a/Community/Esper/automation/jsr223/community/esper/components/000_Esper.py b/Community/Esper/automation/jsr223/community/esper/components/000_Esper.py index fd905cea..5725ae8f 100644 --- a/Community/Esper/automation/jsr223/community/esper/components/000_Esper.py +++ b/Community/Esper/automation/jsr223/community/esper/components/000_Esper.py @@ -1,3 +1,5 @@ +scriptExtension.importPreset(None) + import json import community.esper.java @@ -101,6 +103,3 @@ def scriptUnloaded(): log.info("Destroyed Esper provider") OsgiEventAdmin.remove_listener(esper_bridge) log.info("Esper event bridge removed") - - - diff --git a/Community/OpenWeatherMap/automation/jsr223/community/openweathermap/owm_daily_forecast.py b/Community/OpenWeatherMap/automation/jsr223/community/openweathermap/owm_daily_forecast.py index 8a699ea0..b8662cba 100644 --- a/Community/OpenWeatherMap/automation/jsr223/community/openweathermap/owm_daily_forecast.py +++ b/Community/OpenWeatherMap/automation/jsr223/community/openweathermap/owm_daily_forecast.py @@ -49,7 +49,7 @@ clearing. KNOWN ISSUES: -ArithmethicGroupFunction.Avg does not properly average angles. An ESH issue has +ArithmeticGroupFunction.Avg does not properly average angles. An ESH issue has been opened for this... https://github.com/eclipse/smarthome/issues/6792. I noticed the units for the Cloudiness and Humidity groups display as 'one', but the Items display properly as '%'. @@ -98,10 +98,18 @@ def addOWMItems(): addOWMItems.log = logging.getLogger(LOG_PREFIX + ".addOWMItems") # create OWM Items and groups, if they do not exist - from org.eclipse.smarthome.core.thing import ThingTypeUID - from org.eclipse.smarthome.core.thing import ChannelUID - from org.eclipse.smarthome.config.core import Configuration - from org.eclipse.smarthome.core.library.types import ArithmeticGroupFunction + scriptExtension.importPreset("RuleSupport") + try: + from org.openhab.core.thing import ThingTypeUID + from org.openhab.core.thing import ChannelUID + except: + from org.eclipse.smarthome.core.thing import ThingTypeUID + from org.eclipse.smarthome.core.thing import ChannelUID + + try: + from org.eclipse.smarthome.core.library.types import ArithmeticGroupFunction + except: + from org.openhab.core.library.types import ArithmeticGroupFunction from core.items import add_item from core.links import add_link diff --git a/Community/ideAlarm/automation/lib/python/community/idealarm/__init__.py b/Community/ideAlarm/automation/lib/python/community/idealarm/__init__.py index e4dfc947..e2d95c08 100644 --- a/Community/ideAlarm/automation/lib/python/community/idealarm/__init__.py +++ b/Community/ideAlarm/automation/lib/python/community/idealarm/__init__.py @@ -1,4 +1,5 @@ import weakref # Using this to prevent problems with garbage collection + from org.joda.time import DateTime from core.jsr223 import scope diff --git a/Core/automation/jsr223/core/000_startup_delay.py b/Core/automation/jsr223/core/000_startup_delay.py index d011c45d..42f8f41f 100755 --- a/Core/automation/jsr223/core/000_startup_delay.py +++ b/Core/automation/jsr223/core/000_startup_delay.py @@ -3,7 +3,6 @@ from org.slf4j import Logger, LoggerFactory log = LoggerFactory.getLogger("org.eclipse.smarthome.automation.jsr223.jython.startup_delay") - log.info("Checking for initialized context") while True: diff --git a/Core/automation/jsr223/core/components/100_DirectoryTrigger.py b/Core/automation/jsr223/core/components/100_DirectoryTrigger.py index 98946add..9d53a9ae 100644 --- a/Core/automation/jsr223/core/components/100_DirectoryTrigger.py +++ b/Core/automation/jsr223/core/components/100_DirectoryTrigger.py @@ -1,19 +1,27 @@ +scriptExtension.importPreset(None) + from java.nio.file.StandardWatchEventKinds import ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY -from org.eclipse.smarthome.automation import Visibility -from org.eclipse.smarthome.automation.handler import TriggerHandler -from org.eclipse.smarthome.core.service import AbstractWatchService +try: + from org.openhab.core.automation.handler import TriggerHandler +except: + from org.eclipse.smarthome.automation.handler import TriggerHandler + +try: + from org.openhab.core.service import AbstractWatchService +except: + from org.eclipse.smarthome.core.service import AbstractWatchService import core from core.log import logging, log_traceback, LOG_PREFIX log = logging.getLogger(LOG_PREFIX + ".core.DirectoryEventTrigger") +scriptExtension.importPreset("RuleSimple") scriptExtension.importPreset("RuleSupport") scriptExtension.importPreset("RuleFactories") class JythonDirectoryWatcher(AbstractWatchService): - def __init__(self, path, event_kinds=[ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY], watch_subdirectories=False): AbstractWatchService.__init__(self, path) self.event_kinds = event_kinds @@ -32,7 +40,6 @@ def processWatchEvent(self, event, kind, path): self.callback(event, kind, path) class _DirectoryEventTriggerHandlerFactory(TriggerHandlerFactory): - class Handler(TriggerHandler): @log_traceback def __init__(self, trigger): @@ -70,19 +77,16 @@ def scriptLoaded(*args): automationManager.addTriggerHandler( core.DIRECTORY_TRIGGER_MODULE_ID, _DirectoryEventTriggerHandlerFactory()) - log.info("TriggerHandler added".format(core.DIRECTORY_TRIGGER_MODULE_ID)) + log.info("TriggerHandler added [{}]".format(core.DIRECTORY_TRIGGER_MODULE_ID)) automationManager.addTriggerType(TriggerType( - core.DIRECTORY_TRIGGER_MODULE_ID, - [], + core.DIRECTORY_TRIGGER_MODULE_ID, None, "a directory change event is detected.", "Triggers when a directory change event is detected.", - set(), - Visibility.VISIBLE, - [])) - log.info("TriggerType added".format(core.DIRECTORY_TRIGGER_MODULE_ID)) + None, Visibility.VISIBLE, None)) + log.info("TriggerType added [{}]".format(core.DIRECTORY_TRIGGER_MODULE_ID)) def scriptUnloaded(): automationManager.removeHandler(core.DIRECTORY_TRIGGER_MODULE_ID) automationManager.removeModuleType(core.DIRECTORY_TRIGGER_MODULE_ID) - log.info("TriggerType and TriggerHandler removed".format(core.DIRECTORY_TRIGGER_MODULE_ID)) \ No newline at end of file + log.info("TriggerType and TriggerHandler removed [{}]".format(core.DIRECTORY_TRIGGER_MODULE_ID)) diff --git a/Core/automation/jsr223/core/components/100_OsgiEventTrigger.py b/Core/automation/jsr223/core/components/100_OsgiEventTrigger.py index a31d483e..72e8ff6e 100644 --- a/Core/automation/jsr223/core/components/100_OsgiEventTrigger.py +++ b/Core/automation/jsr223/core/components/100_OsgiEventTrigger.py @@ -1,9 +1,13 @@ +scriptExtension.importPreset(None) + import java.util import traceback import uuid -from org.eclipse.smarthome.automation import Visibility -from org.eclipse.smarthome.automation.handler import TriggerHandler +try: + from org.openhab.core.automation.handler import TriggerHandler +except: + from org.eclipse.smarthome.automation.handler import TriggerHandler import core from core.osgi.events import OsgiEventAdmin, event_dict, osgi_triggers @@ -11,6 +15,7 @@ log = logging.getLogger(LOG_PREFIX + ".core.OsgiEventTrigger") +scriptExtension.importPreset("RuleSimple") scriptExtension.importPreset("RuleSupport") scriptExtension.importPreset("RuleFactories") @@ -61,19 +66,15 @@ def get(self, trigger): def scriptLoaded(*args): automationManager.addTriggerHandler(core.OSGI_TRIGGER_ID, OsgiEventTriggerHandlerFactory()) - log.info("TriggerHandler added".format(core.OSGI_TRIGGER_ID)) + log.info("TriggerHandler added [{}]".format(core.OSGI_TRIGGER_ID)) - automationManager.addTriggerType(TriggerType( - core.OSGI_TRIGGER_ID, - [], + automationManager.addTriggerType(TriggerType(core.OSGI_TRIGGER_ID, None, "an OSGI event is published", "Triggers when an OSGI event is published", - set(), - Visibility.VISIBLE, - [])) - log.info("TriggerType added".format(core.OSGI_TRIGGER_ID)) + None, Visibility.VISIBLE, None)) + log.info("TriggerType added [{}]".format(core.OSGI_TRIGGER_ID)) def scriptUnloaded(): automationManager.removeHandler(core.OSGI_TRIGGER_ID) automationManager.removeModuleType(core.OSGI_TRIGGER_ID) - log.info("TriggerType and TriggerHandler removed".format(core.OSGI_TRIGGER_ID)) \ No newline at end of file + log.info("TriggerType and TriggerHandler removed [{}]".format(core.OSGI_TRIGGER_ID)) diff --git a/Core/automation/jsr223/core/components/100_ShutdownTrigger.py b/Core/automation/jsr223/core/components/100_ShutdownTrigger.py deleted file mode 100644 index 6bfe3855..00000000 --- a/Core/automation/jsr223/core/components/100_ShutdownTrigger.py +++ /dev/null @@ -1,55 +0,0 @@ -from org.eclipse.smarthome.automation import Visibility -from org.eclipse.smarthome.automation.handler import TriggerHandler - -import core -from core.jsr223 import scope -from core.log import logging, LOG_PREFIX - -log = logging.getLogger(LOG_PREFIX + ".core.ShutdownTrigger") - -scriptExtension.importPreset("RuleSupport") -scriptExtension.importPreset("RuleFactories") - -class _ShutdownTriggerHandlerFactory(TriggerHandlerFactory): - - class Handler(TriggerHandler): - def __init__(self, trigger): - self.trigger = trigger - - def setRuleEngineCallback(self, rule_engine_callback): - rule_engine_callback.triggered(self.trigger, {'shutdown': True}) - - def dispose(self): - pass - - def get(self, trigger): - return _ShutdownTriggerHandlerFactory.Handler(trigger) - - def ungetHandler(self, module, ruleUID, handler): - pass - - def dispose(self): - pass - -core.SHUTDOWN_MODULE_ID = "jsr223.ShutdownTrigger" - -def scriptLoaded(*args): - automationManager.addTriggerHandler( - core.SHUTDOWN_MODULE_ID, - _ShutdownTriggerHandlerFactory()) - log.info("TriggerHandler added [{}]".format(core.SHUTDOWN_MODULE_ID)) - - automationManager.addTriggerType(TriggerType( - core.SHUTDOWN_MODULE_ID, - [], - "the rule is activated", - "Triggers when a rule is activated the first time", - set(), - Visibility.VISIBLE, - [])) - log.info("TriggerType added [{}]".format(core.SHUTDOWN_MODULE_ID)) - -def scriptUnloaded(): - automationManager.removeHandler(core.SHUTDOWN_MODULE_ID) - automationManager.removeModuleType(core.SHUTDOWN_MODULE_ID) - log.info("TriggerType and TriggerHandler removed [{}]".format(core.SHUTDOWN_MODULE_ID)) \ No newline at end of file diff --git a/Core/automation/jsr223/core/components/100_StartupTrigger.py b/Core/automation/jsr223/core/components/100_StartupTrigger.py index eed7e20f..ac75e50b 100644 --- a/Core/automation/jsr223/core/components/100_StartupTrigger.py +++ b/Core/automation/jsr223/core/components/100_StartupTrigger.py @@ -1,55 +1,56 @@ -from org.eclipse.smarthome.automation import Visibility -from org.eclipse.smarthome.automation.handler import TriggerHandler +scriptExtension.importPreset(None) + +import traceback + +try: + from org.openhab.core.automation.handler import TriggerHandler +except: + from org.eclipse.smarthome.automation.handler import TriggerHandler import core -from core.jsr223 import scope from core.log import logging, LOG_PREFIX log = logging.getLogger(LOG_PREFIX + ".core.StartupTrigger") +scriptExtension.importPreset("RuleSimple") scriptExtension.importPreset("RuleSupport") scriptExtension.importPreset("RuleFactories") class _StartupTriggerHandlerFactory(TriggerHandlerFactory): - class Handler(TriggerHandler): def __init__(self, trigger): self.trigger = trigger - def setRuleEngineCallback(self, rule_engine_callback): - rule_engine_callback.triggered(self.trigger, {'startup': True}) + def setCallback(self, callback): + from threading import Timer + startTimer = Timer(1, lambda: callback.triggered(self.trigger, {'startup': True})) + startTimer.start() def dispose(self): pass - + def get(self, trigger): - return _StartupTriggerHandlerFactory.Handler(trigger) - + return self.Handler(trigger) + def ungetHandler(self, module, ruleUID, handler): pass - + def dispose(self): pass - + core.STARTUP_MODULE_ID = "jsr223.StartupTrigger" -def scriptLoaded(*args): - automationManager.addTriggerHandler( - core.STARTUP_MODULE_ID, - _StartupTriggerHandlerFactory()) +def scriptLoaded(id): + automationManager.addTriggerHandler(core.STARTUP_MODULE_ID, _StartupTriggerHandlerFactory()) log.info("TriggerHandler added [{}]".format(core.STARTUP_MODULE_ID)) - automationManager.addTriggerType(TriggerType( - core.STARTUP_MODULE_ID, - [], - "the rule is activated", - "Triggers when a rule is activated the first time", - set(), - Visibility.VISIBLE, - [])) + automationManager.addTriggerType(TriggerType(core.STARTUP_MODULE_ID, None, + "System started or rule saved", + "Triggers when the rule is added, which occurs when the system has started or the rule has been saved", + None, Visibility.VISIBLE, None)) log.info("TriggerType added [{}]".format(core.STARTUP_MODULE_ID)) def scriptUnloaded(): automationManager.removeHandler(core.STARTUP_MODULE_ID) automationManager.removeModuleType(core.STARTUP_MODULE_ID) - log.info("TriggerType and TriggerHandler removed [{}]".format(core.STARTUP_MODULE_ID)) \ No newline at end of file + log.info("TriggerType and TriggerHandler removed") diff --git a/Core/automation/jsr223/core/components/200_JythonBindingInfoProvider.py b/Core/automation/jsr223/core/components/200_JythonBindingInfoProvider.py index c621bf99..e2a8ab8f 100644 --- a/Core/automation/jsr223/core/components/200_JythonBindingInfoProvider.py +++ b/Core/automation/jsr223/core/components/200_JythonBindingInfoProvider.py @@ -1,32 +1,49 @@ -from org.eclipse.smarthome.core.binding import BindingInfoProvider +scriptExtension.importPreset(None) -import core from distutils.log import info -class JythonBindingInfoProvider(BindingInfoProvider): - def __init__(self): - self.binding_infos = {} - - def getBindingInfo(self, id, locale): - return self.binding_infos.get(id, None) - - def getBindingInfos(self, locale): - return set(self.binding_infos.values()) +provider_class = None +try: + from org.openhab.core.binding import BindingInfoProvider + provider_class = "org.openhab.core.binding.BindingInfoProvider" +except: + from org.eclipse.smarthome.core.binding import BindingInfoProvider + provider_class = "org.eclipse.smarthome.core.binding.BindingInfoProvider" - def add(self, info): - self.binding_infos[info.id] = info +import core +from core.log import logging, LOG_PREFIX + +try: + class JythonBindingInfoProvider(BindingInfoProvider): + def __init__(self): + self.binding_infos = {} + + def getBindingInfo(self, id, locale): + return self.binding_infos.get(id, None) - def remove(self, info): - if info.id in self.binding_infos: - del self.binding_infos[info.id] + def getBindingInfos(self, locale): + return set(self.binding_infos.values()) + + def add(self, info): + self.binding_infos[info.id] = info -core.JythonBindingInfoProvider = JythonBindingInfoProvider() + def remove(self, info): + if info.id in self.binding_infos: + del self.binding_infos[info.id] + + core.JythonBindingInfoProvider = JythonBindingInfoProvider() +except: + core.JythonBindingInfoProvider = None + import traceback + logging.getLogger(LOG_PREFIX + ".core.JythonBindingInfoProvider").warn(traceback.format_exc()) def scriptLoaded(id): - core.osgi.register_service( - core.JythonBindingInfoProvider, - ["org.eclipse.smarthome.core.binding.BindingInfoProvider"]) + if core.JythonBindingInfoProvider is not None: + core.osgi.register_service(core.JythonBindingInfoProvider, [provider_class]) + logging.getLogger(LOG_PREFIX + ".core.JythonBindingInfoProvider.scriptLoaded").debug("Registered service") def scriptUnloaded(): - core.osgi.unregister_service(core.JythonBindingInfoProvider) - delattr(core, 'JythonBindingInfoProvider') + if core.JythonBindingInfoProvider is not None: + core.osgi.unregister_service(core.JythonBindingInfoProvider) + core.JythonBindingInfoProvider = None + logging.getLogger(LOG_PREFIX + ".core.JythonBindingInfoProvider.scriptUnloaded").debug("Unregistered service") diff --git a/Core/automation/jsr223/core/components/200_JythonExtensionProvider.py b/Core/automation/jsr223/core/components/200_JythonExtensionProvider.py index b5064ddd..44b2d24d 100644 --- a/Core/automation/jsr223/core/components/200_JythonExtensionProvider.py +++ b/Core/automation/jsr223/core/components/200_JythonExtensionProvider.py @@ -1,77 +1,94 @@ +ScriptExtensionProvider = None + import collections +from java.lang import Class + +try: + ScriptExtensionProvider = Class.forName( + "org.openhab.core.automation.module.script.ScriptExtensionProvider", + True, + scriptExtension.getClass().getClassLoader() + ) +except: + ScriptExtensionProvider = Class.forName( + "org.eclipse.smarthome.automation.module.script.ScriptExtensionProvider", + True, + scriptExtension.getClass().getClassLoader() + ) + import core from core.log import logging, LOG_PREFIX -log = logging.getLogger(LOG_PREFIX + ".core.JythonExtensionProvider") -def scriptLoaded(*args): - try: - from java.lang import Class - name = "org.eclipse.smarthome.automation.module.script.ScriptExtensionProvider" - ScriptExtensionProvider = Class.forName(name, True, scriptExtension.getClass().getClassLoader()) - - class JythonExtensionProvider(ScriptExtensionProvider): - def __init__(self): - self._defaultPresets = set() - self._presets = set() - self._preset_values = collections.defaultdict(list) - self._values = {} - - def getDefaultPresets(self): - """These presets will always get injected into the ScriptEngine on instance creation.""" - return self._defaultPresets +try: + class JythonExtensionProvider(ScriptExtensionProvider): + def __init__(self): + logging.getLogger(LOG_PREFIX + ".core.JythonExtensionProvider").debug("Start init") + self._defaultPresets = set() + self._presets = set() + self._preset_values = collections.defaultdict(list) + self._values = {} + logging.getLogger(LOG_PREFIX + ".core.JythonExtensionProvider").debug("End init") + + def getDefaultPresets(self): + """These presets will always get injected into the ScriptEngine on instance creation.""" + return self._defaultPresets - def getPresets(self): - """Returns the provided Presets which are supported by this ScriptExtensionProvider. - Presets define imports which will be injected into the ScriptEngine if called by "importPreset". - Note: default preset names must also be in this list. - """ - return self._presets + def getPresets(self): + """Returns the provided Presets which are supported by this ScriptExtensionProvider. + Presets define imports which will be injected into the ScriptEngine if called by "importPreset". + Note: default preset names must also be in this list. + """ + return self._presets - def getTypes(self): - """Returns the supported types which can be received by the given ScriptExtensionProvider. - "Types" are just names and can refer to any object, either instance or class.""" - return self._values.keys() - - def get(self, scriptIdentifier, name): - """This method should return an Object of the given type. Note: get can be called - multiple times in the scripts use caching where appropriate. The scriptIdentifier can - be used to create script-specific values.""" - return self._values.get(name) + def getTypes(self): + """Returns the supported types which can be received by the given ScriptExtensionProvider. + "Types" are just names and can refer to any object, either instance or class.""" + return self._values.keys() - def importPreset(self, scriptIdentifier, preset): - """This method should return variables and types of the concrete type which - will be injected into the ScriptEngines scope.""" - # scriptIdentifier is ignored - return {name: self._values.get(name) for name in self._preset_values.get(preset, [])} + def get(self, scriptIdentifier, name): + """This method should return an Object of the given type. Note: get can be called + multiple times in the scripts use caching where appropriate. The scriptIdentifier can + be used to create script-specific values.""" + return self._values.get(name) + + def importPreset(self, scriptIdentifier, preset): + """This method should return variables and types of the concrete type which + will be injected into the ScriptEngines scope.""" + # scriptIdentifier is ignored + return {name: self._values.get(name) for name in self._preset_values.get(preset, [])} + + def unload(self, scriptIdentifier): + """This will be called when the ScriptEngine will be unloaded (e.g. if the Script is deleted or updated). + Script-specific information should be removed.""" + # scriptIdentifier is ignored + pass - def unload(self, scriptIdentifier): - """This will be called when the ScriptEngine will be unloaded (e.g. if the Script is deleted or updated). - Script-specific information should be removed.""" - # scriptIdentifier is ignored - pass + def addValue(self, name, value): + self._values[name] = value + + def addValues(self, values): + self._values.update(values) - def addValue(self, name, value): - self._values[name] = value - - def addValues(self, values): - self._values.update(values) - - def addPreset(self, preset_name, value_names, is_default=False): - self._presets.add(preset_name) - self._preset_values[preset_name] = value_names - if is_default: - self._defaultPresets.add(preset_name) - - core.JythonExtensionProvider = JythonExtensionProvider() + def addPreset(self, preset_name, value_names, is_default=False): + self._presets.add(preset_name) + self._preset_values[preset_name] = value_names + if is_default: + self._defaultPresets.add(preset_name) + + core.JythonExtensionProvider = JythonExtensionProvider() +except: + core.JythonExtensionProvider = None + import traceback + logging.getLogger(LOG_PREFIX + ".core.JythonExtensionProvider").warn(traceback.format_exc()) + +def scriptLoaded(id): + if core.JythonExtensionProvider is not None: scriptExtension.addScriptExtensionProvider(core.JythonExtensionProvider) - except: - core.JythonExtensionProvider = None - import traceback - log.error(traceback.format_exc()) + logging.getLogger(LOG_PREFIX + ".core.JythonExtensionProvider.scriptLoaded").debug("Registered service") def scriptUnloaded(): if core.JythonExtensionProvider is not None: scriptExtension.removeScriptExtensionProvider(core.JythonExtensionProvider) core.JythonExtensionProvider = None - + logging.getLogger(LOG_PREFIX + ".core.JythonExtensionProvider.scriptUnloaded").debug("Unregistered service") diff --git a/Core/automation/jsr223/core/components/200_JythonItemChannelLinkProvider.py b/Core/automation/jsr223/core/components/200_JythonItemChannelLinkProvider.py index 3dfab91e..bc926d44 100755 --- a/Core/automation/jsr223/core/components/200_JythonItemChannelLinkProvider.py +++ b/Core/automation/jsr223/core/components/200_JythonItemChannelLinkProvider.py @@ -1,45 +1,61 @@ -from org.eclipse.smarthome.core.thing.link import ItemChannelLinkProvider +scriptExtension.importPreset(None) + +provider_class = None +try: + from org.openhab.core.thing.link import ItemChannelLinkProvider + provider_class = "org.openhab.core.thing.link.ItemChannelLinkProvider" +except: + from org.eclipse.smarthome.core.thing.link import ItemChannelLinkProvider + provider_class = "org.eclipse.smarthome.core.thing.link.ItemChannelLinkProvider" import core -import core.osgi +from core.log import logging, LOG_PREFIX -class JythonItemChannelLinkProvider(ItemChannelLinkProvider): - def __init__(self): - self.listeners = [] - self.links = [] +try: + class JythonItemChannelLinkProvider(ItemChannelLinkProvider): + def __init__(self): + self.listeners = [] + self.links = [] - def add(self, link): - self.links.append(link) - for listener in self.listeners: - listener.added(self, link) - def remove(self, link): - if link in self.links: - self.links.remove(link) - for listener in self.listeners: - listener.removed(self, link) + def addProviderChangeListener(self, listener): + self.listeners.append(listener) + + def removeProviderChangeListener(self, listener): + if listener in self.listeners: + self.listeners.remove(listener) - def getAll(self): - return self.links + def add(self, link): + self.links.append(link) + for listener in self.listeners: + listener.added(self, link) - def update(self, link): - for listener in self.listeners: - listener.updated(self, link) + def remove(self, link): + if link in self.links: + self.links.remove(link) + for listener in self.listeners: + listener.removed(self, link) - def addProviderChangeListener(self, listener): - self.listeners.append(listener) + def update(self, link): + for listener in self.listeners: + listener.updated(self, link) - def removeProviderChangeListener(self, listener): - if listener in self.listeners: - self.listeners.remove(listener) + def getAll(self): + return self.links -core.JythonItemChannelLinkProvider = JythonItemChannelLinkProvider() + core.JythonItemChannelLinkProvider = JythonItemChannelLinkProvider() +except: + core.JythonItemChannelLinkProvider = None + import traceback + logging.getLogger(LOG_PREFIX + ".core.JythonItemChannelLinkProvider").warn(traceback.format_exc()) def scriptLoaded(id): - core.osgi.register_service( - core.JythonItemChannelLinkProvider, - ["org.eclipse.smarthome.core.thing.link.ItemChannelLinkProvider"]) - + if core.JythonItemChannelLinkProvider is not None: + core.osgi.register_service(core.JythonItemChannelLinkProvider, [provider_class]) + logging.getLogger(LOG_PREFIX + ".core.JythonItemChannelLinkProvider.scriptLoaded").debug("Registered service") + def scriptUnloaded(): - core.osgi.unregister_service(core.JythonItemChannelLinkProvider) - delattr(core, 'JythonItemChannelLinkProvider') + if core.JythonItemChannelLinkProvider is not None: + core.osgi.unregister_service(core.JythonItemChannelLinkProvider) + core.JythonItemChannelLinkProvider = None + logging.getLogger(LOG_PREFIX + ".core.JythonItemChannelLinkProvider.scriptUnloaded").debug("Unregistered service") diff --git a/Core/automation/jsr223/core/components/200_JythonItemProvider.py b/Core/automation/jsr223/core/components/200_JythonItemProvider.py index 3626c849..fa3deac6 100644 --- a/Core/automation/jsr223/core/components/200_JythonItemProvider.py +++ b/Core/automation/jsr223/core/components/200_JythonItemProvider.py @@ -1,45 +1,65 @@ -from org.eclipse.smarthome.core.items import ItemProvider +scriptExtension.importPreset(None) + +provider_class = None +try: + from org.openhab.core.items import ItemProvider + provider_class = "org.openhab.core.items.ItemProvider" +except: + from org.eclipse.smarthome.core.items import ItemProvider + provider_class = "org.eclipse.smarthome.core.items.ItemProvider" import core -import core.osgi +from core.log import logging, LOG_PREFIX + +try: + class JythonItemProvider(ItemProvider): + def __init__(self): + self.items_ = [] + self.listeners = [] + + def addProviderChangeListener(self, listener): + self.listeners.append(listener) -class JythonItemProvider(ItemProvider): - def __init__(self): - self.listeners = [] - self.items = [] + def removeProviderChangeListener(self, listener): + if listener in self.listeners: + self.listeners.remove(listener) - def add(self, item): - self.items.append(item) - for listener in self.listeners: - listener.added(self, item) + def add(self, item): + self.items_.append(item) + for listener in self.listeners: + listener.added(self, item) - def remove(self, item): - if isinstance(item, str): - for i in self.items: - if i.name == item: - self.remove(i) - else: - if item in self.items: - self.items.remove(item) - for listener in self.listeners: - listener.removed(self, item) + def remove(self, item): + if isinstance(item, str): + for i in self.items_: + if i.name == item: + self.remove(i) + elif item in self.items_: + self.items_.remove(item) - def getAll(self): - return self.items + for listener in self.listeners: + listener.removed(self, item) - def addProviderChangeListener(self, listener): - self.listeners.append(listener) + def update(self, item): + for listener in self.listeners: + listener.updated(self, item) - def removeProviderChangeListener(self, listener): - self.listeners.remove(listener) + def getAll(self): + return self.items_ -core.JythonItemProvider = JythonItemProvider() + core.JythonItemProvider = JythonItemProvider() +except: + core.JythonItemProvider = None + import traceback + logging.getLogger(LOG_PREFIX + ".core.JythonItemProvider").error(traceback.format_exc()) def scriptLoaded(id): - core.osgi.register_service( - core.JythonItemProvider, - ["org.eclipse.smarthome.core.items.ItemProvider"]) + if core.JythonItemProvider is not None: + core.osgi.register_service(core.JythonItemProvider, [provider_class]) + logging.getLogger(LOG_PREFIX + ".core.JythonItemProvider.scriptLoaded").debug("Registered service") def scriptUnloaded(): - core.osgi.unregister_service(core.JythonItemProvider) - delattr(core, 'JythonItemProvider') \ No newline at end of file + if core.JythonItemProvider is not None: + core.osgi.unregister_service(core.JythonItemProvider) + core.JythonItemProvider = None + logging.getLogger(LOG_PREFIX + ".core.JythonItemProvider.scriptUnloaded").debug("Unregistered service") diff --git a/Core/automation/jsr223/core/components/200_JythonThingProvider.py b/Core/automation/jsr223/core/components/200_JythonThingProvider.py index fef81e38..558db7b7 100644 --- a/Core/automation/jsr223/core/components/200_JythonThingProvider.py +++ b/Core/automation/jsr223/core/components/200_JythonThingProvider.py @@ -1,45 +1,60 @@ -from org.eclipse.smarthome.core.thing import ThingProvider +scriptExtension.importPreset(None) -import core -import core.osgi +provider_class = None +try: + from org.openhab.core.thing import ThingProvider + provider_class = "org.openhab.core.thing.ThingProvider" +except: + from org.eclipse.smarthome.core.thing import ThingProvider + provider_class = "org.eclipse.smarthome.core.thing.ThingProvider" -class JythonThingProvider(ThingProvider): - def __init__(self): - self.things = [] - self.listeners = [] - - def addProviderChangeListener(self, listener): # ProviderChangeListener - self.listeners.append(listener) - - def getAll(self): - return self.things +import core +from core.log import logging, LOG_PREFIX - def removeProviderChangeListener(self, listener): - if listener in self.listeners: - self.listeners.remove(listener) - - def add(self, thing): - self.things.append(thing) - for listener in self.listeners: - listener.added(self, thing) +try: + class JythonThingProvider(ThingProvider): + def __init__(self): + self.things = [] + self.listeners = [] - def remove(self, thing): - if thing in self.things: - self.things.remove(thing) + def addProviderChangeListener(self, listener): # ProviderChangeListener + self.listeners.append(listener) + + def removeProviderChangeListener(self, listener): + if listener in self.listeners: + self.listeners.remove(listener) + + def add(self, thing): + self.things.append(thing) for listener in self.listeners: - listener.removed(self, thing) - - def update(self, thing): - for listener in self.listeners: - listener.updated(self, thing) + listener.added(self, thing) + + def remove(self, thing): + if thing in self.things: + self.things.remove(thing) + for listener in self.listeners: + listener.removed(self, thing) + + def update(self, thing): + for listener in self.listeners: + listener.updated(self, thing) + + def getAll(self): + return self.things -core.JythonThingProvider = JythonThingProvider() + core.JythonThingProvider = JythonThingProvider() +except: + core.JythonThingProvider = None + import traceback + logging.getLogger(LOG_PREFIX + ".core.JythonThingProvider").error(traceback.format_exc()) def scriptLoaded(id): - core.osgi.register_service( - core.JythonThingProvider, - ["org.eclipse.smarthome.core.thing.ThingProvider"]) + if core.JythonThingProvider is not None: + core.osgi.register_service(core.JythonThingProvider, [provider_class]) + logging.getLogger(LOG_PREFIX + ".core.JythonThingProvider.scriptLoaded").debug("Registered service") def scriptUnloaded(): - core.osgi.unregister_service(core.JythonThingProvider) - delattr(core, 'JythonThingProvider') + if core.JythonThingProvider is not None: + core.osgi.unregister_service(core.JythonThingProvider) + core.JythonThingProvider = None + logging.getLogger(LOG_PREFIX + ".core.JythonThingProvider.scriptUnloaded").debug("Unregistered service") diff --git a/Core/automation/jsr223/core/components/200_JythonThingTypeProvider.py b/Core/automation/jsr223/core/components/200_JythonThingTypeProvider.py index 80619818..929519a9 100644 --- a/Core/automation/jsr223/core/components/200_JythonThingTypeProvider.py +++ b/Core/automation/jsr223/core/components/200_JythonThingTypeProvider.py @@ -1,33 +1,48 @@ -from org.eclipse.smarthome.core.thing.binding import ThingTypeProvider +scriptExtension.importPreset(None) + +provider_class = None +try: + from org.openhab.core.thing.binding import ThingTypeProvider + provider_class = "org.openhab.core.thing.binding.ThingTypeProvider" +except: + from org.eclipse.smarthome.core.thing.binding import ThingTypeProvider + provider_class = "org.eclipse.smarthome.core.thing.binding.ThingTypeProvider" import core -class JythonThingTypeProvider(ThingTypeProvider): - def __init__(self): - self.thing_types = [] +try: + class JythonThingTypeProvider(ThingTypeProvider): + def __init__(self): + self.thing_types = [] + + def getThingTypes(self, locale): + return self.thing_types - def getThingTypes(self, locale): - return self.thing_types - - def getThingType(self, thingTypeUID, locale): - for type in self.thing_types: - if type.getUID() == thingTypeUID: - return type + def getThingType(self, thingTypeUID, locale): + for type in self.thing_types: + if type.getUID() == thingTypeUID: + return type - def add(self, thing_type): - self.thing_types.append(thing_type) - - def remove(self, thing_type): - if thing_type in self.thing_types: - self.thing_types.remove(thing_type) + def add(self, thing_type): + self.thing_types.append(thing_type) -core.JythonThingTypeProvider = JythonThingTypeProvider() + def remove(self, thing_type): + if thing_type in self.thing_types: + self.thing_types.remove(thing_type) + + core.JythonThingTypeProvider = JythonThingTypeProvider() +except: + core.JythonThingTypeProvider = None + import traceback + logging.getLogger(LOG_PREFIX + ".core.JythonThingTypeProvider").error(traceback.format_exc()) def scriptLoaded(id): - core.osgi.register_service( - core.JythonThingTypeProvider, - ["org.eclipse.smarthome.core.thing.binding.ThingTypeProvider"]) - + if core.JythonThingProvider is not None: + core.osgi.register_service(core.JythonThingTypeProvider, [provider_class]) + logging.getLogger(LOG_PREFIX + ".core.JythonThingTypeProvider.scriptLoaded").debug("Registered service") + def scriptUnloaded(): - core.osgi.unregister_service(core.JythonThingTypeProvider) - delattr(core, 'JythonThingTypeProvider') + if core.JythonThingProvider is not None: + core.osgi.unregister_service(core.JythonThingTypeProvider) + core.JythonThingTypeProvider = None + logging.getLogger(LOG_PREFIX + ".core.JythonThingTypeProvider.scriptUnloaded").debug("Unregistered service") diff --git a/Core/automation/jsr223/core/components/200_JythonTransform.py b/Core/automation/jsr223/core/components/200_JythonTransform.py index 6b45f095..b0c53a5a 100644 --- a/Core/automation/jsr223/core/components/200_JythonTransform.py +++ b/Core/automation/jsr223/core/components/200_JythonTransform.py @@ -1,19 +1,36 @@ -from org.eclipse.smarthome.core.transform import TransformationService +scriptExtension.importPreset(None) -from core.osgi import register_service, unregister_service +transformation_class = None +try: + from org.openhab.core.transform import TransformationService + transformation_class = "org.openhab.core.transform.TransformationService" +except: + from org.eclipse.smarthome.core.transform import TransformationService + transformation_class = "org.eclipse.smarthome.core.transform.TransformationService" -class JythonTransformationService(TransformationService): +import core +from core.log import logging, LOG_PREFIX + +try: + class JythonTransformationService(TransformationService): def transform(self, pathname, value): with open(pathname, "r") as fp: code = fp.read() return eval(code, globals(), {'value': value}) - + + core.JythonTransformationService = JythonTransformationService() +except: + core.JythonTransformationService = None + import traceback + logging.getLogger(LOG_PREFIX + ".core.JythonTransformationService").error(traceback.format_exc()) + def scriptLoaded(id): - global service - service = JythonTransformationService() - interfaces = ["org.eclipse.smarthome.core.transform.TransformationService"] - registration = register_service(service, interfaces, {'smarthome.transform': 'JYTHON'}) + if core.JythonTransformationService is not None: + core.osgi.register_service(core.JythonTransformationService, [transformation_class], {'smarthome.transform': 'JYTHON'}) + logging.getLogger(LOG_PREFIX + ".core.JythonTransformationService.scriptLoaded").debug("Registered service") def scriptUnloaded(): - global service - unregister_service(service) \ No newline at end of file + if core.JythonTransformationService is not None: + core.osgi.unregister_service(core.JythonTransformationService) + core.JythonTransformationService = None + logging.getLogger(LOG_PREFIX + ".core.JythonTransformationService.scriptUnloaded").debug("Unregistered service") diff --git a/Core/automation/lib/python/configuration.py.example b/Core/automation/lib/python/configuration.py.example index a15c897d..7d8fa178 100644 --- a/Core/automation/lib/python/configuration.py.example +++ b/Core/automation/lib/python/configuration.py.example @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- LOG_PREFIX = "jsr223.jython" -adminEmail = "admin_email@some_domain.com" +admin_email = "admin_email@some_domain.com" openhabHost = "localhost" openhabPort = "8080"# "8443" diff --git a/Core/automation/lib/python/core/__init__.py b/Core/automation/lib/python/core/__init__.py index 4a129bbb..ea1f7393 100644 --- a/Core/automation/lib/python/core/__init__.py +++ b/Core/automation/lib/python/core/__init__.py @@ -7,4 +7,5 @@ def _item_getattr(self, name): return self[name] -type(items).__getattr__ = _item_getattr.__get__(items, type(items)) +if items:# this check prevents errors if no Items have been created yet + type(items).__getattr__ = _item_getattr.__get__(items, type(items)) diff --git a/Core/automation/lib/python/core/date.py b/Core/automation/lib/python/core/date.py index 1798ee62..cf917402 100644 --- a/Core/automation/lib/python/core/date.py +++ b/Core/automation/lib/python/core/date.py @@ -28,10 +28,9 @@ import datetime import sys -if 'org.eclipse.smarthome.automation' in sys.modules: - # Workaround for Jython JSR223 bug where - # dates and datetimes are converted to java.sql.Date - # and java.sql.Timestamp +if 'org.eclipse.smarthome.automation' in sys.modules or 'org.openhab.core.automation' in sys.modules: + # Workaround for Jython JSR223 bug where dates and datetimes are converted + # to java.sql.Date and java.sql.Timestamp def remove_java_converter(clazz): if hasattr(clazz, '__tojava__'): del clazz.__tojava__ @@ -184,7 +183,6 @@ def tzname(self, value): def dst(self, value): return datetime.timedelta(0) - # aliases toJTime = to_java_zoneddatetime toJCal = to_java_calendar diff --git a/Core/automation/lib/python/core/items.py b/Core/automation/lib/python/core/items.py index ebc39751..a112b57b 100644 --- a/Core/automation/lib/python/core/items.py +++ b/Core/automation/lib/python/core/items.py @@ -1,30 +1,42 @@ # NOTE: Requires JythonItemProvider component -from core import osgi, jsr223, JythonItemProvider from core.jsr223 import scope +scope.scriptExtension.importPreset(None) + +import core +from core import osgi, JythonItemProvider from core.log import logging, LOG_PREFIX from core.links import remove_all_links +ItemBuilderFactory = osgi.get_service( + "org.openhab.core.items.ItemBuilderFactory" + ) or osgi.get_service( + "org.eclipse.smarthome.core.items.ItemBuilderFactory" + ) + log = logging.getLogger(LOG_PREFIX + ".core.items") __all__ = ["add_item", "remove_item"] -def add_item(item, item_type=None, category=None, groups=None, label=None, tags=[], gi_base_type=None, group_function=None): +def add_item(item_or_item_name, item_type=None, category=None, groups=None, label=None, tags=[], gi_base_type=None, group_function=None): try: - if isinstance(item, basestring): + if not isinstance(item_or_item_name, basestring) and not hasattr(item_or_item_name, 'name'): + raise Exception("\"{}\" is not a string or Item".format(item_or_item_name)) + item = item_or_item_name + if isinstance(item_or_item_name, basestring): + item_name = item_or_item_name if item_type is None: - raise Exception("Must provide item_type when creating an item by name") + raise Exception("Must provide item_type when creating an Item by name") - itemBuilderFactory = osgi.get_service("org.eclipse.smarthome.core.items.ItemBuilderFactory") - baseItem = None if item_type != "Group" or gi_base_type is None else itemBuilderFactory.newItemBuilder(gi_base_type, item + "_baseItem").build() + base_item = None if item_type != "Group" or gi_base_type is None else ItemBuilderFactory.newItemBuilder(gi_base_type, item_name + "_baseItem").build() group_function = None if item_type != "Group" else group_function - item = itemBuilderFactory.newItemBuilder(item_type, item) \ - .withCategory(category) \ - .withGroups(groups) \ - .withLabel(label) \ - .withBaseItem(baseItem) \ - .withGroupFunction(group_function) \ - .withTags(set(tags)) \ - .build() + item = ItemBuilderFactory.newItemBuilder(item_type, item_name)\ + .withCategory(category)\ + .withGroups(groups)\ + .withLabel(label)\ + .withBaseItem(base_item)\ + .withGroupFunction(group_function)\ + .withTags(set(tags))\ + .build() JythonItemProvider.add(item) log.debug("Item added: [{}]".format(item)) @@ -35,18 +47,19 @@ def add_item(item, item_type=None, category=None, groups=None, label=None, tags= else: return item -def remove_item(item): +def remove_item(item_or_item_name): try: - from org.eclipse.smarthome.core.items import GenericItem + item = item_or_item_name if isinstance(item, basestring): if scope.itemRegistry.getItems(item) == []: raise Exception("\"{}\" is not in the ItemRegistry".format(item)) else: - item = scope.ir.getItem(item) - elif not isinstance(item, GenericItem): - raise Exception("\"{}\" is not a string or Item".format(item)) - elif scope.itemRegistry.getItems(item.name) == []: - raise Exception("\"{}\" is not in the ItemRegistry".format(item)) + item = scope.ir.getItem(item_or_item_name) + elif not hasattr(item_or_item_name, 'name'): + raise Exception("\"{}\" is not a string or Item".format(item_or_item_name)) + + if scope.itemRegistry.getItems(item.name) == []: + raise Exception("\"{}\" is not in the ItemRegistry".format(item.name)) remove_all_links(item) JythonItemProvider.remove(item) log.debug("Item removed: [{}]".format(item)) diff --git a/Core/automation/lib/python/core/links.py b/Core/automation/lib/python/core/links.py index ef1cce9d..d72f200a 100755 --- a/Core/automation/lib/python/core/links.py +++ b/Core/automation/lib/python/core/links.py @@ -1,24 +1,37 @@ # NOTE: Requires JythonItemChannelLinkProvider component -from core import osgi, jsr223, JythonItemChannelLinkProvider from core.jsr223 import scope +scope.scriptExtension.importPreset(None) + +import core +from core import osgi, JythonItemChannelLinkProvider from core.log import logging, LOG_PREFIX +try: + from org.openhab.core.thing import ChannelUID + from org.openhab.core.thing.link import ItemChannelLink +except: + from org.eclipse.smarthome.core.thing import ChannelUID + from org.eclipse.smarthome.core.thing.link import ItemChannelLink + +ItemChannelLinkRegistry = osgi.get_service( + "org.openhab.core.thing.link.ItemChannelLinkRegistry" + ) or osgi.get_service( + "org.eclipse.smarthome.core.thing.link.ItemChannelLinkRegistry" + ) + log = logging.getLogger(LOG_PREFIX + ".core.links") __all__ = ["add_link", "remove_link"] -def validate_item(item): - from org.eclipse.smarthome.core.items import GenericItem - if isinstance(item, GenericItem): - item = item.name - elif not isinstance(item, basestring): - raise Exception("\"{}\" is not a string or Item".format(item)) - if scope.itemRegistry.getItems(item) == []: - raise Exception("\"{}\" is not in the ItemRegistry".format(item)) - return item +def validate_item(item_or_item_name):# returns string + if not isinstance(item_or_item_name, basestring) and not hasattr(item_or_item_name, 'name'): + raise Exception("\"{}\" is not a string or Item".format(item_or_item_name)) + item_name = item_or_item_name if isinstance(item_or_item_name, basestring) else item_or_item_name.name + if scope.itemRegistry.getItems(item_name) == []: + raise Exception("\"{}\" is not in the ItemRegistry".format(item_name)) + return item_name -def validate_channel_uid(channel_uid): - from org.eclipse.smarthome.core.thing import ChannelUID +def validate_channel_uid(channel_uid):# returns ChannelUID if isinstance(channel_uid, basestring): channel_uid = ChannelUID(channel_uid) elif not isinstance(channel_uid, ChannelUID): @@ -27,12 +40,9 @@ def validate_channel_uid(channel_uid): raise Exception("\"{}\" is not a valid Channel".format(channel_uid)) return channel_uid -def add_link(item, channel_uid): +def add_link(item_or_item_name, channel_uid):# returns Link try: - item = validate_item(item) - channel_uid = validate_channel_uid(channel_uid) - from org.eclipse.smarthome.core.thing.link import ItemChannelLink - link = ItemChannelLink(item, channel_uid) + link = ItemChannelLink(validate_item(item_or_item_name), validate_channel_uid(channel_uid)) JythonItemChannelLinkProvider.add(link) log.debug("Link added: [{}]".format(link)) except: @@ -42,28 +52,23 @@ def add_link(item, channel_uid): else: return link -def remove_link(item, channel_uid): +def remove_link(item_or_item_name, channel_uid): try: - item = validate_item(item) - channel_uid = validate_channel_uid(channel_uid) - from org.eclipse.smarthome.core.thing.link import ItemChannelLink - link = ItemChannelLink(item, channel_uid) + link = ItemChannelLink(validate_item(item_or_item_name), validate_channel_uid(channel_uid)) JythonItemChannelLinkProvider.remove(link) log.debug("Link removed: [{}]".format(link)) except: import traceback log.error(traceback.format_exc()) -def remove_all_links(item): +def remove_all_links(item_or_item_name): try: - item = validate_item(item) - ItemChannelLinkRegistry = osgi.get_service("org.eclipse.smarthome.core.thing.link.ItemChannelLinkRegistry") - channels = ItemChannelLinkRegistry.getBoundChannels(item) - from org.eclipse.smarthome.core.thing.link import ItemChannelLink - links = map(lambda channel: ItemChannelLink(item, channel), channels) + item_name = validate_item(item_or_item_name) + channels = ItemChannelLinkRegistry.getBoundChannels(item_name) + links = map(lambda channel: ItemChannelLink(item_name, channel), channels) for link in links: JythonItemChannelLinkProvider.remove(link) log.debug("Link removed: [{}]".format(link)) except: import traceback - log.error(traceback.format_exc()) \ No newline at end of file + log.error(traceback.format_exc()) diff --git a/Core/automation/lib/python/core/log.py b/Core/automation/lib/python/core/log.py index e6be3e0c..f8d63443 100644 --- a/Core/automation/lib/python/core/log.py +++ b/Core/automation/lib/python/core/log.py @@ -54,8 +54,8 @@ def wrapper(*args, **kwargs): import core.actions if hasattr(core.actions, 'NotificationAction'): import configuration - if hasattr(configuration, 'adminEmail') and configuration.adminEmail != "admin_email@some_domain.com": - core.actions.NotificationAction.sendNotification(configuration.adminEmail, "Exception: {}: [{}]".format(rule_name, traceback.format_exc())) + if hasattr(configuration, 'admin_email') and configuration.admin_email != "admin_email@some_domain.com": + core.actions.NotificationAction.sendNotification(configuration.admin_email, "Exception: {}: [{}]".format(rule_name, traceback.format_exc())) else: core.actions.NotificationAction.sendBroadcastNotification("Exception: {}: [{}]".format(rule_name, traceback.format_exc())) return wrapper \ No newline at end of file diff --git a/Core/automation/lib/python/core/osgi/events.py b/Core/automation/lib/python/core/osgi/events.py index 11da32d6..fd7c5167 100644 --- a/Core/automation/lib/python/core/osgi/events.py +++ b/Core/automation/lib/python/core/osgi/events.py @@ -1,3 +1,6 @@ +from core.jsr223 import scope +scope.scriptExtension.importPreset(None) + import uuid import java.util import traceback @@ -6,10 +9,7 @@ from org.osgi.service.event import EventHandler, EventConstants, EventAdmin from org.osgi.service.cm import ManagedService -from org.eclipse.smarthome.automation.handler import TriggerHandler - import core -from core.jsr223 import scope from core.osgi import bundle_context from core.log import logging, LOG_PREFIX @@ -28,8 +28,6 @@ def hashtable(*key_values): return ht class OsgiEventAdmin(object): - log = logging.getLogger(LOG_PREFIX + ".core.osgi.events.OsgiEventAdmin") - _event_handler = None _event_listeners = [] @@ -73,7 +71,7 @@ def remove_listener(cls, listener): cls._event_handler = None -# The ESH / JSR223 design does not allow trigger handlers to access +# The OH / JSR223 design does not allow trigger handlers to access # the original trigger instance. The trigger information is copied into a # RuntimeTrigger and then provided to the trigger handler. Therefore, there # is no way AFAIK to access the original trigger from the trigger handler. @@ -111,4 +109,4 @@ def log_event(event): log.info(" '{}': {} ({})".format(name, value, type(value))) def event_dict(event): - return { key: event.getProperty(key) for key in event.getPropertyNames() } \ No newline at end of file + return { key: event.getProperty(key) for key in event.getPropertyNames() } diff --git a/Core/automation/lib/python/core/rules.py b/Core/automation/lib/python/core/rules.py index 44e8beb0..45580cf2 100644 --- a/Core/automation/lib/python/core/rules.py +++ b/Core/automation/lib/python/core/rules.py @@ -1,10 +1,14 @@ from inspect import isclass from java.util import UUID -from org.eclipse.smarthome.automation import Rule as SmarthomeRule -from core.log import logging, LOG_PREFIX, log_traceback +try: + from org.openhab.core.automation import Rule as SmarthomeRule +except: + from org.eclipse.smarthome.automation import Rule as SmarthomeRule +from core.log import logging, LOG_PREFIX, log_traceback from core.jsr223 import scope, get_automation_manager + scope.scriptExtension.importPreset("RuleSimple") # this needs some attention in order to work with Automation API changes in 2.4.0 snapshots since build 1319 @@ -18,7 +22,6 @@ def set_uid_prefix(rule, prefix=None): class _FunctionRule(scope.SimpleRule): def __init__(self, callback, triggers, name=None, description=None, tags=None): self.triggers = triggers - self.callback = log_traceback(callback) if name is None: if hasattr(callback, '__name__'): name = callback.__name__ @@ -26,6 +29,7 @@ def __init__(self, callback, triggers, name=None, description=None, tags=None): name = "JSR223-Jython" self.name = name callback.log = logging.getLogger(LOG_PREFIX + "." + name) + self.callback = log_traceback(callback) if description is not None: self.description = description if tags is not None: @@ -36,7 +40,7 @@ def execute(self, module, inputs): self.callback(inputs.get('event')) except: import traceback - self.log.error(traceback.format_exc()) + self.callback.log.error(traceback.format_exc()) def rule(name=None, description=None, tags=None): def rule_decorator(object): @@ -68,10 +72,11 @@ def init(self, *args, **kwargs): else: function = object newRule = _FunctionRule(function, function.triggers, name=name, description=description, tags=tags) - get_automation_manager().addRule(newRule) + addRule(newRule) function.triggers = None return function return rule_decorator def addRule(rule): - get_automation_manager().addRule(rule) \ No newline at end of file + get_automation_manager().addRule(rule) + logging.getLogger(LOG_PREFIX + ".core.rules").debug("Added rule [{}]".format(rule.name)) diff --git a/Core/automation/lib/python/core/triggers.py b/Core/automation/lib/python/core/triggers.py index 37d230e3..4ad6d431 100755 --- a/Core/automation/lib/python/core/triggers.py +++ b/Core/automation/lib/python/core/triggers.py @@ -1,3 +1,6 @@ +from core.jsr223 import scope +scope.scriptExtension.importPreset(None) + import inspect import json import uuid @@ -5,15 +8,31 @@ import java.util from java.nio.file.StandardWatchEventKinds import ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY -from org.eclipse.smarthome.automation.core.util import TriggerBuilder -from org.eclipse.smarthome.automation import Trigger -from org.eclipse.smarthome.config.core import Configuration -from org.eclipse.smarthome.core.thing import ChannelUID, ThingUID, ThingStatus -from org.eclipse.smarthome.core.thing.type import ChannelKind -from org.eclipse.smarthome.core.types import TypeParser +try: + from org.openhab.core.automation.util import TriggerBuilder + from org.openhab.core.automation import Trigger +except: + from org.eclipse.smarthome.automation.core.util import TriggerBuilder + from org.eclipse.smarthome.automation import Trigger + +try: + from org.openhab.config.core import Configuration +except: + from org.eclipse.smarthome.config.core import Configuration + +try: + from org.openhab.core.thing import ChannelUID, ThingUID, ThingStatus + from org.openab.core.thing.type import ChannelKind +except: + from org.eclipse.smarthome.core.thing import ChannelUID, ThingUID, ThingStatus + from org.eclipse.smarthome.core.thing.type import ChannelKind + +try: + from org.eclipse.smarthome.core.types import TypeParser +except: + from org.openhab.core.types import TypeParser import core -from core.jsr223 import scope from core.osgi.events import OsgiEventTrigger from core.log import logging, LOG_PREFIX @@ -110,12 +129,7 @@ def __init__(self, cronExpression, triggerName=None): class StartupTrigger(Trigger): def __init__(self, triggerName=None): triggerName = triggerName or uuid.uuid1().hex - self.trigger = TriggerBuilder.create().withId(triggerName).withTypeUID(core.STARTUP_MODULE_ID).withConfiguration(Configuration()).build() - -class ShutdownTrigger(Trigger): - def __init__(self, triggerName=None): - triggerName = triggerName or uuid.uuid1().hex - self.trigger = TriggerBuilder.create().withId(triggerName).withTypeUID(core.SHUTDOWN_MODULE_ID).withConfiguration(Configuration()).build() + self.trigger = TriggerBuilder.create().withId(triggerName).withTypeUID("jsr223.StartupTrigger").withConfiguration(Configuration()).build() # Item Registry Triggers @@ -170,7 +184,7 @@ def item_trigger(function): else: group_members = [ item ] for member in group_members: - trigger_name = "Item-{}-{}{}{}".format(member.name, trigger_type.replace(" ","-"), "-from-{}".format(old_state) if old_state else "", "-to-{}".format(new_state) if new_state else "") + trigger_name = "Item-{}-{}{}{}{}".format(member.name, trigger_type.replace(" ","-"), "-from-{}".format(old_state) if old_state is not None else "", "-to-" if new_state is not None and trigger_type == "changed" else "", new_state if new_state is not None else "") if trigger_type == "received update": function.triggers.append(ItemStateUpdateTrigger(member.name, state=new_state, triggerName=trigger_name).trigger) elif trigger_type == "received command": @@ -208,7 +222,7 @@ def channel_trigger(function): def thing_trigger(function): if not hasattr(function, 'triggers'): function.triggers = [] - event_types = "ThingStatusInfoChangedEvent" if (trigger_type == "changed") else "ThingStatusInfoEvent" + event_types = "ThingStatusInfoChangedEvent" if trigger_type == "changed" else "ThingStatusInfoEvent" function.triggers.append(ThingEventTrigger(trigger_target, event_types, triggerName=trigger_name).trigger) log.debug("when: Created thing_trigger: [{}]".format(trigger_name)) return function @@ -285,7 +299,7 @@ def thing_trigger(function): elif len(inputList) > 0:# there are no more possible combinations, but there is more data raise ValueError("when: \"{}\" could not be parsed. \"{}\" is invalid for \"{} {} {}\"".format(target, inputList, target_type, trigger_target, trigger_type)) - else:# a simple Item target was used, so add default target_type and trigger_type (Item XXXXX changed) + else:# a simple Item target was used, so add a default target_type and trigger_type (Item XXXXX changed) if target_type is None: target_type = "Item" if trigger_target is None: @@ -302,11 +316,11 @@ def thing_trigger(function): raise ValueError("when: \"{}\" could not be parsed because Item \"{}\" is not in the ItemRegistry".format(target, trigger_target)) elif target_type in ["Member of", "Descendent of"] and scope.itemRegistry.getItem(trigger_target).type != "Group": raise ValueError("when: \"{}\" could not be parsed because \"{}\" was specified, but \"{}\" is not a group".format(target, target_type, trigger_target)) - elif target_type == "Item" and old_state is not None and trigger_type == "changed" and not TypeParser.parseState(scope.itemRegistry.getItem(trigger_target).acceptedDataTypes, old_state): + elif target_type == "Item" and old_state is not None and trigger_type == "changed" and TypeParser.parseState(scope.itemRegistry.getItem(trigger_target).acceptedDataTypes, old_state) is None: raise ValueError("when: \"{}\" could not be parsed because \"{}\" is not a valid state for \"{}\"".format(target, old_state, trigger_target)) - elif target_type == "Item" and new_state is not None and (trigger_type == "changed" or trigger_type == "received update") and not TypeParser.parseState(scope.itemRegistry.getItem(trigger_target).acceptedDataTypes, new_state): + elif target_type == "Item" and new_state is not None and (trigger_type == "changed" or trigger_type == "received update") and TypeParser.parseState(scope.itemRegistry.getItem(trigger_target).acceptedDataTypes, new_state) is None: raise ValueError("when: \"{}\" could not be parsed because \"{}\" is not a valid state for \"{}\"".format(target, new_state, trigger_target)) - elif target_type == "Item" and new_state is not None and trigger_type == "received command" and not TypeParser.parseState(scope.itemRegistry.getItem(trigger_target).acceptedCommandTypes, new_state): + elif target_type == "Item" and new_state is not None and trigger_type == "received command" and TypeParser.parseCommand(scope.itemRegistry.getItem(trigger_target).acceptedCommandTypes, new_state) is None: raise ValueError("when: \"{}\" could not be parsed because \"{}\" is not a valid command for \"{}\"".format(target, new_state, trigger_target)) elif target_type == "Channel" and scope.things.getChannel(ChannelUID(trigger_target)) is None:# returns null if Channel does not exist raise ValueError("when: \"{}\" could not be parsed because Channel \"{}\" does not exist".format(target, trigger_target)) @@ -320,10 +334,8 @@ def thing_trigger(function): raise ValueError("when: \"{}\" is not a valid Thing status".format(new_state)) elif target_type == "Thing" and (old_state is not None or new_state is not None):# there is only an event trigger for Things, so old_state and new_state can't be used yet *****TO BE REMOVED***** raise ValueError("when: \"{}\" could not be parsed because rule triggers do not currently support checking the from/to status for Things".format(target)) - elif target_type == "System" and trigger_target != "started" and trigger_target != "shuts down": - raise ValueError("when: \"{}\" could not be parsed. trigger_target \"{}\" is invalid for target_type \"System\". Valid trigger_type values are \"started\" and \"shuts down\"".format(target, target_type)) - elif target_type == "System":# 'System shuts down' is not currently supported, and the 'System started' trigger needs to be reworked for the update API *****TO BE REMOVED***** - raise ValueError("when: \"{}\" could not be parsed because rule triggers do not currently support target_type \"System\"".format(target)) + elif target_type == "System" and trigger_target != "started":# and trigger_target != "shuts down": + raise ValueError("when: \"{}\" could not be parsed. trigger_target \"{}\" is invalid for target_type \"System\". The only valid trigger_type value is \"started\"".format(target, target_type))# and \"shuts down\"".format(target, target_type)) log.debug("when: target=[{}], target_type={}, trigger_target={}, trigger_type={}, old_state={}, new_state={}".format(target, target_type, trigger_target, trigger_type, old_state, new_state)) @@ -340,4 +352,4 @@ def thing_trigger(function): except Exception as e: import traceback - log.error("when: Exception [{}]: [{}]".format(e, traceback.format_exc())) \ No newline at end of file + log.error("when: Exception [{}]: [{}]".format(e, traceback.format_exc())) diff --git a/Core/automation/lib/python/core/utils.py b/Core/automation/lib/python/core/utils.py index be9a552c..47c95b60 100644 --- a/Core/automation/lib/python/core/utils.py +++ b/Core/automation/lib/python/core/utils.py @@ -1,9 +1,11 @@ import random import time -from org.eclipse.smarthome.core.types import TypeParser +try: + from org.eclipse.smarthome.core.types import TypeParser +except: + from org.openhab.core.types import TypeParser -import configuration from core.log import logging, LOG_PREFIX from core.jsr223 import scope from core.actions import PersistenceExtensions diff --git a/Docs/Defining-Rules.md b/Docs/Defining-Rules.md index 74fdea31..1f5d6f28 100644 --- a/Docs/Defining-Rules.md +++ b/Docs/Defining-Rules.md @@ -92,36 +92,37 @@ class exampleExtensionRule(SimpleRule): automationManager.addRule(exampleExtensionRule()) ``` -This removes the need to know the internal ESH trigger type strings, -define trigger names, and to know configuration dictionary requirements. +This removes the need to know the internal ESH trigger type strings, define trigger names, and to know the requirements for the configuration dictionary. #### Rule and Trigger Decorators diff --git a/Script Examples/Alexa/speak_and_respond.py b/Script Examples/Alexa/speak_and_respond.py index 8f43a537..1c6b3bd8 100644 --- a/Script Examples/Alexa/speak_and_respond.py +++ b/Script Examples/Alexa/speak_and_respond.py @@ -21,7 +21,7 @@ from core.rules import rule def getLockStates(): - return "all doors are locked" if items["gSecurity"] == OnOffType.OFF else "the following doors are not locked, \n{}".format("\n".join(map(lambda unlockedLock: unlockedLock.label, filter(lambda lock: lock.state == OnOffType.OFF, list(ir.getItem("gSecurity").getAllMembers()))))) + return "all doors are locked" if items["gSecurity"] == ON else "the following doors are not locked, \n{}".format("\n".join(map(lambda unlockedLock: unlockedLock.label, filter(lambda lock: lock.state == OFF, ir.getItem("gSecurity").getAllMembers())))) @rule("Alert: Voice command alert") @when("Member of gAlexa_LastVoiceCommand received update") diff --git a/Script Examples/components/300_EchoThing.py b/Script Examples/components/300_EchoThing.py index 5eb853f0..c5ba7db5 100644 --- a/Script Examples/components/300_EchoThing.py +++ b/Script Examples/components/300_EchoThing.py @@ -7,10 +7,21 @@ Note: there are load ordering issues that will need to be resolved. """ -from org.eclipse.smarthome.core.thing import ThingTypeUID, ChannelUID -from org.eclipse.smarthome.core.thing.type import ThingType, ChannelTypeUID, ChannelType, ChannelDefinition -from org.eclipse.smarthome.core.thing.binding import ThingFactory, ThingHandlerFactory, BaseThingHandlerFactory, BaseThingHandler, ThingTypeProvider -from org.eclipse.smarthome.core.binding import BindingInfo, BindingInfoProvider +scriptExtension.importPreset(None) + +try: + from org.openhab.core.thing import ThingTypeUID, ChannelUID + from org.openhab.core.thing.type import ThingType, ChannelTypeUID, ChannelType, ChannelDefinition + from org.openhab.core.thing.binding import ThingFactory, ThingHandlerFactory, BaseThingHandlerFactory, BaseThingHandler, ThingTypeProvider +except: + from org.eclipse.smarthome.core.thing import ThingTypeUID, ChannelUID + from org.eclipse.smarthome.core.thing.type import ThingType, ChannelTypeUID, ChannelType, ChannelDefinition + from org.eclipse.smarthome.core.thing.binding import ThingFactory, ThingHandlerFactory, BaseThingHandlerFactory, BaseThingHandler, ThingTypeProvider + +try: + from org.openhab.core.binding import BindingInfo, BindingInfoProvider +except: + from org.eclipse.smarthome.core.binding import BindingInfo, BindingInfoProvider import core from core.osgi import register_service, unregister_service, get_service @@ -22,8 +33,16 @@ THING_NAME = "echo" THING_TYPE_UID = ThingTypeUID(BINDING_ID, THING_NAME) -config_description_registry = get_service("org.eclipse.smarthome.config.core.ConfigDescriptionRegistry") -thing_type_registry = get_service("org.eclipse.smarthome.core.thing.type.ThingTypeRegistry") +config_description_registry = get_service( + "org.openhab.core.config.core.ConfigDescriptionRegistry" + ) or get_service( + "org.eclipse.smarthome.config.core.ConfigDescriptionRegistry" + ) +thing_type_registry = get_service( + "org.openhab.core.thing.type.ThingTypeRegistry" + ) or get_service( + "org.eclipse.smarthome.core.thing.type.ThingTypeRegistry" + ) log = core.log.logging.getLogger("{}.{}".format(BINDING_ID, THING_NAME)) diff --git a/Script Examples/components/300_LogAction.py b/Script Examples/components/300_LogAction.py index 7fa17905..b0a7d1b9 100644 --- a/Script Examples/components/300_LogAction.py +++ b/Script Examples/components/300_LogAction.py @@ -1,6 +1,6 @@ from org.slf4j import Logger, LoggerFactory -ScriptExtension.importPreset("RuleSupport") +scriptExtension.importPreset("RuleSupport") class LoggerAction(ActionHandler): def __init__(self, module): @@ -29,4 +29,4 @@ def param(name, type, label, default=None, required=False): ], "write a log record", "Write a record to the log file.", - set(), Visibility.VISIBLE, [], [])) \ No newline at end of file + set(), Visibility.VISIBLE, [], [])) diff --git a/Script Examples/dirwatcher_example.py b/Script Examples/dirwatcher_example.py index 7596fa58..c48915b0 100644 --- a/Script Examples/dirwatcher_example.py +++ b/Script Examples/dirwatcher_example.py @@ -1,5 +1,4 @@ - -# Requires 000_DirectoryTrigger.py component +# Requires 100_DirectoryTrigger.py component from core.triggers import DirectoryEventTrigger, ENTRY_CREATE from core.rules import rule @@ -11,4 +10,4 @@ def getEventTriggers(self): return [ DirectoryEventTrigger("/tmp", event_kinds=[ENTRY_CREATE]) ] def execute(self, module, inputs): - logging.getLogger(LOG_PREFIX + ".directory_watcher_example").info("Detected new file: [{}]".format(inputs['path'])) \ No newline at end of file + logging.getLogger(LOG_PREFIX + ".directory_watcher_example").info("Detected new file: [{}]".format(inputs['path'])) diff --git a/Script Examples/components/300_ExampleExtensionProvider.py b/Script Examples/example_extension_provider_usage.py similarity index 100% rename from Script Examples/components/300_ExampleExtensionProvider.py rename to Script Examples/example_extension_provider_usage.py